devram.c - vx32 - Local 9vx git repository for patches.
(HTM) git clone git://r-36.net/vx32
(DIR) Log
(DIR) Files
(DIR) 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 };