vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

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 };