Fixes large dirreads on 9ns
[akaros.git] / kern / src / ns / sysfile.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
16 enum {
17         DIRSIZE = STATFIXLEN + 32 * 4,
18         DIRREADLIM = 2048,      /* should handle the largest reasonable directory entry */
19         DIRREADSIZE=8192,       /* Just read a lot. Memory is cheap, lots of bandwidth,
20                                  * and RPCs are very expensive. At the same time,
21                                  * let's not yet exceed a common MSIZE. */
22
23 };
24
25 static int growfd(struct fgrp *f, int fd)
26 {
27         
28         int n;
29         struct chan **nfd, **ofd;
30
31         if (fd < f->nfd) {
32                 return 0;
33         }
34         n = f->nfd + DELTAFD;
35         if (n > MAXNFD)
36                 n = MAXNFD;
37         if (fd >= n) {
38                 return -1;
39         }
40         nfd = kzmalloc(n * sizeof(struct chan *), 0);
41         if (nfd == NULL) {
42                 return -1;
43         }
44         ofd = f->fd;
45         memmove(nfd, ofd, f->nfd * sizeof(struct chan *));
46         f->fd = nfd;
47         f->nfd = n;
48         kfree(ofd);
49         return 0;
50 }
51
52 int newfd(struct chan *c)
53 {
54         
55         int i;
56         struct fgrp *f = current->fgrp;
57
58         spin_lock(&f->lock);
59         if (f->closed) {
60                 spin_unlock(&f->lock);
61                 return -1;
62         }
63         /* VFS hack */
64         /* We'd like to ask it to start at f->minfd, but that would require us to
65          * know if we closed anything.  Since we share the FD numbers with the VFS,
66          * there is no way to know that. */
67         i = get_fd(&current->open_files, 0);
68         while (i >= f->nfd) {
69                 if (growfd(f, i) < 0) {
70                         spin_unlock(&f->lock);
71                         exhausted("file descriptors");
72                         return -1;
73                 }
74                 cpu_relax();
75         }
76         assert(f->fd[i] == 0);
77 #if 0   // 9ns style
78         /* TODO: use a unique integer allocator */
79         for (i = f->minfd; i < f->nfd; i++)
80                 if (f->fd[i] == 0)
81                         break;
82         if (i >= f->nfd && growfd(f, i) < 0) {
83                 spin_unlock(&f->lock);
84                 exhausted("file descriptors");
85                 return -1;
86         }
87 #endif
88         f->minfd = i + 1;
89         if (i > f->maxfd)
90                 f->maxfd = i;
91         f->fd[i] = c;
92         spin_unlock(&f->lock);
93         return i;
94 }
95
96 struct chan *fdtochan(struct fgrp *f, int fd, int mode, int chkmnt, int iref)
97 {
98         
99         struct chan *c;
100
101         c = 0;
102
103         spin_lock(&f->lock);
104         if (f->closed) {
105                 spin_unlock(&f->lock);
106                 error("File group closed");
107         }
108         if (fd < 0 || f->maxfd < fd || (c = f->fd[fd]) == 0) {
109                 spin_unlock(&f->lock);
110                 error(Ebadfd);
111         }
112         if (iref)
113                 chan_incref(c);
114         spin_unlock(&f->lock);
115
116         if (chkmnt && (c->flag & CMSG)) {
117                 if (iref)
118                         cclose(c);
119                 error(Ebadusefd);
120         }
121
122         if (mode < 0 || c->mode == ORDWR) {
123                 return c;
124         }
125
126         if ((mode & OTRUNC) && IS_RDONLY(c->mode)) {
127                 if (iref)
128                         cclose(c);
129                 error(Ebadusefd);
130         }
131
132         /* TODO: this is probably wrong.  if you get this from a dev, in the dev's
133          * open, you are probably saving mode directly, without passing it through
134          * openmode. */
135         if ((mode & ~OTRUNC) != c->mode) {
136                 warn("Trunc mode issue: mode %o, mode minus trunc %o, chan mode %o\n",
137                          mode, mode & ~OTRUNC, c->mode);
138                 if (iref)
139                         cclose(c);
140                 error(Ebadusefd);
141         }
142
143         return c;
144 }
145
146 long kchanio(void *vc, void *buf, int n, int mode)
147 {
148         ERRSTACK(1);
149         int r;
150         struct chan *c;
151
152         c = vc;
153         if (waserror()) {
154                 poperror();
155                 return -1;
156         }
157
158         if (IS_RDONLY(mode))
159                 r = devtab[c->type].read(c, buf, n, c->offset);
160         else
161                 r = devtab[c->type].write(c, buf, n, c->offset);
162
163         spin_lock(&c->lock);
164         c->offset += r;
165         spin_unlock(&c->lock);
166         poperror();
167         return r;
168 }
169
170 int openmode(uint32_t omode)
171 {
172 /* GIANT WARNING: if this ever throws, ipopen (and probably many others) will
173  * screw up refcnts of Qctl, err, data, etc */
174 #if 0
175         /* this is the old plan9 style.  i think they want to turn exec into read,
176          * and strip off anything higher, and just return the RD/WR style bits.  not
177          * stuff like ORCLOSE.  the lack of OEXCL might be a bug on their part (it's
178          * the only one of their non-RW-related flags that isn't masked out) */
179         if (o >= (OTRUNC | OCEXEC | ORCLOSE | OEXEC))
180                 error(Ebadarg);
181         o &= ~(OTRUNC | OCEXEC | ORCLOSE);
182         if (o > OEXEC)
183                 error(Ebadarg);
184         if (o == OEXEC)
185                 return OREAD;
186         return o;
187 #endif
188         /* no error checking (we have a shitload of flags anyway), and we return the
189          * basic access modes (RD/WR/ETC) */
190         if (omode == O_EXEC) {
191         return O_RDONLY;
192         }
193         return omode & O_ACCMODE;
194 }
195
196 void fdclose(struct fgrp *f, int fd)
197 {
198         
199         int i;
200         struct chan *c;
201
202         spin_lock(&f->lock);
203         if (f->closed) {
204                 spin_unlock(&f->lock);
205                 return;
206         }
207         c = f->fd[fd];
208         if (c == 0) {
209                 /* can happen for users with shared fd tables */
210                 spin_unlock(&f->lock);
211                 return;
212         }
213         f->fd[fd] = 0;
214         if (fd == f->maxfd)
215                 for (i = fd; --i >= 0 && f->fd[i] == 0;)
216                         f->maxfd = i;
217         if (fd < f->minfd)
218                 f->minfd = fd;
219         /* VFS hack: give the FD back to VFS */
220         put_fd(&current->open_files, fd);
221         spin_unlock(&f->lock);
222         cclose(c);
223 }
224
225 int syschdir(char *path)
226 {
227         ERRSTACK(1);
228         struct chan *c;
229         struct pgrp *pg;
230
231         if (waserror()) {
232                 poperror();
233                 return -1;
234         }
235
236         c = namec(path, Atodir, 0, 0);
237         pg = current->pgrp;
238         cclose(pg->dot);
239         pg->dot = c;
240         poperror();
241         return 0;
242 }
243
244 int fgrpclose(struct fgrp *f, int fd)
245 {
246         ERRSTACK(1);
247         if (waserror()) {
248                 poperror();
249                 return -1;
250         }
251
252         /*
253          * Take no reference on the chan because we don't really need the
254          * data structure, and are calling fdtochan only for error checks.
255          * fdclose takes care of processes racing through here.
256          */
257         fdtochan(f, fd, -1, 0, 0);
258         fdclose(f, fd);
259         poperror();
260         return 0;
261 }
262
263 int sysclose(int fd)
264 {
265         return fgrpclose(current->fgrp, fd);
266 }
267
268 int syscreate(char *path, int mode, uint32_t perm)
269 {
270         ERRSTACK(2);
271         int fd;
272         struct chan *c;
273
274         if (waserror()) {
275                 poperror();
276                 return -1;
277         }
278
279         openmode(mode & ~OEXCL);        /* error check only; OEXCL okay here */
280         c = namec(path, Acreate, mode, perm);
281         if (waserror()) {
282                 cclose(c);
283                 nexterror();
284         }
285         fd = newfd(c);
286         if (fd < 0)
287                 error(Enofd);
288         poperror();
289
290         poperror();
291         return fd;
292 }
293
294 int sysdup(int old, int new)
295 {
296         ERRSTACK(2);
297         int fd;
298         struct chan *c, *oc;
299         struct fgrp *f = current->fgrp;
300
301         if (waserror()) {
302                 poperror();
303                 return -1;
304         }
305
306         c = fdtochan(current->fgrp, old, -1, 0, 1);
307         if (c->qid.type & QTAUTH) {
308                 cclose(c);
309                 error(Eperm);
310         }
311         fd = new;
312         if (fd != -1) {
313                 /* ideally we'll be done with the VFS before we fix this */
314                 /* double check the ccloses when you fix this */
315                 panic("Need to sync with the VFS");
316                 spin_lock(&f->lock);
317                 if (f->closed) {
318                         spin_unlock(&f->lock);
319                         cclose(c);
320                         return -1;
321                 }
322                 if (fd < 0 || growfd(f, fd) < 0) {
323                         spin_unlock(&f->lock);
324                         cclose(c);
325                         error(Ebadfd);
326                 }
327                 if (fd > f->maxfd)
328                         f->maxfd = fd;
329                 oc = f->fd[fd];
330                 f->fd[fd] = c;
331                 spin_unlock(&f->lock);
332                 if (oc)
333                         cclose(oc);
334         } else {
335                 if (waserror()) {
336                         cclose(c);
337                         nexterror();
338                 }
339                 fd = newfd(c);
340                 if (fd < 0)
341                         error(Enofd);
342                 poperror();
343         }
344         poperror();
345         return fd;
346 }
347
348 char *sysfd2path(int fd)
349 {
350         ERRSTACK(1);
351         struct chan *c;
352         char *s;
353
354         if (waserror()) {
355                 poperror();
356                 return NULL;
357         }
358         c = fdtochan(current->fgrp, fd, -1, 0, 1);
359         s = NULL;
360         if (c->name != NULL) {
361                 s = kzmalloc(c->name->len + 1, 0);
362                 if (s == NULL) {
363                         cclose(c);
364                         error(Enomem);
365                 }
366                 memmove(s, c->name->s, c->name->len + 1);
367         }
368         cclose(c);
369         poperror();
370         return s;
371 }
372
373 int sysfauth(int fd, char *aname)
374 {
375         ERRSTACK(2);
376         struct chan *c, *ac;
377
378         if (waserror()) {
379                 poperror();
380                 return -1;
381         }
382
383         validname(aname, 0);
384         c = fdtochan(current->fgrp, fd, ORDWR, 0, 1);
385         if (waserror()) {
386                 cclose(c);
387                 nexterror();
388         }
389
390         ac = mntauth(c, aname);
391
392         /* at this point ac is responsible for keeping c alive */
393         poperror();     /* c */
394         cclose(c);
395
396         if (waserror()) {
397                 cclose(ac);
398                 nexterror();
399         }
400
401         fd = newfd(ac);
402         if (fd < 0)
403                 error(Enofd);
404         poperror();     /* ac */
405
406         poperror();
407
408         return fd;
409 }
410
411 int sysfversion(int fd, unsigned int msize, char *vers, unsigned int arglen)
412 {
413         ERRSTACK(2);
414         int m;
415         struct chan *c;
416
417         if (waserror()) {
418                 poperror();
419                 return -1;
420         }
421
422         /* check there's a NUL in the version string */
423         if (arglen == 0 || memchr(vers, 0, arglen) == 0)
424                 error(Ebadarg);
425
426         c = fdtochan(current->fgrp, fd, ORDWR, 0, 1);
427         if (waserror()) {
428                 cclose(c);
429                 nexterror();
430         }
431
432         m = mntversion(c, vers, msize, arglen);
433
434         poperror();
435         cclose(c);
436
437         poperror();
438         return m;
439 }
440
441 int syspipe(int fd[2])
442 {
443         ERRSTACK(1);
444         struct dev *d;
445         struct fgrp *f;
446         struct chan *c[2];
447         static char *names[] = { "data", "data1" };
448
449         f = current->fgrp;
450
451         d = &devtab[devno('|', 0)];
452         c[0] = namec("#|", Atodir, 0, 0);
453         c[1] = 0;
454         fd[0] = -1;
455         fd[1] = -1;
456         if (waserror()) {
457                 if (c[0] != 0)
458                         cclose(c[0]);
459                 if (c[1] != 0)
460                         cclose(c[1]);
461                 if (fd[0] >= 0) {
462                         /* VFS hack */
463                         f->fd[fd[0]] = 0;
464                         put_fd(&current->open_files, fd[0]);
465                 }
466                 if (fd[1] >= 0) {
467                         /* VFS hack */
468                         f->fd[fd[1]] = 0;
469                         put_fd(&current->open_files, fd[1]);
470                 }
471                 poperror();
472                 return -1;
473         }
474         c[1] = cclone(c[0]);
475         if (walk(&c[0], &names[0], 1, 1, NULL) < 0)
476                 error(Egreg);
477         if (walk(&c[1], &names[1], 1, 1, NULL) < 0)
478                 error(Egreg);
479         c[0] = d->open(c[0], ORDWR);
480         c[1] = d->open(c[1], ORDWR);
481         fd[0] = newfd(c[0]);
482         if (fd[0] < 0)
483                 error(Enofd);
484         fd[1] = newfd(c[1]);
485         if (fd[1] < 0)
486                 error(Enofd);
487         poperror();
488         return 0;
489 }
490
491 int sysfwstat(int fd, uint8_t * buf, int n)
492 {
493         ERRSTACK(2);
494         struct chan *c;
495
496         if (waserror()) {
497                 poperror();
498                 return -1;
499         }
500
501         validstat(buf, n);
502         c = fdtochan(current->fgrp, fd, -1, 1, 1);
503         if (waserror()) {
504                 cclose(c);
505                 nexterror();
506         }
507         n = devtab[c->type].wstat(c, buf, n);
508         poperror();
509         cclose(c);
510
511         poperror();
512         return n;
513 }
514
515 long bindmount(struct chan *c, char *old, int flag, char *spec)
516 {
517         ERRSTACK(1);
518         int ret;
519         struct chan *c1;
520
521         if (flag > MMASK || (flag & MORDER) == (MBEFORE | MAFTER))
522                 error(Ebadarg);
523
524         c1 = namec(old, Amount, 0, 0);
525         if (waserror()) {
526                 cclose(c1);
527                 nexterror();
528         }
529         ret = cmount(c, c1, flag, spec);
530
531         poperror();
532         cclose(c1);
533         return ret;
534 }
535
536 int sysbind(char *new, char *old, int flags)
537 {
538         ERRSTACK(2);
539         long r;
540         struct chan *c0;
541
542         if (waserror()) {
543                 poperror();
544                 return -1;
545         }
546
547         c0 = namec(new, Abind, 0, 0);
548         if (waserror()) {
549                 cclose(c0);
550                 nexterror();
551         }
552         r = bindmount(c0, old, flags, "");
553         poperror();
554         cclose(c0);
555
556         poperror();
557         return r;
558 }
559
560 int sysmount(int fd, int afd, char *old, int flags, char *spec)
561 {
562         ERRSTACK(1);
563         long r;
564         volatile struct {
565                 struct chan *c;
566         } c0;
567         volatile struct {
568                 struct chan *c;
569         } bc;
570         volatile struct {
571                 struct chan *c;
572         } ac;
573         struct mntparam mntparam;
574
575         ac.c = NULL;
576         bc.c = NULL;
577         c0.c = NULL;
578         if (waserror()) {
579                 cclose(ac.c);
580                 cclose(bc.c);
581                 cclose(c0.c);
582                 poperror();
583                 return -1;
584         }
585         bc.c = fdtochan(current->fgrp, fd, ORDWR, 0, 1);
586         if (afd >= 0)
587                 ac.c = fdtochan(current->fgrp, afd, ORDWR, 0, 1);
588         mntparam.chan = bc.c;
589         mntparam.authchan = ac.c;
590         mntparam.spec = spec;
591         mntparam.flags = flags;
592         c0.c = devtab[devno('M', 0)].attach((char *)&mntparam);
593
594         r = bindmount(c0.c, old, flags, spec);
595         poperror();
596         cclose(ac.c);
597         cclose(bc.c);
598         cclose(c0.c);
599
600         return r;
601 }
602
603 int sysunmount(char *old, char *new)
604 {
605         ERRSTACK(1);
606         volatile struct {
607                 struct chan *c;
608         } cmount;
609         volatile struct {
610                 struct chan *c;
611         } cmounted;
612
613         cmount.c = NULL;
614         cmounted.c = NULL;
615         if (waserror()) {
616                 cclose(cmount.c);
617                 cclose(cmounted.c);
618                 poperror();
619                 return -1;
620         }
621
622         cmount.c = namec(new, Amount, 0, 0);
623         if (old != NULL && old[0] != '\0') {
624                 /*
625                  * This has to be namec(..., Aopen, ...) because
626                  * if arg[0] is something like /srv/cs or /fd/0,
627                  * opening it is the only way to get at the real
628                  * Chan underneath.
629                  */
630                 cmounted.c = namec(old, Aopen, OREAD, 0);
631         }
632
633         cunmount(cmount.c, cmounted.c);
634         poperror();
635         cclose(cmount.c);
636         cclose(cmounted.c);
637         return 0;
638 }
639
640 int sysopen(char *path, int vfs_flags)
641 {
642         ERRSTACK(2);
643         int fd;
644         struct chan *c;
645
646         if (waserror()) {
647                 poperror();
648                 return -1;
649         }
650
651         openmode(vfs_flags);    /* error check only */
652         c = namec(path, Aopen, vfs_flags, 0);
653         if (waserror()) {
654                 cclose(c);
655                 nexterror();
656         }
657         fd = newfd(c);
658         if (fd < 0)
659                 error(Enofd);
660         poperror();
661
662         poperror();
663         return fd;
664 }
665
666 long unionread(struct chan *c, void *va, long n)
667 {
668         ERRSTACK(1);
669         int i;
670         long nr;
671         struct mhead *m;
672         struct mount *mount;
673
674         qlock(&c->umqlock);
675         m = c->umh;
676         rlock(&m->lock);
677         mount = m->mount;
678         /* bring mount in sync with c->uri and c->umc */
679         for (i = 0; mount != NULL && i < c->uri; i++)
680                 mount = mount->next;
681
682         nr = 0;
683         while (mount != NULL) {
684                 /* Error causes component of union to be skipped */
685                 if (mount->to) {
686                         /* normally we want to discard the error, but for our ghetto kdirent
687                          * hack, we need to repeat unionread if we saw a Eshort */
688                         if (waserror()) {
689                                 if (!strcmp(current_errstr(), Eshort)) {
690                                         runlock(&m->lock);
691                                         qunlock(&c->umqlock);
692                                         nexterror();
693                                 }
694                                 /* poperror done below for either branch */
695                         } else {
696                                 if (c->umc == NULL) {
697                                         c->umc = cclone(mount->to);
698                                         c->umc = devtab[c->umc->type].open(c->umc, OREAD);
699                                 }
700
701                                 nr = devtab[c->umc->type].read(c->umc, va, n, c->umc->offset);
702                                 if (nr < 0)
703                                         nr = 0; /* dev.c can return -1 */
704                                 c->umc->offset += nr;
705                         }
706                         poperror();     /* pop regardless */
707                 }
708                 if (nr > 0)
709                         break;
710
711                 /* Advance to next element */
712                 c->uri++;
713                 if (c->umc) {
714                         cclose(c->umc);
715                         c->umc = NULL;
716                 }
717                 mount = mount->next;
718         }
719         runlock(&m->lock);
720         qunlock(&c->umqlock);
721         return nr;
722 }
723
724 static void unionrewind(struct chan *c)
725 {
726         qlock(&c->umqlock);
727         c->uri = 0;
728         if (c->umc) {
729                 cclose(c->umc);
730                 c->umc = NULL;
731         }
732         qunlock(&c->umqlock);
733 }
734
735 static long rread(int fd, void *va, long n, int64_t * offp)
736 {
737         ERRSTACK(3);
738         int dir;
739         struct chan *c;
740         int64_t off;
741
742         /* dirty dirent hack */
743         void *real_va = va;
744
745         if (waserror()) {
746                 poperror();
747                 return -1;
748         }
749
750         c = fdtochan(current->fgrp, fd, OREAD, 1, 1);
751         if (waserror()) {
752                 cclose(c);
753                 nexterror();
754         }
755
756         if (n < 0)
757                 error(Etoosmall);
758
759         dir = c->qid.type & QTDIR;
760
761         /* kdirent hack: userspace is expecting kdirents, but all of 9ns
762          * produces Ms.  Just save up what we don't use and append the
763          * new stuff later. Allocate DIRREADSIZE bytes for that purpose.
764          */
765         if (dir) {
766                 int amt;
767                 /* expecting only one dirent at a time, o/w we're busted */
768                 assert(n >= sizeof(struct kdirent));
769                 if (!c->buf) {
770                         c->buf=kmalloc(DIRREADSIZE, KMALLOC_WAIT);
771                         c->bufused = 0;
772                 }
773                 /* Attempt to extract an M, in case there was some already */
774                 amt = convM2kdirent(c->buf, c->bufused, real_va, 0);
775                 if (amt) {
776                         c->bufused -= amt;
777                         memmove(c->buf, c->buf + amt, c->bufused);
778                         n = sizeof(struct kdirent);
779                         goto out;
780                 }
781                 /* debugging */
782                 if (waserror()) {
783                         printk("Well, sysread of a dir sucks.%s \n", current_errstr());
784                         nexterror();
785                 }
786                 va = c->buf + c->bufused;
787                 n = DIRREADSIZE - c->bufused;
788         }
789
790         /* this is the normal plan9 read */
791         if (dir && c->umh)
792                 n = unionread(c, va, n);
793         else {
794                 if (offp == NULL) {
795                         spin_lock(&c->lock);    /* lock for int64_t assignment */
796                         off = c->offset;
797                         spin_unlock(&c->lock);
798                 } else
799                         off = *offp;
800                 if (off < 0)
801                         error(Enegoff);
802                 if (off == 0) {
803                         if (offp == NULL) {
804                                 spin_lock(&c->lock);
805                                 c->offset = 0;
806                                 c->dri = 0;
807                                 spin_unlock(&c->lock);
808                         }
809                         unionrewind(c);
810                 }
811                 if (! c->ateof) {
812                         n = devtab[c->type].read(c, va, n, off);
813                         if (n == 0 && dir)
814                                 c->ateof = 1;
815                 } else {
816                         n = 0;
817                 }
818                 spin_lock(&c->lock);
819                 c->offset += n;
820                 spin_unlock(&c->lock);
821         }
822
823         /* dirty kdirent hack */
824         if (dir) {
825                 int amt;
826                 c->bufused = c->bufused + n;
827                 /* extract an M from the front, then shift the remainder back */
828                 amt = convM2kdirent(c->buf, c->bufused, real_va, 0);
829                 c->bufused -= amt;
830                 memmove(c->buf, c->buf + amt, c->bufused);
831                 n = amt ? sizeof(struct kdirent) : 0;
832                 poperror();     /* matching our debugging waserror */
833         }
834
835 out:
836         poperror();
837         cclose(c);
838
839         poperror();
840         return n;
841 }
842
843 long sysread(int fd, void *va, long n)
844 {
845         return rread(fd, va, n, NULL);
846 }
847
848 long syspread(int fd, void *va, long n, int64_t off)
849 {
850         return rread(fd, va, n, &off);
851 }
852
853 int sysremove(char *path)
854 {
855         ERRSTACK(2);
856         struct chan *c;
857
858         if (waserror()) {
859                 poperror();
860                 return -1;
861         }
862
863         c = namec(path, Aremove, 0, 0);
864         if (waserror()) {
865                 c->type = -1;   /* see below */
866                 cclose(c);
867                 nexterror();
868         }
869         devtab[c->type].remove(c);
870         /*
871          * Remove clunks the fid, but we need to recover the Chan
872          * so fake it up.  -1 aborts the dev's close.
873          */
874         c->type = -1;
875         poperror();
876         cclose(c);
877
878         poperror();
879         return 0;
880 }
881
882 int64_t sysseek(int fd, int64_t off, int whence)
883 {
884         ERRSTACK(2);
885         struct dir *dir;
886         struct chan *c;
887
888         if (waserror()) {
889                 poperror();
890                 return -1;
891         }
892
893         c = fdtochan(current->fgrp, fd, -1, 1, 1);
894         if (waserror()) {
895                 cclose(c);
896                 nexterror();
897         }
898
899         if (devtab[c->type].dc == '|')
900                 error(Eisstream);
901
902         switch (whence) {
903                 case 0:
904                         if (c->qid.type & QTDIR) {
905                                 if (off != 0)
906                                         error(Eisdir);
907                                 unionrewind(c);
908                         } else if (off < 0)
909                                 error(Enegoff);
910                         spin_lock(&c->lock);    /* lock for int64_t assignment */
911                         c->offset = off;
912                         spin_unlock(&c->lock);
913                         break;
914
915                 case 1:
916                         if (c->qid.type & QTDIR)
917                                 error(Eisdir);
918                         spin_lock(&c->lock);    /* lock for read/write update */
919                         off += c->offset;
920                         if (off < 0) {
921                                 spin_unlock(&c->lock);
922                                 error(Enegoff);
923                         }
924                         c->offset = off;
925                         spin_unlock(&c->lock);
926                         break;
927
928                 case 2:
929                         if (c->qid.type & QTDIR)
930                                 error(Eisdir);
931                         dir = chandirstat(c);
932                         if (dir == NULL)
933                                 error("internal error: stat error in seek");
934                         off += dir->length;
935                         kfree(dir);
936                         if (off < 0)
937                                 error(Enegoff);
938                         spin_lock(&c->lock);    /* lock for read/write update */
939                         c->offset = off;
940                         spin_unlock(&c->lock);
941                         break;
942
943                 default:
944                         error(Ebadarg);
945                         break;
946         }
947         poperror();
948         c->dri = 0;
949         cclose(c);
950         poperror();
951         return off;
952 }
953
954 void validstat(uint8_t * s, int n)
955 {
956         
957         int m;
958         char buf[64];
959
960         if (statcheck(s, n) < 0)
961                 error(Ebadstat);
962         /* verify that name entry is acceptable */
963         s += STATFIXLEN - 4 * BIT16SZ;  /* location of first string */
964         /*
965          * s now points at count for first string.
966          * if it's too long, let the server decide; this is
967          * only for his protection anyway. otherwise
968          * we'd have to allocate and waserror.
969          */
970         m = GBIT16(s);
971         s += BIT16SZ;
972         if (m + 1 > sizeof buf) {
973                 return;
974         }
975         memmove(buf, s, m);
976         buf[m] = '\0';
977         /* name could be '/' */
978         if (strcmp(buf, "/") != 0)
979                 validname(buf, 0);
980 }
981
982 int sysfstat(int fd, uint8_t *buf, int n)
983 {
984         ERRSTACK(2);
985         struct chan *c;
986
987         if (waserror()) {
988                 poperror();
989                 return -1;
990         }
991
992         c = fdtochan(current->fgrp, fd, -1, 0, 1);
993         if (waserror()) {
994                 cclose(c);
995                 nexterror();
996         }
997         devtab[c->type].stat(c, buf, n);
998
999         poperror();
1000         cclose(c);
1001
1002         poperror();
1003         return n;
1004 }
1005
1006 int sysfstatakaros(int fd, struct kstat *ks)
1007 {
1008         
1009         int n = 4096;
1010         uint8_t *buf;
1011         buf = kmalloc(n, KMALLOC_WAIT);
1012         n = sysfstat(fd, buf, n);
1013         if (n > 0) {
1014                 convM2kstat(buf, n, ks);
1015                 n = 0;
1016         }
1017         kfree(buf);
1018         return n;
1019 }
1020
1021 int sysstat(char *path, uint8_t *buf, int n)
1022 {
1023         ERRSTACK(2);
1024         struct chan *c;
1025
1026         if (waserror()) {
1027                 poperror();
1028                 return -1;
1029         }
1030
1031         c = namec(path, Aaccess, 0, 0);
1032         if (waserror()) {
1033                 cclose(c);
1034                 nexterror();
1035         }
1036         devtab[c->type].stat(c, buf, n);
1037         poperror();
1038         cclose(c);
1039
1040         poperror();
1041
1042         return n;
1043 }
1044
1045 int sysstatakaros(char *path, struct kstat *ks)
1046 {
1047         
1048         int n = 4096;
1049         uint8_t *buf;
1050         buf = kmalloc(n, KMALLOC_WAIT);
1051         n = sysstat(path, buf, n);
1052         if (n > 0) {
1053                 convM2kstat(buf, n, ks);
1054                 n = 0;
1055         }
1056         kfree(buf);
1057         return n;
1058 }
1059
1060 static long rwrite(int fd, void *va, long n, int64_t * offp)
1061 {
1062         ERRSTACK(3);
1063         struct chan *c;
1064         struct dir *dir;
1065         int64_t off;
1066         long m;
1067
1068         if (waserror()) {
1069                 poperror();
1070                 return -1;
1071         }
1072         c = fdtochan(current->fgrp, fd, OWRITE, 1, 1);
1073         if (waserror()) {
1074                 cclose(c);
1075                 nexterror();
1076         }
1077         if (c->qid.type & QTDIR)
1078                 error(Eisdir);
1079
1080         if (n < 0)
1081                 error(Etoosmall);
1082
1083         if (offp == NULL) {
1084                 /* append changes the offset to the end, and even if we fail later, this
1085                  * change will persist */
1086                 if (c->flag & CAPPEND) {
1087                         dir = chandirstat(c);
1088                         if (!dir)
1089                                 error("internal error: stat error in append write");
1090                         spin_lock(&c->lock);    /* legacy lock for int64 assignment */
1091                         c->offset = dir->length;
1092                         spin_unlock(&c->lock);
1093                         kfree(dir);
1094                 }
1095                 spin_lock(&c->lock);
1096                 off = c->offset;
1097                 c->offset += n;
1098                 spin_unlock(&c->lock);
1099         } else
1100                 off = *offp;
1101
1102         if (waserror()) {
1103                 if (offp == NULL) {
1104                         spin_lock(&c->lock);
1105                         c->offset -= n;
1106                         spin_unlock(&c->lock);
1107                 }
1108                 nexterror();
1109         }
1110         if (off < 0)
1111                 error(Enegoff);
1112         m = devtab[c->type].write(c, va, n, off);
1113         poperror();
1114
1115         if (offp == NULL && m < n) {
1116                 spin_lock(&c->lock);
1117                 c->offset -= n - m;
1118                 spin_unlock(&c->lock);
1119         }
1120
1121         poperror();
1122         cclose(c);
1123
1124         poperror();
1125         return n;
1126 }
1127
1128 long syswrite(int fd, void *va, long n)
1129 {
1130         return rwrite(fd, va, n, NULL);
1131 }
1132
1133 long syspwrite(int fd, void *va, long n, int64_t off)
1134 {
1135         return rwrite(fd, va, n, &off);
1136 }
1137
1138 int syswstat(char *path, uint8_t * buf, int n)
1139 {
1140         ERRSTACK(2);
1141         struct chan *c;
1142
1143         if (waserror()) {
1144                 poperror();
1145                 return -1;
1146         }
1147
1148         validstat(buf, n);
1149         c = namec(path, Aaccess, 0, 0);
1150         if (waserror()) {
1151                 cclose(c);
1152                 nexterror();
1153         }
1154         n = devtab[c->type].wstat(c, buf, n);
1155         poperror();
1156         cclose(c);
1157
1158         poperror();
1159         return n;
1160 }
1161
1162 struct dir *chandirstat(struct chan *c)
1163 {
1164         ERRSTACK(1);
1165         struct dir *d;
1166         uint8_t *buf;
1167         int n, nd, i;
1168
1169         nd = DIRSIZE;
1170         for (i = 0; i < 2; i++) {       /* should work by the second try */
1171                 d = kzmalloc(sizeof(struct dir) + nd, 0);
1172                 buf = (uint8_t *) & d[1];
1173                 if (waserror()) {
1174                         kfree(d);
1175                         poperror();
1176                         return NULL;
1177                 }
1178                 n = devtab[c->type].stat(c, buf, nd);
1179                 poperror();
1180                 if (n < BIT16SZ) {
1181                         kfree(d);
1182                         return NULL;
1183                 }
1184                 nd = GBIT16((uint8_t *) buf) + BIT16SZ; /* size needed to store whole stat buffer including count */
1185                 if (nd <= n) {
1186                         convM2D(buf, n, d, (char *)&d[1]);
1187                         return d;
1188                 }
1189                 /* else sizeof(Dir)+nd is plenty */
1190                 kfree(d);
1191         }
1192         return NULL;
1193
1194 }
1195
1196 struct dir *sysdirstat(char *name)
1197 {
1198         ERRSTACK(2);
1199         struct chan *c;
1200         struct dir *d;
1201
1202         if (waserror()) {
1203                 poperror();
1204                 return NULL;
1205         }
1206
1207         c = namec(name, Aaccess, 0, 0);
1208         if (waserror()) {
1209                 cclose(c);
1210                 nexterror();
1211         }
1212         d = chandirstat(c);
1213         poperror();
1214         cclose(c);
1215
1216         poperror();
1217         return d;
1218 }
1219
1220 struct dir *sysdirfstat(int fd)
1221 {
1222         ERRSTACK(2);
1223         struct chan *c;
1224         struct dir *d;
1225
1226         if (waserror()) {
1227                 poperror();
1228                 return NULL;
1229         }
1230
1231         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1232         if (waserror()) {
1233                 cclose(c);
1234                 nexterror();
1235         }
1236         d = chandirstat(c);
1237         poperror();
1238         cclose(c);
1239
1240         poperror();
1241         return d;
1242 }
1243
1244 int sysdirwstat(char *name, struct dir *dir)
1245 {
1246         
1247         uint8_t *buf;
1248         int r;
1249
1250         r = sizeD2M(dir);
1251         buf = kzmalloc(r, 0);
1252         convD2M(dir, buf, r);
1253         r = syswstat(name, buf, r);
1254         kfree(buf);
1255         return r < 0 ? r : 0;
1256 }
1257
1258 int sysdirfwstat(int fd, struct dir *dir)
1259 {
1260         
1261         uint8_t *buf;
1262         int r;
1263
1264         r = sizeD2M(dir);
1265         buf = kzmalloc(r, 0);
1266         convD2M(dir, buf, r);
1267         r = sysfwstat(fd, buf, r);
1268         kfree(buf);
1269         return r < 0 ? r : 0;
1270 }
1271
1272 static long dirpackage(uint8_t * buf, long ts, struct kdirent **d)
1273 {
1274         
1275         char *s;
1276         long ss, i, n, nn, m = 0;
1277
1278         *d = NULL;
1279         if (ts <= 0) {
1280                 return ts;
1281         }
1282
1283         /*
1284          * first find number of all stats, check they look like stats, & size all associated strings
1285          */
1286         ss = 0;
1287         n = 0;
1288         for (i = 0; i < ts; i += m) {
1289                 m = BIT16SZ + GBIT16(&buf[i]);
1290                 if (statcheck(&buf[i], m) < 0)
1291                         break;
1292                 ss += m;
1293                 n++;
1294         }
1295
1296         if (i != ts)
1297                 error("bad directory format");
1298
1299         *d = kzmalloc(n * sizeof(**d) + ss, 0);
1300         if (*d == NULL)
1301                 error(Enomem);
1302
1303         /*
1304          * then convert all buffers
1305          */
1306         s = (char *)*d + n * sizeof(**d);
1307         nn = 0;
1308         for (i = 0; i < ts; i += m) {
1309                 m = BIT16SZ + GBIT16((uint8_t *) & buf[i]);
1310                 if (nn >= n || /*convM2D */ convM2kdirent(&buf[i], m, *d + nn, s) != m) {
1311                         kfree(*d);
1312                         *d = NULL;
1313                         error("bad directory entry");
1314                 }
1315                 nn++;
1316                 s += m;
1317         }
1318
1319         return nn;
1320 }
1321
1322 long sysdirread(int fd, struct kdirent **d)
1323 {
1324         ERRSTACK(2);
1325         uint8_t *buf;
1326         long ts;
1327
1328         *d = NULL;
1329         if (waserror()) {
1330                 poperror();
1331                 return -1;
1332         }
1333         buf = kzmalloc(DIRREADLIM, 0);
1334         if (buf == NULL)
1335                 error(Enomem);
1336         if (waserror()) {
1337                 kfree(buf);
1338                 nexterror();
1339         }
1340         ts = sysread(fd, buf, DIRREADLIM);
1341         if (ts >= 0)
1342                 ts = dirpackage(buf, ts, d);
1343         poperror();
1344         kfree(buf);
1345         poperror();
1346         return ts;
1347 }
1348
1349 int sysiounit(int fd)
1350 {
1351         ERRSTACK(1);
1352         struct chan *c;
1353         int n;
1354
1355         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1356         if (waserror()) {
1357                 cclose(c);
1358                 poperror();
1359                 return 0;       /* n.b. */
1360         }
1361         n = c->iounit;
1362         poperror();
1363         cclose(c);
1364         return n;
1365 }
1366
1367 /* Notes on concurrency:
1368  * - Can't hold spinlocks while we call cclose, since it might sleep eventually.
1369  * - We're called from proc_destroy, so we could have concurrent openers trying
1370  *   to add to the group (other syscalls), hence the "closed" flag.
1371  * - dot and slash chans are dealt with in proc_free.  its difficult to close
1372  *   and zero those with concurrent syscalls, since those are a source of krefs.
1373  * - the memory is freed in proc_free().  need to wait to do it, since we can
1374  *   have concurrent accesses to fgrp before free.
1375  * - Once we lock and set closed, no further additions can happen.  To simplify
1376  *   our closes, we also allow multiple calls to this func (though that should
1377  *   never happen with the current code). */
1378 void close_9ns_files(struct proc *p, bool only_cloexec)
1379 {
1380         
1381         struct fgrp *f = p->fgrp;
1382
1383         spin_lock(&f->lock);
1384         if (f->closed) {
1385                 spin_unlock(&f->lock);
1386                 warn("Unexpected double-close");
1387                 return;
1388         }
1389         if (!only_cloexec)
1390                 f->closed = TRUE;
1391         spin_unlock(&f->lock);
1392
1393         /* maxfd is a legit val, not a +1 */
1394         for (int i = 0; i <= f->maxfd; i++) {
1395                 if (!f->fd[i])
1396                         continue;
1397                 if (only_cloexec && !(f->fd[i]->flag & CCEXEC))
1398                         continue;
1399                 cclose(f->fd[i]);
1400                 f->fd[i] = 0;
1401         }
1402 }
1403
1404 void print_chaninfo(struct chan *c)
1405 {
1406         
1407         char buf[64] = { 0 };
1408         bool has_dev = c->type != -1;
1409         if (has_dev && !devtab[c->type].chaninfo) {
1410                 printk("Chan type %d has no chaninfo!\n", c->type);
1411                 has_dev = FALSE;
1412         }
1413         printk("Chan pathname: %s ref %d, Dev: %s, Devinfo: %s",
1414                    c->name ? c->name->s : "no cname",
1415                    kref_refcnt(&c->ref),
1416                    has_dev ? devtab[c->type].name : "no dev",
1417                    has_dev ? devtab[c->type].chaninfo(c, buf, sizeof(buf)) : "");
1418         if (!has_dev)
1419                 printk("qid.path: %p\n", c->qid.path);
1420         printk("\n");
1421 }
1422
1423 void print_9ns_files(struct proc *p)
1424 {
1425         
1426         struct fgrp *f = p->fgrp;
1427         spin_lock(&f->lock);
1428         printk("9ns files for proc %d:\n", p->pid);
1429         /* maxfd is a legit val, not a +1 */
1430         for (int i = 0; i <= f->maxfd; i++) {
1431                 if (!f->fd[i])
1432                         continue;
1433                 printk("\t9fs %4d, ", i);
1434                 print_chaninfo(f->fd[i]);
1435         }
1436         spin_unlock(&f->lock);
1437 }
1438
1439 /* TODO: 9ns ns inheritance flags: Shared, copied, or empty.  Looks like we're
1440  * copying the fgrp, and sharing the pgrp. */
1441 int plan9setup(struct proc *new_proc, struct proc *parent, int flags)
1442 {
1443         
1444         struct proc *old_current;
1445         struct kref *new_dot_ref;
1446         ERRSTACK(1);
1447         if (waserror()) {
1448                 printk("plan9setup failed, %s\n", current_errstr());
1449                 poperror();
1450                 return -1;
1451         }
1452         if (!parent) {
1453                 /* We are probably spawned by the kernel directly, and have no parent to
1454                  * inherit from.  Be sure to set up fgrp/pgrp before calling namec().
1455                  *
1456                  * TODO: One problem is namec wants a current set for things like
1457                  * genbuf.  So we'll use new_proc for this bootstrapping.  Note
1458                  * switch_to() also loads the cr3. */
1459                 new_proc->fgrp = newfgrp();
1460                 new_proc->pgrp = newpgrp();
1461                 old_current = switch_to(new_proc);
1462                 new_proc->slash = namec("#r", Atodir, 0, 0);
1463                 if (!new_proc->slash)
1464                         panic("no root device");
1465                 switch_back(new_proc, old_current);
1466                 /* Want the name to be "/" instead of "#r" */
1467                 cnameclose(new_proc->slash->name);
1468                 new_proc->slash->name = newcname("/");
1469                 new_proc->dot = cclone(new_proc->slash);
1470                 poperror();
1471                 return 0;
1472         }
1473         /* When we use the old fgrp, we have copy semantics: do not change this
1474          * without revisiting proc_destroy, close_9ns_files, and closefgrp. */
1475         if (flags & PROC_DUP_FGRP)
1476                 new_proc->fgrp = dupfgrp(new_proc, parent->fgrp);
1477         else
1478                 new_proc->fgrp = newfgrp();
1479         /* Shared semantics */
1480         kref_get(&parent->pgrp->ref, 1);
1481         new_proc->pgrp = parent->pgrp;
1482         /* copy semantics on / and . (doesn't make a lot of sense in akaros o/w) */
1483         /* / should never disappear while we hold a ref to parent */
1484         chan_incref(parent->slash);
1485         new_proc->slash = parent->slash;
1486         /* dot could change concurrently, and we could fail to gain a ref if whoever
1487          * decref'd dot triggered the release.  if that did happen, new_proc->dot
1488          * should update and we can try again. */
1489         while (!(new_dot_ref = kref_get_not_zero(&parent->dot->ref, 1)))
1490                 cpu_relax();
1491         /* And now, we can't trust parent->dot, and need to determine our dot from
1492          * the ref we obtained. */
1493         new_proc->dot = container_of(new_dot_ref, struct chan, ref);
1494         poperror();
1495         return 0;
1496 }
1497
1498 /* Open flags, create modes, access types, file flags, and all that...
1499  *
1500  * there are a bunch of things here:
1501  *              1) file creation flags (e.g. O_TRUNC)
1502  *              2) file status flags (e.g. O_APPEND)
1503  *              3) file open modes (e.g. O_RDWR)
1504  *              4) file descriptor flags (e.g. CLOEXEC)
1505  *              5) file creation mode (e.g. S_IRWXU)
1506  * the 1-4 are passed in via open's vfs_flags, and the 5 via mode only when
1507  * O_CREATE is set.
1508  *
1509  * file creation flags (1) only matter when creating, but aren't permanent.
1510  * O_EXCL, O_DIRECTORY, O_TRUNC, etc.
1511  *
1512  * file status flags (2) are per struct file/chan.  stuff like O_APPEND,
1513  * O_ASYNC, etc.  we convert those to an internal flag bit and store in c->flags
1514  *
1515  * the open mode (3) matters for a given FD/chan (chan->mode), and should be
1516  * stored in the chan. (c->mode) stuff like O_RDONLY.
1517  *
1518  * the file descriptor flags (4) clearly are in the FD.  note that the same
1519  * file/chan can be opened by two different FDs, with different flags.  the only
1520  * one anyone uses is CLOEXEC.  while exec may not last long in akaros, i can
1521  * imagine similar "never pass to children" flags/meanings.
1522  *
1523  * the file creation mode (5) matters for the device's permissions; given this,
1524  * it should be stored in the device/inode.  ACLs fall under this category.
1525  *
1526  * finally, only certain categories can be edited afterwards: file status flags
1527  * (2), FD flags (4), and file permissions (5). */
1528 int fd_getfl(int fd)
1529 {
1530         ERRSTACK(1);
1531         struct chan *c;
1532         int ret;
1533
1534         if (waserror()) {
1535                 poperror();
1536                 return -1;
1537         }
1538         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1539
1540         ret = c->mode;
1541         if (c->flag & CAPPEND)
1542                 ret |= O_APPEND;
1543
1544         cclose(c);
1545         poperror();
1546         return ret;
1547 }
1548
1549 int fd_setfl(int fd, int flags)
1550 {
1551         ERRSTACK(1);
1552         struct chan *c;
1553
1554         if (waserror()) {
1555                 poperror();
1556                 return -1;
1557         }
1558         c = fdtochan(current->fgrp, fd, -1, 0, 1);
1559
1560         if (flags & O_APPEND)
1561                 c->flag |= CAPPEND;
1562
1563         cclose(c);
1564         poperror();
1565         return 0;
1566 }