read_exactly_n()
[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  *
61  * If you want to add new entries, add it to the roottab such that the linked
62  * list of indexes is a cycle (change the last current one), then add an entry
63  * to rootdata, and then change the first rootdata entry to have another entry.
64  * Yeah, it's a pain in the ass. */
65 struct dirtab roottab[MAXFILE] = {
66         {"", {0, 0, QTDIR}, 0, DMDIR | 0777},
67         {"chan", {1, 2, QTDIR}, 0, DMDIR | 0777},
68         {"dev", {2, 3, QTDIR}, 0, DMDIR | 0777},
69         {"fd", {3, 4, QTDIR}, 0, DMDIR | 0777},
70         {"prog", {4, 5, QTDIR}, 0, DMDIR | 0777},
71         {"prof", {5, 6, QTDIR}, 0, DMDIR | 0777},
72         {"net", {6, 7, QTDIR}, 0, DMDIR | 0777},
73         {"net.alt", {7, 8, QTDIR}, 0, DMDIR | 0777},
74         {"nvfs", {8, 9, QTDIR}, 0, DMDIR | 0777},
75         {"env", {9, 10, QTDIR}, 0, DMDIR | 0777},
76         {"root", {10, 11, QTDIR}, 0, DMDIR | 0777},
77         {"srv", {11, 12, QTDIR}, 0, DMDIR | 0777},
78         {"mnt", {12, 13, QTDIR}, 0, DMDIR | 0777},
79         {"proc", {13, 0, QTDIR}, 0, DMDIR | 0777},
80 };
81
82 struct rootdata {
83         int dotdot;
84         int child;
85         void *ptr;
86         int size;
87         int *sizep;
88 };
89
90 struct rootdata rootdata[MAXFILE] = {
91         {0,     1,       &roottab[1],    13,    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         {0,     0,       NULL,   0,      NULL},
99         {0,     0,       NULL,   0,      NULL},
100         {0,     0,       NULL,   0,      NULL},
101         {0,     0,       NULL,   0,      NULL},
102         {0,     0,       NULL,   0,      NULL},
103         {0,     0,       NULL,   0,      NULL},
104         {0,     0,       NULL,   0,      NULL},
105 };
106
107 /* this is super useful */
108 void dumprootdev(void)
109 {
110         struct dirtab *r = roottab;
111         struct rootdata *rd = rootdata;
112         int i;
113
114         printk("[       dirtab     ]      name: [pth, ver, typ],   len,        "
115                "perm,  .., chld,       data pointer,  size,       size pointer\n");
116         for (i = 0; i < rootmaxq; i++, r++, rd++) {
117                 if (i && (!r->name[0]))
118                         continue;
119                 printk("[%p]%10s: [%3d, %3d, %3d], %5d, %11o,",
120                            r,
121                            r->name, r->qid.path, r->qid.vers, r->qid.type,
122                            r->length, r->perm);
123                 printk(" %3d, %4d, %p, %5d, %p\n",
124                            rd->dotdot, rd->child, rd->ptr, rd->size, rd->sizep);
125         }
126 }
127
128 static int findempty(void)
129 {
130         int i;
131         for (i = 0; i < rootmaxq; i++) {
132                 if (!roottab[i].qid.type) {
133                         memset(&roottab[i], 0, sizeof(roottab[i]));
134                         return i;
135                 }
136         }
137         return -1;
138 }
139
140 static void freeempty(int i)
141 {
142         roottab[i].qid.type = 0;
143 }
144
145 static int newentry(int parent)
146 {
147         int n = findempty();
148         int sib;
149         if (n < 0)
150                 error("#r. No more");
151         printd("new entry is %d\n", n);
152         /* add the new one to the head of the linked list.  vers is 'next' */
153         roottab[n].qid.vers = rootdata[parent].child;
154         rootdata[parent].child = n;
155         return n;
156 }
157
158 static int createentry(int dir, char *name, int omode, int perm)
159 {
160         int n = newentry(dir);
161         strncpy(roottab[n].name, name, sizeof(roottab[n].name));
162         roottab[n].length = 0;
163         roottab[n].perm = perm;
164         /* vers is already properly set. */
165         mkqid(&roottab[n].qid, n, roottab[n].qid.vers,
166               perm & DMDIR ? QTDIR : QTFILE);
167         rootdata[n].dotdot = roottab[dir].qid.path;
168         rootdata[dir].ptr = &roottab[n];
169         rootdata[n].size = 0;
170         rootdata[n].sizep = &rootdata[n].size;
171         return n;
172 }
173
174 static void rootinit(void)
175 {
176         /* brho: pretty sure this should only be run once.  putting it in attach
177          * will run it multiple times. */
178         int i;
179         uint32_t len;
180         struct rootdata *r;
181         /* this begins with the root. */
182         for (i = 0;; i++) {
183                 r = &rootdata[i];
184                 if (r->sizep) {
185                         len = *r->sizep;
186                         r->size = len;
187                         roottab[i].length = len;
188                 }
189                 i = roottab[i].qid.vers;
190                 if (!i)
191                         break;
192         }
193 }
194
195 static struct chan *rootattach(char *spec)
196 {
197         struct chan *c;
198         if (*spec)
199                 error(Ebadspec);
200         c = devattach('r', spec);
201         mkqid(&c->qid, roottab[0].qid.path, roottab[0].qid.vers, QTDIR);
202         return c;
203 }
204
205 static int
206 rootgen(struct chan *c, char *name,
207                 struct dirtab *tab, int nd, int s, struct dir *dp)
208 {
209         int p, i;
210         struct rootdata *r;
211         int iter;
212         printd("rootgen, path is %d, tap %p, nd %d s %d name %s\n", c->qid.path,
213                tab, nd, s, name);
214
215         if (s == DEVDOTDOT) {
216                 panic("this is busted");
217                 p = rootdata[c->qid.path].dotdot;
218                 // XXX we need to set the vers too.  equiv to mkqid(&c->qid, ...)
219                 c->qid.path = p;
220                 c->qid.type = QTDIR;
221                 name = "#r";
222                 if (p != 0) {
223                         /* TODO: what is this doing?  do we want to walk the entire table,
224                          * or are we just walking the siblings of our parent? */
225                         for (i = p;;) {
226                                 if (roottab[i].qid.path == c->qid.path) {
227                                         name = roottab[i].name;
228                                         break;
229                                 }
230                                 i = roottab[i].qid.vers;
231                                 if (!i)
232                                         break;
233                         }
234                 }
235                 devdir(c, c->qid, name, 0, eve, 0777, dp);
236                 return 1;
237         }
238
239         if (c->qid.type != QTDIR) {
240                 /* return ourselved the first time; after that, -1 */
241                 if (s)
242                         return -1;
243                 tab = &roottab[c->qid.path];
244                 devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
245                 return 1;
246         }
247
248         if (name != NULL) {
249                 int path = c->qid.path;
250                 isdir(c);
251                 tab = &roottab[rootdata[path].child];
252                 /* we're starting at a directory. It might be '.' */
253                 for (iter = 0, i = rootdata[path].child; /* break */; iter++) {
254                         if(strcmp(tab->name, name) == 0){
255                                 printd("Rootgen returns 1 for %s\n", name);
256                                 devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
257                                 printd("return 1 with [%d, %d, %d]\n", dp->qid.path,
258                                        dp->qid.vers, dp->qid.type);
259                                 return 1;
260                         }
261                         if (iter > rootmaxq) {
262                                 printk("BUG:");
263                                 dumprootdev();
264                                 printk("name %s\n", name);
265                                 return -1;
266                         }
267                         i = roottab[i].qid.vers;
268                         if (!i)
269                                 break;
270                         tab = &roottab[i];
271                 }
272                 printd("rootgen: :%s: failed at path %d\n", name, path);
273                 return -1;
274         }
275         /* need to gen the file or the contents of the directory we are currently
276          * at.  but i think the tab entries are all over the place.  nd is how
277          * many entries the directory has. */
278         if (s >= nd) {
279                 printd("S OVERFLOW\n");
280                 return -1;
281         }
282         //tab += s;     /* this would only work if our entries were contig in the tab */
283         for (i = rootdata[c->qid.path].child; i; i = roottab[i].qid.vers) {
284                 tab = &roottab[i];
285                 if (s-- == 0)
286                         break;
287         }
288         if (!i) {
289                 printd("I OVERFLOW\n");
290                 return -1;
291         }
292         printd("root scan find returns path %p name %s\n", tab->qid.path, tab->name);
293         devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
294         return 1;
295 }
296
297 static struct walkqid *rootwalk(struct chan *c, struct chan *nc, char **name,
298                                                                 int nname)
299 {
300         uint32_t p;
301         if (0){
302                 printk("rootwalk: c %p. :", c);
303                 if (nname){
304                         int i;
305                         for (i = 0; i < nname - 1; i++)
306                                 printk("%s/", name[i]);
307                         printk("%s:\n", name[i]);
308                 }
309         }
310         p = c->qid.path;
311         printd("Start from #%d at %p\n", p, &roottab[p]);
312         return devwalk(c, nc, name, nname, &roottab[p], rootdata[p].size, rootgen);
313 }
314
315 static int rootstat(struct chan *c, uint8_t * dp, int n)
316 {
317         int p = c->qid.path;
318         return devstat(c, dp, n, rootdata[p].ptr, rootdata[p].size, rootgen);
319 }
320
321 static struct chan *rootopen(struct chan *c, int omode)
322 {
323         int p;
324         printd("rootopen: omode %o\n", omode);
325         p = c->qid.path;
326         return devopen(c, omode, rootdata[p].ptr, rootdata[p].size, rootgen);
327 }
328
329 static void rootcreate(struct chan *c, char *name, int omode, uint32_t perm)
330 {
331         struct dirtab *r = &roottab[c->qid.path], *newr;
332         struct rootdata *rd = &rootdata[c->qid.path];
333         /* need to filter openmode so that it gets only the access-type bits */
334         omode = openmode(omode);
335         c->mode = openmode(omode);
336         printd("rootcreate: c %p, name %s, omode %o, perm %x\n", 
337                c, name, omode, perm);
338         /* find an empty slot */
339         int path = c->qid.path;
340         int newfile;
341         newfile = createentry(path, name, omode, perm);
342         c->qid = roottab[newfile].qid;  /* need to update c */
343         rd->size++;
344         if (newfile > rootmaxq)
345                 rootmaxq = newfile;
346         printd("create: %s, newfile %d, dotdot %d, rootmaxq %d\n", name, newfile,
347                rootdata[newfile].dotdot, rootmaxq);
348 }
349
350 /*
351  * sysremove() knows this is a nop
352  *              fyi, this isn't true anymore!  they need to set c->type = -1;
353  */
354 static void rootclose(struct chan *c)
355 {
356 }
357
358 static long rootread(struct chan *c, void *buf, long n, int64_t offset)
359 {
360         uint32_t p, len;
361         uint8_t *data;
362
363         p = c->qid.path;
364         if (c->qid.type & QTDIR) {
365                 return devdirread(c, buf, n, rootdata[p].ptr, rootdata[p].size,
366                                                   rootgen);
367         }
368         len = rootdata[p].size;
369         if (offset < 0 || offset >= len) {
370                 return 0;
371         }
372         if (offset + n > len)
373                 n = len - offset;
374         data = rootdata[p].ptr;
375         /* we can't really claim it has to be a user address. Lots of
376          * kernel things read directly, e.g. /dev/reboot, #V, etc.
377          * Address validation should be done in the syscall layer.
378          */
379         memcpy(buf, data + offset, n);
380         return n;
381 }
382
383 /* For now, just kzmalloc the right amount. Later, we should use
384  * pages so mmap will go smoothly. Would be really nice to have a
385  * kpagemalloc ... barret?
386  *              we have kpage_alloc (gives a page) and kpage_alloc_addr (void*)
387  */
388 static long rootwrite(struct chan *c, void *a, long n, int64_t off)
389 {
390         struct rootdata *rd = &rootdata[c->qid.path];
391         struct dirtab *r = &roottab[c->qid.path];
392
393         if (off < 0)
394                 error("rootwrite: offset < 0!");
395
396         if (off + n > rd->size){
397                 void *p;
398                 p = krealloc(rd->ptr, off + n, KMALLOC_WAIT);
399                 if (! p)
400                         error("rootwrite: could not grow the file to %d bytes", off + n);
401                 rd->ptr = p;
402                 rd->size = off + n;
403         }
404         assert(current);
405         if (memcpy_from_user_errno(current, rd->ptr + off, a, n) < 0)
406                 error("%s: bad user addr %p", __FUNCTION__, a);
407
408         return n;
409 }
410
411 static int rootwstat(struct chan *c, uint8_t *m_buf, int m_buf_sz)
412 {
413         struct dirtab *file = &roottab[c->qid.path];
414         struct dir *dir;
415         int m_sz;
416
417         /* TODO: some security check, Eperm on error */
418
419         /* common trick in wstats.  we want the dir and any strings in the M.  the
420          * strings are smaller than entire M (strings plus other M).  the strings
421          * will be placed right after the dir (dir[1]) */
422         dir = kzmalloc(sizeof(struct dir) + m_buf_sz, KMALLOC_WAIT);
423         m_sz = convM2D(m_buf, m_buf_sz, &dir[0], (char*)&dir[1]);
424         if (!m_sz) {
425                 kfree(dir);
426                 error(Eshortstat);
427         }
428         /* TODO: handle more things than just the mode */
429         if (!emptystr(dir->name))
430                 printk("[%s] attempted rename of %s to %s\n", __FUNCTION__,
431                        file->name, dir->name);  /* strncpy for this btw */
432         if (dir->mode != ~0UL)
433                 file->perm = dir->mode | (file->qid.type == QTDIR ? DMDIR : 0);
434         kfree(dir);
435         return m_sz;
436 }
437
438 struct dev rootdevtab __devtab = {
439         'r',
440         "root",
441         devreset,
442         rootinit,
443         devshutdown,
444         rootattach,
445         rootwalk,
446         rootstat,
447         rootopen,
448         rootcreate,
449         rootclose,
450         rootread,
451         devbread,
452         rootwrite,
453         devbwrite,
454         devremove,
455         rootwstat,
456         devpower,
457         devchaninfo,
458 };