Devroot fixup
[akaros.git] / kern / drivers / dev / root.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15 #include <umem.h>
16
17 /* make it a power of 2 and nobody gets hurt */
18 #define MAXFILE 1024
19 int rootmaxq = MAXFILE;
20 int inumber = 13;
21
22 /* TODO:
23  *  - fix DOTDOT in gen.
24  *  - synchronization!  what needs protection from concurrent use, etc.
25  *      - clean up documentation and whatnot
26  *      - does remove, mkdir, rmdir work?
27  *      - fill this with cpio stuff
28  *      - figure out how to use the page cache
29  */
30
31 /* this gives you some idea of how much I like linked lists. Just make
32  * a big old table. Later on we can put next and prev indices into the
33  * data if we want but, our current kfs is 1-3 levels deep and very small
34  * (< 200 entries) so I doubt we'll need to do that. It just makes debugging
35  * memory a tad easier.
36  */
37 /* Da Rules.
38  * The roottab contains [name, qid, length, perm]. Length means length for files.
39  * Qid is [path, vers, type]. Path is me. vers is next. Type is QTDIR for dir
40  * and QTFILE for file and 0 for empty.
41  * Data is [dotdot, ptr, size, *sizep, next]
42  * dotdot is .., ptr is data (for files)
43  * size is # elements (for dirs)
44  * *sizep is a pointer for reasons not understood.
45  * next is the sibling. For a dir, it's the first element after '.'.
46  *      int     dotdot;
47  *      int     child; 
48  *      void    *ptr;
49  *      int     size;
50  *      int     *sizep;
51  * 
52  * entry is empty if type is 0. We look in roottab to determine that. 
53 */
54 /* we pack the qid as follows: path is the index, vers is ., and type is type */
55
56 /* Inferno seems to want to: perm |= DMDIR.  It gets checked in other places.
57  * NxM didn't want this, IIRC.
58  *
59  * Also note that "" (/, #r, whatever) has no vers/next/sibling. */
60 struct dirtab roottab[MAXFILE] = {
61         {"", {0, 0, QTDIR}, 0, DMDIR | 0777},
62         {"chan", {1, 2, QTDIR}, 0, DMDIR | 0777},
63         {"dev", {2, 3, QTDIR}, 0, DMDIR | 0777},
64         {"fd", {3, 4, QTDIR}, 0, DMDIR | 0777},
65         {"prog", {4, 5, QTDIR}, 0, DMDIR | 0777},
66         {"prof", {5, 6, QTDIR}, 0, DMDIR | 0777},
67         {"net", {6, 7, QTDIR}, 0, DMDIR | 0777},
68         {"net.alt", {7, 8, QTDIR}, 0, DMDIR | 0777},
69         {"nvfs", {8, 9, QTDIR}, 0, DMDIR | 0777},
70         {"env", {9, 10, QTDIR}, 0, DMDIR | 0777},
71         {"root", {10, 11, QTDIR}, 0, DMDIR | 0777},
72         {"srv", {11, 12, QTDIR}, 0, DMDIR | 0777},
73         {"mnt", {12, 0, QTDIR}, 0, DMDIR | 0777},
74 };
75
76 struct rootdata {
77         int dotdot;
78         int child;
79         void *ptr;
80         int size;
81         int *sizep;
82 };
83
84 struct rootdata rootdata[MAXFILE] = {
85         {0,     1,       &roottab[1],    12,    NULL},
86         {0,     0,       NULL,   0,      NULL},
87         {0,     0,       NULL,   0,      NULL},
88         {0,     0,       NULL,   0,      NULL},
89         {0,     0,       NULL,   0,      NULL},
90         {0,     0,       NULL,   0,      NULL},
91         {0,     0,       NULL,   0,      NULL},
92         {0,     0,       NULL,   0,      NULL},
93         {0,     0,       NULL,   0,      NULL},
94         {0,     0,       NULL,   0,      NULL},
95         {0,     0,       NULL,   0,      NULL},
96         {0,     0,       NULL,   0,      NULL},
97         {0,     0,       NULL,   0,      NULL},
98 };
99
100 /* this is super useful */
101 void dumprootdev(void)
102 {
103         struct dirtab *r = roottab;
104         struct rootdata *rd = rootdata;
105         int i;
106
107         printk("[       dirtab     ]      name: [pth, ver, typ],   len,        "
108                "perm,  .., chld,       data pointer,  size,       size pointer\n");
109         for (i = 0; i < rootmaxq; i++, r++, rd++) {
110                 if (i && (!r->name[0]))
111                         continue;
112                 printk("[%p]%10s: [%3d, %3d, %3d], %5d, %11o,",
113                            r,
114                            r->name, r->qid.path, r->qid.vers, r->qid.type,
115                            r->length, r->perm);
116                 printk(" %3d, %4d, %p, %5d, %p\n",
117                            rd->dotdot, rd->child, rd->ptr, rd->size, rd->sizep);
118         }
119 }
120
121 static int findempty(void)
122 {
123         int i;
124         for (i = 0; i < rootmaxq; i++) {
125                 if (!roottab[i].qid.type) {
126                         memset(&roottab[i], 0, sizeof(roottab[i]));
127                         return i;
128                 }
129         }
130         return -1;
131 }
132
133 static void freeempty(int i)
134 {
135         roottab[i].qid.type = 0;
136 }
137
138 static int newentry(int parent)
139 {
140         int n = findempty();
141         int sib;
142         if (n < 0)
143                 error("#r. No more");
144         printd("new entry is %d\n", n);
145         /* add the new one to the head of the linked list.  vers is 'next' */
146         roottab[n].qid.vers = rootdata[parent].child;
147         rootdata[parent].child = n;
148         return n;
149 }
150
151 static int createentry(int dir, char *name, int omode, int perm)
152 {
153         int n = newentry(dir);
154         strncpy(roottab[n].name, name, sizeof(roottab[n].name));
155         roottab[n].length = 0;
156         roottab[n].perm = perm;
157         /* vers is already properly set. */
158         mkqid(&roottab[n].qid, n, roottab[n].qid.vers,
159               perm & DMDIR ? QTDIR : QTFILE);
160         rootdata[n].dotdot = roottab[dir].qid.path;
161         rootdata[dir].ptr = &roottab[n];
162         rootdata[n].size = 0;
163         rootdata[n].sizep = &rootdata[n].size;
164         return n;
165 }
166
167 static void rootinit(void)
168 {
169         /* brho: pretty sure this should only be run once.  putting it in attach
170          * will run it multiple times. */
171         int i;
172         uint32_t len;
173         struct rootdata *r;
174         /* this begins with the root. */
175         for (i = 0;; i++) {
176                 r = &rootdata[i];
177                 if (r->sizep) {
178                         len = *r->sizep;
179                         r->size = len;
180                         roottab[i].length = len;
181                 }
182                 i = roottab[i].qid.vers;
183                 if (!i)
184                         break;
185         }
186 }
187
188 static struct chan *rootattach(char *spec)
189 {
190         struct chan *c;
191         if (*spec)
192                 error(Ebadspec);
193         c = devattach('r', spec);
194         mkqid(&c->qid, roottab[0].qid.path, roottab[0].qid.vers, QTDIR);
195         return c;
196 }
197
198 static int
199 rootgen(struct chan *c, char *name,
200                 struct dirtab *tab, int nd, int s, struct dir *dp)
201 {
202         int p, i;
203         struct rootdata *r;
204         int iter;
205         printd("rootgen, path is %d, tap %p, nd %d s %d name %s\n", c->qid.path,
206                tab, nd, s, name);
207
208         if (s == DEVDOTDOT) {
209                 panic("this is busted");
210                 p = rootdata[c->qid.path].dotdot;
211                 // XXX we need to set the vers too.  equiv to mkqid(&c->qid, ...)
212                 c->qid.path = p;
213                 c->qid.type = QTDIR;
214                 name = "#r";
215                 if (p != 0) {
216                         /* TODO: what is this doing?  do we want to walk the entire table,
217                          * or are we just walking the siblings of our parent? */
218                         for (i = p;;) {
219                                 if (roottab[i].qid.path == c->qid.path) {
220                                         name = roottab[i].name;
221                                         break;
222                                 }
223                                 i = roottab[i].qid.vers;
224                                 if (!i)
225                                         break;
226                         }
227                 }
228                 devdir(c, c->qid, name, 0, eve, 0777, dp);
229                 return 1;
230         }
231
232         if (c->qid.type != QTDIR) {
233                 /* return ourselved the first time; after that, -1 */
234                 if (s)
235                         return -1;
236                 tab = &roottab[c->qid.path];
237                 devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
238                 return 1;
239         }
240
241         if (name != NULL) {
242                 int path = c->qid.path;
243                 isdir(c);
244                 tab = &roottab[rootdata[path].child];
245                 /* we're starting at a directory. It might be '.' */
246                 for (iter = 0, i = rootdata[path].child; /* break */; iter++) {
247                         if(strcmp(tab->name, name) == 0){
248                                 printd("Rootgen returns 1 for %s\n", name);
249                                 devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
250                                 printd("return 1 with [%d, %d, %d]\n", dp->qid.path,
251                                        dp->qid.vers, dp->qid.type);
252                                 return 1;
253                         }
254                         if (iter > rootmaxq) {
255                                 printk("BUG:");
256                                 dumprootdev();
257                                 printk("name %s\n", name);
258                                 return -1;
259                         }
260                         i = roottab[i].qid.vers;
261                         if (!i)
262                                 break;
263                         tab = &roottab[i];
264                 }
265                 printd("rootgen: :%s: failed at path %d\n", name, path);
266                 return -1;
267         }
268         /* need to gen the file or the contents of the directory we are currently
269          * at.  but i think the tab entries are all over the place.  nd is how
270          * many entries the directory has. */
271         if (s >= nd) {
272                 printd("S OVERFLOW\n");
273                 return -1;
274         }
275         //tab += s;     /* this would only work if our entries were contig in the tab */
276         for (i = rootdata[c->qid.path].child; i; i = roottab[i].qid.vers) {
277                 tab = &roottab[i];
278                 if (s-- == 0)
279                         break;
280         }
281         if (!i) {
282                 printd("I OVERFLOW\n");
283                 return -1;
284         }
285         printd("root scan find returns path %p name %s\n", tab->qid.path, tab->name);
286         devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
287         return 1;
288 }
289
290 static struct walkqid *rootwalk(struct chan *c, struct chan *nc, char **name,
291                                                                 int nname)
292 {
293         uint32_t p;
294         if (0){
295                 printk("rootwalk: c %p. :", c);
296                 if (nname){
297                         int i;
298                         for (i = 0; i < nname - 1; i++)
299                                 printk("%s/", name[i]);
300                         printk("%s:\n", name[i]);
301                 }
302         }
303         p = c->qid.path;
304         printd("Start from #%d at %p\n", p, &roottab[p]);
305         return devwalk(c, nc, name, nname, &roottab[p], rootdata[p].size, rootgen);
306 }
307
308 static int rootstat(struct chan *c, uint8_t * dp, int n)
309 {
310         int p = c->qid.path;
311         return devstat(c, dp, n, rootdata[p].ptr, rootdata[p].size, rootgen);
312 }
313
314 static struct chan *rootopen(struct chan *c, int omode)
315 {
316         int p;
317         printd("rootopen: omode %o\n", omode);
318         p = c->qid.path;
319         return devopen(c, omode, rootdata[p].ptr, rootdata[p].size, rootgen);
320 }
321
322 static void rootcreate(struct chan *c, char *name, int omode, uint32_t perm)
323 {
324         struct dirtab *r = &roottab[c->qid.path], *newr;
325         struct rootdata *rd = &rootdata[c->qid.path];
326         /* need to filter openmode so that it gets only the access-type bits */
327         omode = openmode(omode);
328         c->mode = openmode(omode);
329         printd("rootcreate: c %p, name %s, omode %o, perm %x\n", 
330                c, name, omode, perm);
331         /* find an empty slot */
332         int path = c->qid.path;
333         int newfile;
334         newfile = createentry(path, name, omode, perm);
335         c->qid = roottab[newfile].qid;  /* need to update c */
336         rd->size++;
337         if (newfile > rootmaxq)
338                 rootmaxq = newfile;
339         printd("create: %s, newfile %d, dotdot %d, rootmaxq %d\n", name, newfile,
340                rootdata[newfile].dotdot, rootmaxq);
341 }
342
343 /*
344  * sysremove() knows this is a nop
345  *              fyi, this isn't true anymore!  they need to set c->type = -1;
346  */
347 static void rootclose(struct chan *c)
348 {
349 }
350
351 static long rootread(struct chan *c, void *buf, long n, int64_t offset)
352 {
353         uint32_t p, len;
354         uint8_t *data;
355
356         p = c->qid.path;
357         if (c->qid.type & QTDIR) {
358                 return devdirread(c, buf, n, rootdata[p].ptr, rootdata[p].size,
359                                                   rootgen);
360         }
361         len = rootdata[p].size;
362         if (offset < 0 || offset >= len) {
363                 return 0;
364         }
365         if (offset + n > len)
366                 n = len - offset;
367         data = rootdata[p].ptr;
368         /* we might call read from the kernel (load_elf()) */
369         if (current) {
370                 if (memcpy_to_user_errno(current, buf, data + offset, n) < 0)
371                         error("%s: bad user addr %p", __FUNCTION__, buf);
372         } else {
373                 memcpy(buf, data + offset, n);
374         }
375         return n;
376 }
377
378 /* For now, just kzmalloc the right amount. Later, we should use
379  * pages so mmap will go smoothly. Would be really nice to have a
380  * kpagemalloc ... barret?
381  *              we have kpage_alloc (gives a page) and kpage_alloc_addr (void*)
382  */
383 static long rootwrite(struct chan *c, void *a, long n, int64_t off)
384 {
385         struct rootdata *rd = &rootdata[c->qid.path];
386         struct dirtab *r = &roottab[c->qid.path];
387
388         if (off < 0)
389                 error("rootwrite: offset < 0!");
390
391         if (off + n > rd->size){
392                 void *p;
393                 p = krealloc(rd->ptr, off + n, KMALLOC_WAIT);
394                 if (! p)
395                         error("rootwrite: could not grow the file to %d bytes", off + n);
396                 rd->ptr = p;
397                 rd->size = off + n;
398         }
399         assert(current);
400         if (memcpy_from_user_errno(current, rd->ptr + off, a, n) < 0)
401                 error("%s: bad user addr %p", __FUNCTION__, a);
402
403         return n;
404 }
405
406 struct dev rootdevtab __devtab = {
407         'r',
408         "root",
409         devreset,
410         rootinit,
411         devshutdown,
412         rootattach,
413         rootwalk,
414         rootstat,
415         rootopen,
416         rootcreate,
417         rootclose,
418         rootread,
419         devbread,
420         rootwrite,
421         devbwrite,
422         devremove,
423         devwstat,
424         devpower,
425         devchaninfo,
426 };