devram.c (6712B)
1 #include "u.h" 2 #include "lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "error.h" 7 8 #include "netif.h" 9 10 typedef struct Ram Ram; 11 struct Ram 12 { 13 QLock lk; 14 Ram *next; 15 int ref; 16 /* simple for now */ 17 uchar **pages; 18 int pagecount; 19 int size; 20 int qref[2]; 21 ulong path; 22 }; 23 24 struct 25 { 26 Lock lk; 27 ulong path; 28 } ramalloc; 29 30 enum 31 { 32 Qdir, 33 Qdata0, 34 Qctl, 35 }; 36 37 Dirtab ramdir[] = 38 { 39 ".", {Qdir,0,QTDIR}, 0, DMDIR|0500, 40 "data", {Qdata0}, 0, 0600, 41 "ctl", {Qctl}, 0, 0600, 42 }; 43 #define NPIPEDIR 3 44 45 static void 46 raminit(void) 47 { 48 } 49 50 /* 51 * create a ram, no streams are created until an open 52 */ 53 static Chan* 54 ramattach(char *spec) 55 { 56 Ram *p; 57 Chan *c; 58 59 c = devattach('R', spec); 60 p = malloc(sizeof(Ram)); 61 if(p == 0) 62 exhausted("memory"); 63 p->ref = 1; 64 p->size = 0; 65 p->pagecount = 1; 66 p->pages = mallocz(sizeof(char *), 1); 67 p->pages[0] = mallocz(BY2PG, 1); 68 lock(&ramalloc.lk); 69 p->path = ++ramalloc.path; 70 unlock(&ramalloc.lk); 71 72 mkqid(&c->qid, NETQID(2*p->path, Qdir), 0, QTDIR); 73 c->aux = p; 74 c->dev = 0; 75 return c; 76 } 77 78 static int 79 ramgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp) 80 { 81 Qid q; 82 int len; 83 Ram *p; 84 85 if(i == DEVDOTDOT){ 86 devdir(c, c->qid, "#R", 0, eve, DMDIR|0555, dp); 87 return 1; 88 } 89 i++; /* skip . */ 90 if(tab==0 || i>=ntab) 91 return -1; 92 93 tab += i; 94 p = c->aux; 95 switch((ulong)tab->qid.path){ 96 case Qdata0: 97 len = p->size; 98 break; 99 case Qctl: 100 len = 0; 101 break; 102 default: 103 len = tab->length; 104 break; 105 } 106 mkqid(&q, NETQID(NETID(c->qid.path), tab->qid.path), 0, QTFILE); 107 devdir(c, q, tab->name, len, eve, tab->perm, dp); 108 return 1; 109 } 110 111 112 static Walkqid* 113 ramwalk(Chan *c, Chan *nc, char **name, int nname) 114 { 115 Walkqid *wq; 116 Ram *p; 117 118 wq = devwalk(c, nc, name, nname, ramdir, NPIPEDIR, ramgen); 119 if(wq != nil && wq->clone != nil && wq->clone != c){ 120 p = c->aux; 121 qlock(&p->lk); 122 p->ref++; 123 if(c->flag & COPEN){ 124 print("channel open in ramwalk\n"); 125 switch(NETTYPE(c->qid.path)){ 126 case Qdata0: 127 p->qref[0]++; 128 break; 129 case Qctl: 130 p->qref[1]++; 131 break; 132 } 133 } 134 qunlock(&p->lk); 135 } 136 return wq; 137 } 138 139 static int 140 ramstat(Chan *c, uchar *db, int n) 141 { 142 Ram *p; 143 Dir dir; 144 145 p = c->aux; 146 147 switch(NETTYPE(c->qid.path)){ 148 case Qdir: 149 devdir(c, c->qid, ".", 0, eve, DMDIR|0555, &dir); 150 break; 151 case Qdata0: 152 devdir(c, c->qid, "data", p->size, eve, 0600, &dir); 153 break; 154 case Qctl: 155 devdir(c, c->qid, "ctl", 0, eve, 0600, &dir); 156 break; 157 default: 158 panic("ramstat"); 159 } 160 n = convD2M(&dir, db, n); 161 if(n < BIT16SZ) 162 error(Eshortstat); 163 return n; 164 } 165 166 /* 167 * if the stream doesn't exist, create it 168 */ 169 static Chan* 170 ramopen(Chan *c, int omode) 171 { 172 Ram *p; 173 174 if(c->qid.type & QTDIR){ 175 if(omode != OREAD) 176 error(Ebadarg); 177 c->mode = omode; 178 c->flag |= COPEN; 179 c->offset = 0; 180 return c; 181 } 182 183 p = c->aux; 184 qlock(&p->lk); 185 switch(NETTYPE(c->qid.path)){ 186 case Qdata0: 187 p->qref[0]++; 188 break; 189 case Qctl: 190 p->qref[1]++; 191 break; 192 } 193 qunlock(&p->lk); 194 195 c->mode = openmode(omode); 196 c->flag |= COPEN; 197 c->offset = 0; 198 c->iounit = qiomaxatomic; 199 return c; 200 } 201 202 static void 203 ramclose(Chan *c) 204 { 205 Ram *p; 206 207 p = c->aux; 208 qlock(&p->lk); 209 210 if(c->flag & COPEN){ 211 switch(NETTYPE(c->qid.path)){ 212 case Qdata0: 213 p->qref[0]--; 214 break; 215 case Qctl: 216 p->qref[1]--; 217 break; 218 } 219 } 220 221 /* 222 * free the structure on last close 223 */ 224 p->ref--; 225 if(p->ref == 0){ 226 int i; 227 qunlock(&p->lk); 228 for(i = 0; i < p->pagecount; i++) 229 free(p->pages[i]); 230 free(p->pages); 231 free(p); 232 } else 233 qunlock(&p->lk); 234 } 235 236 static long 237 rampageread(Ram *p, void *va, long n, vlong offset) 238 { 239 int i; 240 long total, offinpage, leninpage; 241 242 total = n; 243 244 /* figure out what range we can actually read */ 245 if(offset > p->size) 246 return 0; 247 if(offset + n > p->size) 248 n = p->size - offset; 249 /* granular copy */ 250 for(i = offset / BY2PG; n > 0; i++) { 251 /* i is the page */ 252 offinpage = offset & (BY2PG - 1); 253 leninpage = BY2PG - offinpage; 254 /* unless there is too little left ... */ 255 if(leninpage > n) 256 leninpage = n; 257 memcpy(va, p->pages[i] + offinpage, leninpage); 258 offset += offinpage; 259 n -= leninpage; 260 va += leninpage; 261 } 262 return total; 263 } 264 265 static long 266 ramread(Chan *c, void *va, long n, vlong offset) 267 { 268 Ram *p; 269 char *buf, *s, *e; 270 271 p = c->aux; 272 273 switch(NETTYPE(c->qid.path)){ 274 case Qdir: 275 return devdirread(c, va, n, ramdir, NPIPEDIR, ramgen); 276 case Qdata0: 277 return rampageread(p, va, n, offset); 278 case Qctl: 279 buf = smalloc(8192); 280 s = buf; 281 e = buf + 8192; 282 s = seprint(s, e, "pages %p count %d ", p->pages, p->pagecount); 283 seprint(s, e, "size %d\n", p->size); 284 n = readstr(offset, va, n, buf); 285 free(buf); 286 return n; 287 default: 288 panic("ramread"); 289 } 290 return -1; /* not reached */ 291 } 292 293 /* for the range offset .. offset + n, make sure we have pages */ 294 static 295 void pages(Ram *p, long n, vlong offset) 296 { 297 int i; 298 int newpagecount; 299 uchar **newpages; 300 301 newpagecount = (offset + n + BY2PG-1)/BY2PG; 302 if(newpagecount > p->pagecount) { 303 newpages = mallocz(sizeof(char *) * newpagecount, 1); 304 if(!newpages) 305 error("No more pages in devram"); 306 memcpy(newpages, p->pages, sizeof(char *) * p->pagecount); 307 free(p->pages); 308 p->pages = newpages; 309 p->pagecount = newpagecount; 310 /* now allocate them */ 311 for(i = offset / BY2PG; i < newpagecount; i++) { 312 if(p->pages[i]) 313 continue; 314 p->pages[i] = mallocz(BY2PG, 1); 315 } 316 } 317 } 318 319 static long 320 rampagewrite(Ram *p, void *va, long n, vlong offset) 321 { 322 int i; 323 long total, offinpage, leninpage; 324 long newsize; 325 326 total = n; 327 pages(p, n, offset); 328 329 /* granular copy */ 330 newsize = offset + n; 331 for(i = offset / BY2PG; n > 0; i++) { 332 /* i is the page */ 333 offinpage = offset & (BY2PG - 1); 334 leninpage = BY2PG - offinpage; 335 /* unless there is too little left ... */ 336 if(leninpage > n) 337 leninpage = n; 338 memcpy(p->pages[i] + offinpage, va, leninpage); 339 offset += leninpage; 340 n -= leninpage; 341 va += leninpage; 342 } 343 p->size = newsize > p->size? newsize : p->size; 344 return total; 345 } 346 static long 347 ramwrite(Chan *c, void *va, long n, vlong offset) 348 { 349 Ram *p; 350 int i; 351 uchar **new; 352 uchar *page; 353 354 if(!islo()) 355 print("ramwrite hi %lux\n", getcallerpc(&c)); 356 p = c->aux; 357 switch(NETTYPE(c->qid.path)){ 358 case Qdata0: 359 n = rampagewrite(p, va, n, offset); 360 break; 361 362 case Qctl: 363 if(strcmp(va, "free") == 0) { 364 new = mallocz(sizeof(char *), 1); 365 page = p->pages[0]; 366 for(i = 1; i < p->pagecount; i++) 367 free(p->pages[i]); 368 free(p->pages); 369 p->pages = new; 370 p->pages[0] = page; 371 p->size = 0; 372 p->pagecount = 1; 373 } else { 374 error("bad command"); 375 } 376 break; 377 378 default: 379 panic("ramwrite"); 380 } 381 382 return n; 383 } 384 385 386 Dev ramdevtab = { 387 'R', 388 "ram", 389 390 devreset, 391 raminit, 392 devshutdown, 393 ramattach, 394 ramwalk, 395 ramstat, 396 ramopen, 397 devcreate, 398 ramclose, 399 ramread, 400 devbread, 401 ramwrite, 402 devbwrite, 403 devremove, 404 devwstat, 405 };