ampfs.c (6021B)
1 #include <u.h> 2 #include <libc.h> 3 #include <fcall.h> 4 #include <thread.h> 5 #include <9p.h> 6 #include <plumb.h> 7 8 #include "pages.h" 9 10 enum { 11 FrameSize = sizeof(s16int) * 2, 12 }; 13 14 PBuf pg; 15 16 struct { 17 vlong min; 18 vlong max; 19 char str[12*3+1]; // see update_selstr 20 } sel; 21 22 void plumbsel(void); 23 24 void fs_open(Req *r); 25 void fs_read(Req *r); 26 void fs_write(Req *r); 27 28 void fcut_open(Req *r); 29 void fcut_write(Req *r); 30 31 void normalize_sel(void); 32 void update_selstr(void); 33 34 void threadplumb(void *); 35 36 Srv ampsrv = { 37 .read = fs_read, 38 .write = fs_write, 39 .open = fs_open, 40 }; 41 42 File *fdata, *fcut, *fctl; 43 char *service, *mountpath = "/mnt/amp"; 44 45 struct { 46 int send, recv; 47 char *port; 48 } plumb = {.port = "amp"}; 49 50 void 51 usage(void) 52 { 53 fprint(2,"usage: %s\n", argv0); 54 threadexitsall("usage"); 55 } 56 57 void 58 threadmain(int argc, char **argv) 59 { 60 ARGBEGIN { 61 case 'D': 62 chatty9p++; 63 break; 64 case 's': 65 service = EARGF(usage()); 66 break; 67 case 'm': 68 mountpath = EARGF(usage()); 69 break; 70 default: usage(); 71 } ARGEND 72 if (argc != 0) usage(); 73 74 plumb.send = plumbopen("send", OWRITE); 75 if (plumb.send < 0) fprint(2, "%r\n"); 76 plumb.recv = plumbopen(plumb.port, OREAD); 77 if (plumb.recv <0) fprint(2, "%r\n"); 78 79 proccreate(threadplumb, nil, 1024); 80 update_selstr(); 81 ampsrv.tree = alloctree("amp", "amp", DMDIR|0555, nil); 82 fdata = createfile(ampsrv.tree->root, "data", "amp", 0666, nil); 83 fcut = createfile(ampsrv.tree->root, "cut", "amp", 0666, nil); 84 fctl = createfile(ampsrv.tree->root, "ctl", "amp", 0666, nil); 85 threadpostmountsrv(&srv, service, mountpath, MREPL); 86 } 87 88 void 89 threadplumb(void *) 90 { 91 Plumbmsg *m; 92 vlong s, e; 93 if (plumb.recv < 0) return; 94 threadsetname("plumb"); 95 for (;;) { 96 m = plumbrecv(plumb.recv); 97 if (m->ndata < 24) fprint(2, "plumb message too short\n"); 98 else if (strcmp(m->src, "ampfs") != 0){ 99 s = strtoll(m->data, nil, 10); 100 e = strtoll(m->data + 12, nil, 10); 101 sel.max = s, sel.min = e; 102 normalize_sel(); 103 update_selstr(); 104 fcut->length = (sel.max - sel.min); 105 } 106 plumbfree(m); 107 } 108 } 109 110 void 111 plumbsel(void) 112 { 113 Plumbmsg *m; 114 m = mallocz(sizeof(Plumbmsg), 1); 115 m->src = smprint("ampfs"); 116 m->dst = strdup(plumb.port); 117 m->type = strdup("text"); 118 m->data = smprint("%11lld %11lld ", sel.min, sel.max); 119 m->ndata = strlen(m->data); 120 plumbsend(plumb.send, m); 121 plumbfree(m); 122 } 123 124 void 125 fs_open(Req *r) 126 { 127 char *rstr = nil; 128 File *file = r->fid->file; 129 uchar mode = r->ifcall.mode; 130 if (file == fcut) { 131 fcut_open(r); 132 goto end; 133 } 134 if ((mode & OTRUNC) == 0) goto end; 135 if (file == fctl) goto end; 136 if (file == fdata) { 137 pg.length = 0; 138 fdata->length = 0; 139 // TODO: free pages ??? 140 // probably better to do it on fs_close() 141 goto end; 142 } 143 rstr = "what"; 144 end: 145 respond(r, rstr); 146 } 147 148 void 149 fs_read(Req *r) 150 { 151 if (r->fid->file == fdata) { 152 r->ofcall.count = pbread(&pg, r->ofcall.data, 153 r->ifcall.count, r->ifcall.offset); 154 respond(r, nil); 155 } else if (r->fid->file == fcut) { 156 long min = sel.min; 157 long max = sel.max; 158 r->ifcall.offset += min; 159 if (r->ifcall.offset + r->ifcall.count > max) 160 r->ifcall.count = max - r->ifcall.offset; 161 if (r->ifcall.offset > max) r->ifcall.count = 0; 162 r->ofcall.count = pbread(&pg, r->ofcall.data, 163 r->ifcall.count, r->ifcall.offset); 164 respond(r, nil); 165 } else if (r->fid->file == fctl) { 166 readstr(r, sel.str); 167 respond(r, nil); 168 } else { 169 respond(r, "nope"); 170 } 171 } 172 173 void 174 fs_write(Req *r) 175 { 176 if (r->fid->file == fdata) { 177 r->ofcall.count = pbwrite(&pg, r->ifcall.data, 178 r->ifcall.count, r->ifcall.offset); 179 if (pg.length > fdata->length) fdata->length = pg.length; 180 update_selstr(); 181 respond(r, nil); 182 } else if (r->fid->file == fcut) { 183 fcut_write(r); 184 update_selstr(); 185 respond(r, nil); 186 } else if (r->fid->file == fctl) { 187 vlong newmin, newmax; 188 char *np, *rp; 189 np = r->ifcall.data; 190 newmin = strtol(np, &rp, 10); 191 if (rp <= np) { 192 respond(r, "bad first value"); 193 return; 194 } 195 newmax = strtol(rp, &rp, 10); 196 if (rp <= np) { 197 respond(r, "bad second value"); 198 return; 199 } 200 if (rp - np > r->ifcall.count) { 201 respond(r, "somehow buffer overrun"); 202 return; 203 } 204 sel.min = newmin; 205 sel.max = newmax; 206 normalize_sel(); 207 update_selstr(); 208 fcut->length = (sel.max - sel.min); 209 r->ofcall.count = r->ifcall.count; 210 plumbsel(); 211 respond(r, nil); 212 } else { 213 respond(r, "nope"); 214 } 215 } 216 217 void 218 fcut_open(Req *r) 219 { 220 if ((r->ifcall.mode & OTRUNC) != 0) { 221 Page *maxpg = splitpage(&pg, sel.max); 222 Page *minpg = splitpage(&pg, sel.min); 223 assert(minpg != nil); 224 assert(maxpg != nil); 225 if (minpg->prev != nil) { 226 minpg->prev->next = maxpg; 227 maxpg->prev = minpg->prev; 228 } else { 229 pg.start = maxpg; 230 maxpg->prev = nil; 231 } 232 while (minpg != maxpg) { 233 Page *fp = minpg; 234 fp->as->len = 0; 235 minpg = fp->next; 236 freepage(fp); 237 } 238 pg.length -= sel.max - sel.min; 239 fdata->length = pg.length; 240 fcut->length = 0; 241 sel.max = sel.min; 242 normalize_sel(); 243 plumbsel(); 244 } 245 } 246 247 void 248 fcut_write(Req *r) 249 { 250 Page *maxpage; 251 vlong offset; 252 long count; 253 254 maxpage = splitpage(&pg, sel.max); 255 if (maxpage == nil) { 256 maxpage = addpage(&pg); 257 } 258 // insert more pages as needed 259 offset = r->ifcall.offset + sel.min; 260 count = r->ifcall.count; 261 while (offset + count > sel.max) { 262 long n = offset + count - sel.max; 263 if (n > PageSize) n = PageSize; 264 Page *ins = allocpage(); 265 ins->as->len = n; 266 ins->next = maxpage; 267 ins->prev = maxpage->prev; 268 if (maxpage->prev != nil) maxpage->prev->next = ins; 269 else { 270 pg.start = ins; 271 } 272 maxpage->prev = ins; 273 sel.max += n; 274 pg.length += n; 275 } 276 normalize_sel(); 277 fcut->length = (sel.max - sel.min); 278 fdata->length = pg.length; 279 plumbsel(); 280 // write to pagebuffer as usual 281 r->ofcall.count = pbwrite(&pg, r->ifcall.data, count, offset); 282 } 283 284 void 285 normalize_sel(void) 286 { 287 vlong bufmax = pg.length; 288 if (sel.min > bufmax) sel.min = bufmax; 289 if (sel.max > bufmax) sel.max = bufmax; 290 if (sel.min > sel.max) { 291 int x = sel.max; 292 sel.max = sel.min; 293 sel.min = x; 294 } 295 } 296 297 void 298 update_selstr(void) 299 { 300 snprint(sel.str, sizeof(sel.str), "%11lld %11lld %11lld \n", 301 sel.min, sel.max, pg.length); 302 }