Export CONFIG_ options via #version/kconfig
[akaros.git] / kern / drivers / dev / root.c
1 /* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
2  * Portions Copyright © 1997-1999 Vita Nuova Limited
3  * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
4  *                                (www.vitanuova.com)
5  * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
6  *
7  * Modified for the Akaros operating system:
8  * Copyright (c) 2013-2014 The Regents of the University of California
9  * Copyright (c) 2013-2015 Google Inc.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE. */
28
29 #include <vfs.h>
30 #include <kfs.h>
31 #include <slab.h>
32 #include <kmalloc.h>
33 #include <kref.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <assert.h>
37 #include <error.h>
38 #include <cpio.h>
39 #include <pmap.h>
40 #include <smp.h>
41 #include <ip.h>
42 #include <umem.h>
43
44 struct dev rootdevtab;
45
46 static char *devname(void)
47 {
48         return rootdevtab.name;
49 }
50
51 /* make it a power of 2 and nobody gets hurt */
52 #define MAXFILE 1024
53 int rootmaxq = MAXFILE;
54 int inumber = 13;
55
56 /* TODO:
57  *  - synchronization!  what needs protection from concurrent use, etc.
58  *      - clean up documentation and whatnot
59  *      - does remove, mkdir, rmdir work?
60  *      - fill this with cpio stuff
61  *      - figure out how to use the page cache
62  */
63
64 /* this gives you some idea of how much I like linked lists. Just make
65  * a big old table. Later on we can put next and prev indices into the
66  * data if we want but, our current kfs is 1-3 levels deep and very small
67  * (< 200 entries) so I doubt we'll need to do that. It just makes debugging
68  * memory a tad easier.
69  */
70 /* Da Rules.
71  * The roottab contains [name, qid, length, perm]. Length means length for files.
72  * Qid is [path, vers, type]. Path is me. vers is next. Type is QTDIR for dir
73  * and QTFILE for file and 0 for empty.
74  * Data is [dotdot, ptr, size, *sizep, next]
75  * dotdot is .., ptr is data (for files)
76  * size is # elements (for dirs)
77  * *sizep is a pointer for reasons not understood.
78  * child is the qid.path of the first child of a directory.
79  * Possibly 0 == no child.
80  * To find the next sibling (in a directory), look at roottab[i].qid.vers.
81  *
82  *      int     dotdot;
83  *      int     child;
84  *      void    *ptr;
85  *      int     size;
86  *      int     *sizep;
87  *
88  * entry is empty if type is 0. We look in roottab to determine that.
89 */
90 /* we pack the qid as follows: path is the index, vers is ., and type is type */
91
92 /* Inferno seems to want to: perm |= DMDIR.  It gets checked in other places.
93  * NxM didn't want this, IIRC.
94  *
95  * Also note that "" (/, #root, whatever) has no vers/next/sibling.
96  *
97  * If you want to add new entries, add it to the roottab such that the linked
98  * list of indexes is a cycle (change the last current one), then add an entry
99  * to rootdata, and then change the first rootdata entry to have another entry.
100  * Yeah, it's a pain in the ass.
101  *
102  * To add subdirectories, or any child of a directory, the files (e.g. env_dir1)
103  * go in roottab.  Children of a parent are linked with their vers (note
104  * env_dir1 points to env_dir2), and the last item's vers = 0.  These files need
105  * their dotdot set in rootdata to the qid of their parent.  The directory that
106  * has children needs its child pointer set to the first qid in the list, and
107  * its data pointer must point to the roottab entry for the child.  This also
108  * means that all child entries in roottab for a parent must be contiguous.
109  *
110  * Yeah, it's a pain in the ass.  And, given this structure, it probably can't
111  * grow dynamically (I think we assume roottab[i] = entry for qid.path all over
112  * the place - imagine what happens if we wanted to squeeze in a new entry). */
113 struct dirtab roottab[MAXFILE] = {
114         {"", {0, 0, QTDIR}, 0, DMDIR | 0777},
115         {"chan", {1, 2, QTDIR}, 0, DMDIR | 0777},
116         {"dev", {2, 3, QTDIR}, 0, DMDIR | 0777},
117         {"fd", {3, 4, QTDIR}, 0, DMDIR | 0777},
118         {"prog", {4, 5, QTDIR}, 0, DMDIR | 0777},
119         {"prof", {5, 6, QTDIR}, 0, DMDIR | 0777},
120         {"net", {6, 7, QTDIR}, 0, DMDIR | 0777},
121         {"net.alt", {7, 8, QTDIR}, 0, DMDIR | 0777},
122         {"nvfs", {8, 9, QTDIR}, 0, DMDIR | 0777},
123         {"env", {9, 10, QTDIR}, 0, DMDIR | 0777},
124         {"root", {10, 11, QTDIR}, 0, DMDIR | 0777},
125         {"srv", {11, 12, QTDIR}, 0, DMDIR | 0777},
126         {"mnt", {12, 13, QTDIR}, 0, DMDIR | 0777},
127         {"proc", {13, 0, QTDIR}, 0, DMDIR | 0777},
128         {"env_dir1", {14, 15, QTDIR}, 0, DMDIR | 0777},
129         {"env_dir2", {15, 0, QTDIR}, 0, DMDIR | 0777},
130 };
131
132 struct rootdata {
133         int dotdot;
134         int child;
135         void *ptr;
136         int size;
137         int *sizep;
138 };
139
140 struct rootdata rootdata[MAXFILE] = {
141         {0,     1,       &roottab[1],    13,    NULL},
142         {0,     0,       NULL,   0,      NULL},
143         {0,     0,       NULL,   0,      NULL},
144         {0,     0,       NULL,   0,      NULL},
145         {0,     0,       NULL,   0,      NULL},
146         {0,     0,       NULL,   0,      NULL},
147         {0,     0,       NULL,   0,      NULL},
148         {0,     0,       NULL,   0,      NULL},
149         {0,     0,       NULL,   0,      NULL},
150         {0,     14,      &roottab[14],   2,      NULL},
151         {0,     0,       NULL,   0,      NULL},
152         {0,     0,       NULL,   0,      NULL},
153         {0,     0,       NULL,   0,      NULL},
154         {0,     0,       NULL,   0,      NULL},
155         {9,     0,       NULL,   0,      NULL},
156         {9,     0,       NULL,   0,      NULL},
157 };
158
159 /* this is super useful */
160 void dumprootdev(void)
161 {
162         struct dirtab *r = roottab;
163         struct rootdata *rd = rootdata;
164         int i;
165
166         printk("[       dirtab     ]      name: [pth, ver, typ],   len,        "
167                "perm,  .., chld,       data pointer,  size,       size pointer\n");
168         for (i = 0; i < rootmaxq; i++, r++, rd++) {
169                 if (i && (!r->name[0]))
170                         continue;
171                 printk("[%p]%10s: [%3d, %3d, %3d], %5d, %11o,",
172                            r,
173                            r->name, r->qid.path, r->qid.vers, r->qid.type,
174                            r->length, r->perm);
175                 printk(" %3d, %4d, %p, %5d, %p\n",
176                            rd->dotdot, rd->child, rd->ptr, rd->size, rd->sizep);
177         }
178 }
179
180 static int findempty(void)
181 {
182         int i;
183         for (i = 0; i < rootmaxq; i++) {
184                 if (!roottab[i].qid.type) {
185                         memset(&roottab[i], 0, sizeof(roottab[i]));
186                         return i;
187                 }
188         }
189         return -1;
190 }
191
192 static void freeempty(int i)
193 {
194         roottab[i].qid.type = 0;
195 }
196
197 static int newentry(int parent)
198 {
199         int n = findempty();
200         int sib;
201         if (n < 0)
202                 error(EFAIL, "#root. No more");
203         printd("new entry is %d\n", n);
204         /* add the new one to the head of the linked list.  vers is 'next' */
205         roottab[n].qid.vers = rootdata[parent].child;
206         rootdata[parent].child = n;
207         return n;
208 }
209
210 static int createentry(int dir, char *name, int omode, int perm)
211 {
212         int n = newentry(dir);
213         strncpy(roottab[n].name, name, sizeof(roottab[n].name));
214         roottab[n].length = 0;
215         roottab[n].perm = perm;
216         /* vers is already properly set. */
217         mkqid(&roottab[n].qid, n, roottab[n].qid.vers,
218               perm & DMDIR ? QTDIR : QTFILE);
219         rootdata[n].dotdot = roottab[dir].qid.path;
220         rootdata[dir].ptr = &roottab[n];
221         rootdata[n].size = 0;
222         rootdata[n].sizep = &rootdata[n].size;
223         return n;
224 }
225
226 static void rootinit(void)
227 {
228         /* brho: pretty sure this should only be run once.  putting it in attach
229          * will run it multiple times. */
230         int i;
231         uint32_t len;
232         struct rootdata *r;
233         /* this begins with the root. */
234         for (i = 0;; i++) {
235                 r = &rootdata[i];
236                 if (r->sizep) {
237                         len = *r->sizep;
238                         r->size = len;
239                         roottab[i].length = len;
240                 }
241                 i = roottab[i].qid.vers;
242                 if (!i)
243                         break;
244         }
245 }
246
247 static struct chan *rootattach(char *spec)
248 {
249         struct chan *c;
250         if (*spec)
251                 error(EINVAL, ERROR_FIXME);
252         c = devattach(devname(), spec);
253         mkqid(&c->qid, roottab[0].qid.path, roottab[0].qid.vers, QTDIR);
254         return c;
255 }
256
257 static int
258 rootgen(struct chan *c, char *name,
259                 struct dirtab *tab, int nd, int s, struct dir *dp)
260 {
261         int p, i;
262         struct rootdata *r;
263         int iter;
264         printd("rootgen, path is %d, tap %p, nd %d s %d name %s\n", c->qid.path,
265                tab, nd, s, name);
266
267         if (s == DEVDOTDOT) {
268                 p = rootdata[c->qid.path].dotdot;
269                 c->qid = roottab[p].qid;
270                 name = roottab[p].name;
271                 devdir(c, c->qid, name, 0, eve.name, 0777, dp);
272                 return 1;
273         }
274
275         if (c->qid.type != QTDIR) {
276                 /* return ourselved the first time; after that, -1 */
277                 if (s)
278                         return -1;
279                 tab = &roottab[c->qid.path];
280                 devdir(c, tab->qid, tab->name, tab->length, eve.name, tab->perm, dp);
281                 return 1;
282         }
283
284         if (name != NULL) {
285                 int path = c->qid.path;
286                 isdir(c);
287                 tab = &roottab[rootdata[path].child];
288                 /* we're starting at a directory. It might be '.' */
289                 for (iter = 0, i = rootdata[path].child; /* break */; iter++) {
290                         if (strncmp(tab->name, name, KNAMELEN) == 0) {
291                                 printd("Rootgen returns 1 for %s\n", name);
292                                 devdir(c, tab->qid, tab->name, tab->length, eve.name, tab->perm,
293                                        dp);
294                                 printd("return 1 with [%d, %d, %d]\n", dp->qid.path,
295                                        dp->qid.vers, dp->qid.type);
296                                 return 1;
297                         }
298                         if (iter > rootmaxq) {
299                                 printk("BUG:");
300                                 dumprootdev();
301                                 printk("name %s\n", name);
302                                 return -1;
303                         }
304                         i = roottab[i].qid.vers;
305                         if (!i)
306                                 break;
307                         tab = &roottab[i];
308                 }
309                 printd("rootgen: :%s: failed at path %d\n", name, path);
310                 return -1;
311         }
312         /* need to gen the file or the contents of the directory we are currently
313          * at.  but i think the tab entries are all over the place.  nd is how
314          * many entries the directory has. */
315         if (s >= nd) {
316                 printd("S OVERFLOW\n");
317                 return -1;
318         }
319         //tab += s;     /* this would only work if our entries were contig in the tab */
320         for (i = rootdata[c->qid.path].child; i; i = roottab[i].qid.vers) {
321                 tab = &roottab[i];
322                 if (s-- == 0)
323                         break;
324         }
325         if (!i) {
326                 printd("I OVERFLOW\n");
327                 return -1;
328         }
329         printd("root scan find returns path %p name %s\n", tab->qid.path, tab->name);
330         devdir(c, tab->qid, tab->name, tab->length, eve.name, tab->perm, dp);
331         return 1;
332 }
333
334 static struct walkqid *rootwalk(struct chan *c, struct chan *nc, char **name,
335                                                                 int nname)
336 {
337         uint32_t p;
338         if (0){
339                 printk("rootwalk: c %p. :", c);
340                 if (nname){
341                         int i;
342                         for (i = 0; i < nname - 1; i++)
343                                 printk("%s/", name[i]);
344                         printk("%s:\n", name[i]);
345                 }
346         }
347         p = c->qid.path;
348         printd("Start from #%d at %p\n", p, &roottab[p]);
349         return devwalk(c, nc, name, nname, &roottab[p], rootdata[p].size, rootgen);
350 }
351
352 static int rootstat(struct chan *c, uint8_t * dp, int n)
353 {
354         int p = c->qid.path;
355         return devstat(c, dp, n, rootdata[p].ptr, rootdata[p].size, rootgen);
356 }
357
358 static struct chan *rootopen(struct chan *c, int omode)
359 {
360         int p;
361         printd("rootopen: omode %o\n", omode);
362         p = c->qid.path;
363         return devopen(c, omode, rootdata[p].ptr, rootdata[p].size, rootgen);
364 }
365
366 static void rootcreate(struct chan *c, char *name, int omode, uint32_t perm)
367 {
368         struct dirtab *r = &roottab[c->qid.path], *newr;
369         struct rootdata *rd = &rootdata[c->qid.path];
370         /* need to filter openmode so that it gets only the access-type bits */
371         omode = openmode(omode);
372         c->mode = openmode(omode);
373         printd("rootcreate: c %p, name %s, omode %o, perm %x\n",
374                c, name, omode, perm);
375         /* find an empty slot */
376         int path = c->qid.path;
377         int newfile;
378         newfile = createentry(path, name, omode, perm);
379         c->qid = roottab[newfile].qid;  /* need to update c */
380         rd->size++;
381         if (newfile > rootmaxq)
382                 rootmaxq = newfile;
383         printd("create: %s, newfile %d, dotdot %d, rootmaxq %d\n", name, newfile,
384                rootdata[newfile].dotdot, rootmaxq);
385 }
386
387 /*
388  * sysremove() knows this is a nop
389  *              fyi, this isn't true anymore!  they need to set c->type = -1;
390  */
391 static void rootclose(struct chan *c)
392 {
393 }
394
395 static long rootread(struct chan *c, void *buf, long n, int64_t offset)
396 {
397         uint32_t p, len;
398         uint8_t *data;
399
400         p = c->qid.path;
401         if (c->qid.type & QTDIR) {
402                 return devdirread(c, buf, n, rootdata[p].ptr, rootdata[p].size,
403                                                   rootgen);
404         }
405         len = rootdata[p].size;
406         if (offset < 0 || offset >= len) {
407                 return 0;
408         }
409         if (offset + n > len)
410                 n = len - offset;
411         data = rootdata[p].ptr;
412         /* we can't really claim it has to be a user address. Lots of
413          * kernel things read directly, e.g. /dev/reboot, #nix, etc.
414          * Address validation should be done in the syscall layer.
415          */
416         memcpy(buf, data + offset, n);
417         return n;
418 }
419
420 /* For now, just kzmalloc the right amount. Later, we should use
421  * pages so mmap will go smoothly. Would be really nice to have a
422  * kpagemalloc ... barret?
423  *              we have kpage_alloc (gives a page) and kpage_alloc_addr (void*)
424  */
425 static long rootwrite(struct chan *c, void *a, long n, int64_t off)
426 {
427         struct rootdata *rd = &rootdata[c->qid.path];
428         struct dirtab *r = &roottab[c->qid.path];
429
430         if (off < 0)
431                 error(EFAIL, "rootwrite: offset < 0!");
432
433         if (off + n > rd->size){
434                 void *p;
435                 p = krealloc(rd->ptr, off + n, MEM_WAIT);
436                 if (! p)
437                         error(EFAIL, "rootwrite: could not grow the file to %d bytes",
438                                   off + n);
439                 rd->ptr = p;
440                 rd->size = off + n;
441         }
442         assert(current);
443         if (memcpy_from_user_errno(current, rd->ptr + off, a, n) < 0)
444                 error(EFAIL, "%s: bad user addr %p", __FUNCTION__, a);
445
446         return n;
447 }
448
449 static int rootwstat(struct chan *c, uint8_t *m_buf, int m_buf_sz)
450 {
451         struct dirtab *file = &roottab[c->qid.path];
452         struct dir *dir;
453         int m_sz;
454
455         /* TODO: some security check, Eperm on error */
456
457         /* common trick in wstats.  we want the dir and any strings in the M.  the
458          * strings are smaller than entire M (strings plus other M).  the strings
459          * will be placed right after the dir (dir[1]) */
460         dir = kzmalloc(sizeof(struct dir) + m_buf_sz, MEM_WAIT);
461         m_sz = convM2D(m_buf, m_buf_sz, &dir[0], (char*)&dir[1]);
462         if (!m_sz) {
463                 kfree(dir);
464                 error(ENODATA, ERROR_FIXME);
465         }
466         /* TODO: handle more things than just the mode */
467         if (!emptystr(dir->name))
468                 printk("[%s] attempted rename of %s to %s\n", __FUNCTION__,
469                        file->name, dir->name);  /* strncpy for this btw */
470         if (dir->mode != ~0UL)
471                 file->perm = dir->mode | (file->qid.type == QTDIR ? DMDIR : 0);
472         kfree(dir);
473         return m_sz;
474 }
475
476 struct dev rootdevtab __devtab = {
477         .name = "root",
478         .reset = devreset,
479         .init = rootinit,
480         .shutdown = devshutdown,
481         .attach = rootattach,
482         .walk = rootwalk,
483         .stat = rootstat,
484         .open = rootopen,
485         .create = rootcreate,
486         .close = rootclose,
487         .read = rootread,
488         .bread = devbread,
489         .write = rootwrite,
490         .bwrite = devbwrite,
491         .remove = devremove,
492         .wstat = rootwstat,
493         .power = devpower,
494         .chaninfo = devchaninfo,
495 };