]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devfs.c
kernel: implement separate wait queues for page allocation
[plan9front.git] / sys / src / 9 / port / devfs.c
1 /*
2  * File system devices.
3  * Follows device config in Ken's file server.
4  * Builds mirrors, concatenations, interleavings, and partitions
5  * of devices out of other (inner) devices.
6  * It is ok if inner devices are provided by this driver.
7  *
8  * Built files are grouped on different directories
9  * (called trees, and used to represent disks).
10  * The "#k/fs" tree is always available and never goes away.
11  * Configuration changes happen only while no I/O is in progress.
12  *
13  * Default sector size is one byte unless changed by the "disk" ctl.
14  */
15
16 #include "u.h"
17 #include "../port/lib.h"
18 #include "mem.h"
19 #include "dat.h"
20 #include "fns.h"
21 #include "io.h"
22 #include "ureg.h"
23 #include "../port/error.h"
24 #include "libsec.h"
25
26 int  dec16(uchar *out, int lim, char *in, int n);
27
28 enum
29 {
30         Fnone,
31         Fmirror,                /* mirror of others */
32         Fcat,                   /* catenation of others */
33         Finter,                 /* interleaving of others */
34         Fpart,                  /* part of other */
35         Fclear,                 /* start over */
36         Fdel,                   /* delete a configure device */
37         Fdisk,                  /* set default tree and sector sz*/
38         Fcrypt,                 /* encrypted device */
39
40         Sectorsz = 1,
41         Blksize = 8*1024,       /* for Finter only */
42
43         Incr = 5,               /* Increments for the dev array */
44
45         /*
46          * All qids are decorated with the tree number.
47          * #k/fs is tree number 0, is automatically added and
48          * its first qid is for the ctl file. It never goes away.
49          */
50         Qtop    = 0,            /* #k */
51         Qdir,                   /* directory (#k/fs) */
52         Qctl,                   /* ctl, only for #k/fs/ctl */
53         Qfirst,                 /* first qid assigned for device */
54
55         Iswrite = 0,
56         Isread,
57
58         Optional = 0,
59         Mustexist,
60
61         /* tunable parameters */
62         Maxconf = 4*1024,       /* max length for config */
63         Ndevs   = 32,           /* max. inner devs per command */
64         Ntrees  = 128,          /* max. number of trees */
65         Maxretries = 3,         /* max. retries of i/o errors */
66         Retrypause = 5000,      /* ms. to pause between retries */
67 };
68
69 typedef struct Inner Inner;
70 typedef struct Fsdev Fsdev;
71 typedef struct Tree Tree;
72 typedef struct Key Key;
73
74 struct Inner
75 {
76         char    *iname;         /* inner device name */
77         vlong   isize;          /* size of inner device */
78         Chan    *idev;          /* inner device */
79 };
80
81 struct Fsdev
82 {
83         Ref;                    /* one per Chan doing I/O */
84         int     gone;           /* true if removed */
85         int     vers;           /* qid version for this device */
86         int     type;           /* Fnone, Fmirror, ... */
87         char    *name;          /* name for this fsdev */
88         Tree*   tree;           /* where the device is kept */
89         vlong   size;           /* min(inner[X].isize) */
90         vlong   start;          /* start address (for Fpart) */
91         uint    ndevs;          /* number of inner devices */
92         Inner   *inner[Ndevs];  /* inner devices */
93         void *extra;                /* extra state for the device */
94 };
95
96 struct Tree
97 {
98         char    *name;          /* name for #k/<name> */
99         Fsdev   **devs;         /* devices in dir. */
100         uint    ndevs;          /* number of devices */
101         uint    nadevs;         /* number of allocated devices in devs */
102 };
103
104 struct Key {
105         AESstate tweak, ecb;
106 };
107
108 #define dprint if(debug)print
109
110 extern Dev fsdevtab;            /* forward */
111
112 static RWlock lck;              /* r: use devices; w: change config  */
113 static Tree fstree;             /* The main "fs" tree. Never goes away */
114 static Tree *trees[Ntrees];     /* internal representation of config */
115 static int ntrees;              /* max number of trees */
116 static int qidvers;
117 static char *disk;              /* default tree name used */
118 static char *source;            /* default inner device used */
119 static int sectorsz = Sectorsz; /* default sector size */
120 static char confstr[Maxconf];   /* textual configuration */
121
122 static int debug;
123
124 static char cfgstr[] = "fsdev:\n";
125
126 static Qid tqid = {Qtop, 0, QTDIR};
127 static Qid cqid = {Qctl, 0, 0};
128
129 static char* tnames[] = {
130         [Fmirror]       "mirror",
131         [Fcat]          "cat",
132         [Finter]        "inter",
133         [Fpart]         "part",
134         [Fcrypt]        "crypt",
135 };
136
137 static Cmdtab configs[] = {
138         Fmirror,"mirror",       0,
139         Fcat,   "cat",          0,
140         Finter, "inter",        0,
141         Fpart,  "part",         0,
142         Fclear, "clear",        1,
143         Fdel,   "del",          2,
144         Fdisk,  "disk",         0,
145         Fcrypt, "crypt",        0,
146 };
147
148 static char Egone[] = "device is gone";         /* file has been removed */
149
150 static char*
151 seprintdev(char *s, char *e, Fsdev *mp)
152 {
153         int i;
154
155         if(mp == nil)
156                 return seprint(s, e, "<null Fsdev>");
157         if(mp->type < 0 || mp->type >= nelem(tnames) || tnames[mp->type] == nil)
158                 return seprint(s, e, "bad device type %d\n", mp->type);
159
160         s = strecpy(s, e, tnames[mp->type]);
161         if(mp->tree != &fstree)
162                 s = seprint(s, e, " %s/%s", mp->tree->name, mp->name);
163         else
164                 s = seprint(s, e, " %s", mp->name);
165         for(i = 0; i < mp->ndevs; i++)
166                 s = seprint(s, e, " %s", mp->inner[i]->iname);
167         switch(mp->type){
168         case Fmirror:
169         case Fcat:
170         case Finter:
171         case Fcrypt:
172                 s = strecpy(s, e, "\n");
173                 break;
174         case Fpart:
175                 s = seprint(s, e, " %ulld %ulld\n", mp->start, mp->size);
176                 break;
177         default:
178                 panic("#k: seprintdev bug");
179         }
180         return s;
181 }
182
183 static vlong
184 mkpath(int tree, int devno)
185 {
186         return (tree&0xFFFF)<<16 | devno&0xFFFF;
187 }
188
189 static int
190 path2treeno(int q)
191 {
192         return q>>16 & 0xFFFF;
193 }
194
195 static int
196 path2devno(int q)
197 {
198         return q & 0xFFFF;
199 }
200
201 static Tree*
202 gettree(int i, int mustexist)
203 {
204         dprint("gettree %d\n", i);
205         if(i < 0)
206                 panic("#k: bug: bad tree index %d in gettree", i);
207         if(i >= ntrees || trees[i] == nil)
208                 if(mustexist)
209                         error(Enonexist);
210                 else
211                         return nil;
212         return trees[i];
213 }
214
215 static Fsdev*
216 getdev(Tree *t, int i, int mustexist)
217 {
218         dprint("getdev %d\n", i);
219         if(i < 0)
220                 panic("#k: bug: bad dev index %d in getdev", i);
221         if(i >= t->nadevs || t->devs[i] == nil)
222                 if(mustexist)
223                         error(Enonexist);
224                 else
225                         return nil;
226         return t->devs[i];
227 }
228
229 static Fsdev*
230 path2dev(int q)
231 {
232         Tree    *t;
233
234         dprint("path2dev %ux\n", q);
235         t = gettree(path2treeno(q), Mustexist);
236         return getdev(t, path2devno(q) - Qfirst, Mustexist);
237 }
238
239 static Tree*
240 treealloc(char *name)
241 {
242         int     i;
243         Tree    *t;
244
245         dprint("treealloc %s\n", name);
246         for(i = 0; i < nelem(trees); i++)
247                 if(trees[i] == nil)
248                         break;
249         if(i == nelem(trees))
250                 return nil;
251         t = trees[i] = mallocz(sizeof(Tree), 1);
252         if(t == nil)
253                 error(Enomem);
254         if(i == ntrees)
255                 ntrees++;
256         kstrdup(&t->name, name);
257         return t;
258 }
259
260 static Tree*
261 lookuptree(char *name)
262 {
263         int i;
264
265         dprint("lookuptree %s\n", name);
266         for(i = 0; i < ntrees; i++)
267                 if(trees[i] != nil && strcmp(trees[i]->name, name) == 0)
268                         return trees[i];
269         return nil;
270 }
271
272 static Fsdev*
273 devalloc(Tree *t, char *name)
274 {
275         int     i, ndevs;
276         Fsdev   *mp, **devs;
277
278         dprint("devalloc %s %s\n", t->name, name);
279         mp = mallocz(sizeof(Fsdev), 1);
280         if(mp == nil)
281                 return nil;
282         for(i = 0; i < t->nadevs; i++)
283                 if(t->devs[i] == nil)
284                         break;
285         if(i >= t->nadevs){
286                 if(t->nadevs % Incr == 0){
287                         ndevs = t->nadevs + Incr;
288                         devs = realloc(t->devs, ndevs * sizeof(Fsdev*));
289                         if(devs == nil){
290                                 free(mp);
291                                 return nil;
292                         }
293                         t->devs = devs;
294                 }
295                 t->devs[t->nadevs] = nil;
296                 t->nadevs++;
297         }
298         kstrdup(&mp->name, name);
299         mp->vers = ++qidvers;
300         mp->tree = t;
301         t->devs[i] = mp;
302         t->ndevs++;
303         return mp;
304 }
305
306 static void
307 deltree(Tree *t)
308 {
309         int i;
310
311         dprint("deltree %s\n", t->name);
312         for(i = 0; i < ntrees; i++)
313                 if(trees[i] == t){
314                         if(i > 0){              /* "fs" never goes away */
315                                 free(t->name);
316                                 free(t->devs);
317                                 free(t);
318                                 trees[i] = nil;
319                         }
320                         return;
321                 }
322         panic("#k: deltree: bug: tree not found");
323 }
324
325 /*
326  * A device is gone and we know that all its users are gone.
327  * A tree is gone when all its devices are gone ("fs" is never gone).
328  * Must close devices outside locks, so we could nest our own devices.
329  */
330 static void
331 mdeldev(Fsdev *mp)
332 {
333         int     i;
334         Inner   *in;
335         Tree    *t;
336
337         dprint("deldev %s gone %d ref %uld\n", mp->name, mp->gone, mp->ref);
338
339         mp->gone = 1;
340         mp->vers = ++qidvers;
341
342         wlock(&lck);
343         t = mp->tree;
344         for(i = 0; i < t->nadevs; i++)
345                 if(t->devs[i] == mp){
346                         t->devs[i] = nil;
347                         t->ndevs--;
348                         if(t->ndevs == 0)
349                                 deltree(t);
350                         break;
351                 }
352         wunlock(&lck);
353
354         free(mp->name);
355         for(i = 0; i < mp->ndevs; i++){
356                 in = mp->inner[i];
357                 if(in->idev != nil)
358                         cclose(in->idev);
359                 free(in->iname);
360                 free(in);
361         }
362         if(debug)
363                 memset(mp, 9, sizeof *mp);      /* poison */
364         free(mp);
365 }
366
367 /*
368  * Delete one or all devices in one or all trees.
369  */
370 static void
371 mdelctl(char *tname, char *dname)
372 {
373         int i, alldevs, alltrees, some;
374         Fsdev *mp;
375         Tree *t;
376
377         dprint("delctl %s\n", dname);
378         alldevs = strcmp(dname, "*") == 0;
379         alltrees = strcmp(tname, "*") == 0;
380         some = 0;
381 Again:
382         wlock(&lck);
383         for(i = 0; i < ntrees; i++){
384                 t = trees[i];
385                 if(t == nil)
386                         continue;
387                 if(alltrees == 0 && strcmp(t->name, tname) != 0)
388                         continue;
389                 for(i = 0; i < t->nadevs; i++){
390                         mp = t->devs[i];
391                         if(t->devs[i] == nil)
392                                 continue;
393                         if(alldevs == 0 && strcmp(mp->name, dname) != 0)
394                                 continue;
395                         /*
396                          * Careful: must close outside locks and that
397                          * may change the file tree we are looking at.
398                          */
399                         some++;
400                         mp->gone = 1;
401                         if(mp->ref == 0){
402                                 incref(mp);     /* keep it there */
403                                 wunlock(&lck);
404                                 mdeldev(mp);
405                                 goto Again;     /* tree can change */
406                         }
407                 }
408         }
409         wunlock(&lck);
410         if(some == 0 && alltrees == 0)
411                 error(Enonexist);
412 }
413
414 static void
415 setdsize(Fsdev* mp, vlong *ilen)
416 {
417         int     i;
418         vlong   inlen;
419         Inner   *in;
420
421         dprint("setdsize %s\n", mp->name);
422         for (i = 0; i < mp->ndevs; i++){
423                 in = mp->inner[i];
424                 in->isize = ilen[i];
425                 inlen = in->isize;
426                 switch(mp->type){
427                 case Finter:
428                         /* truncate to multiple of Blksize */
429                         inlen &= ~(Blksize-1);
430                         in->isize = inlen;
431                         /* fall through */
432                 case Fmirror:
433                         /* use size of smallest inner device */
434                         if (mp->size == 0 || mp->size > inlen)
435                                 mp->size = inlen;
436                         break;
437                 case Fcat:
438                         mp->size += inlen;
439                         break;
440                 case Fpart:
441                         if(mp->start > inlen)
442                                 error("partition starts after device end");
443                         if(inlen < mp->start + mp->size){
444                                 print("#k: %s: partition truncated from "
445                                         "%lld to %lld bytes\n", mp->name,
446                                         mp->size, inlen - mp->start);
447                                 mp->size = inlen - mp->start;
448                         }
449                         break;
450                 case Fcrypt:
451                         if(inlen > (64*1024)) {
452                                 mp->size = inlen - (64 * 1024);
453                         } else {
454                                 mp->size = 0;
455                         }
456                         break;
457                 }
458         }
459         if(mp->type == Finter)
460                 mp->size *= mp->ndevs;
461 }
462
463 static void
464 validdevname(Tree *t, char *dname)
465 {
466         int i;
467
468         for(i = 0; i < t->nadevs; i++)
469                 if(t->devs[i] != nil && strcmp(t->devs[i]->name, dname) == 0)
470                         error(Eexist);
471 }
472
473 static void
474 parseconfig(char *a, long n, Cmdbuf **cbp, Cmdtab **ctp)
475 {
476         Cmdbuf  *cb;
477         Cmdtab  *ct;
478
479         *cbp = cb = parsecmd(a, n);
480         *ctp = ct = lookupcmd(cb, configs, nelem(configs));
481
482         cb->f++;                        /* skip command */
483         cb->nf--;
484         switch(ct->index){
485         case Fmirror:
486         case Fcat:
487         case Finter:
488                 if(cb->nf < 2)
489                         error("too few arguments for ctl");
490                 if(cb->nf - 1 > Ndevs)
491                         error("too many devices in ctl");
492                 break;
493         case Fdisk:
494                 if(cb->nf < 1 || cb->nf > 3)
495                         error("ctl usage: disk name [sz dev]");
496                 break;
497         case Fpart:
498                 if(cb->nf != 4 && (cb->nf != 3 || source == nil))
499                         error("ctl usage: part new [file] off len");
500                 break;
501         case Fcrypt:
502                 if(cb->nf != 3)
503                         error("ctl usage: crypt newname device keyhex");
504                 break;
505         }
506 }
507
508 static void
509 parsename(char *name, char *disk, char **tree, char **dev)
510 {
511         char *slash;
512
513         slash = strchr(name, '/');
514         if(slash == nil){
515                 if(disk != nil)
516                         *tree = disk;
517                 else
518                         *tree = "fs";
519                 *dev = name;
520         }else{
521                 *tree = name;
522                 *slash++ = 0;
523                 *dev = slash;
524         }
525         validname(*tree, 0);
526         validname(*dev, 0);
527 }
528
529 static vlong
530 getlen(Chan *c)
531 {
532         uchar   buf[128];       /* old DIRLEN plus a little should be plenty */
533         Dir     d;
534         long    l;
535
536         l = devtab[c->type]->stat(c, buf, sizeof buf);
537         convM2D(buf, l, &d, nil);
538         return d.length;
539 }
540
541 /*
542  * Process a single line of configuration,
543  * often of the form "cmd newname idev0 idev1".
544  * locking is tricky, because we need a write lock to
545  * add/remove devices yet adding/removing them may lead
546  * to calls to this driver that require a read lock (when
547  * inner devices are also provided by us).
548  */
549 static void
550 mconfig(char* a, long n)
551 {
552         int     i;
553         vlong   size, start;
554         vlong   *ilen;
555         char    *tname, *dname, *fakef[4];
556         uchar key[32];
557         Chan    **idev;
558         Cmdbuf  *cb;
559         Cmdtab  *ct;
560         Fsdev   *mp;
561         Inner   *inprv;
562         Tree    *t;
563
564         /* ignore comments & empty lines */
565         if (*a == '\0' || *a == '#' || *a == '\n')
566                 return;
567
568         dprint("mconfig\n");
569         size = 0;
570         start = 0;
571         mp = nil;
572         cb = nil;
573         idev = nil;
574         ilen = nil;
575
576         if(waserror()){
577                 free(cb);
578                 nexterror();
579         }
580
581         parseconfig(a, n, &cb, &ct);
582         switch (ct->index) {
583         case Fdisk:
584                 kstrdup(&disk, cb->f[0]);
585                 if(cb->nf >= 2)
586                         sectorsz = strtoul(cb->f[1], 0, 0);
587                 else
588                         sectorsz = Sectorsz;
589                 if(cb->nf == 3)
590                         kstrdup(&source, cb->f[2]);
591                 else{
592                         free(source);
593                         source = nil;
594                 }
595                 poperror();
596                 free(cb);
597                 return;
598         case Fclear:
599                 poperror();
600                 free(cb);
601                 mdelctl("*", "*");              /* del everything */
602                 return;
603         case Fcrypt:
604                 dec16(key, 32, cb->f[2], 64);
605                 cb->nf -= 1;
606                 break;
607         case Fpart:
608                 if(cb->nf == 3){
609                         /*
610                          * got a request in the format of sd(3),
611                          * pretend we got one in our format.
612                          * later we change end to be len.
613                          */
614                         fakef[0] = cb->f[0];
615                         fakef[1] = source;
616                         fakef[2] = cb->f[1];
617                         fakef[3] = cb->f[2];
618                         cb->f = fakef;
619                         cb->nf = 4;
620                 }
621                 start = strtoll(cb->f[2], nil, 10);
622                 size =  strtoll(cb->f[3], nil, 10);
623                 if(cb->f == fakef)
624                         size -= start;          /* it was end */
625                 cb->nf -= 2;
626                 break;
627         }
628         parsename(cb->f[0], disk, &tname, &dname);
629         for(i = 1; i < cb->nf; i++)
630                 validname(cb->f[i], 1);
631
632         if(ct->index == Fdel){
633                 mdelctl(tname, dname);
634                 poperror();
635                 free(cb);
636                 return;
637         }
638
639         /*
640          * Open all inner devices while we have only a read lock.
641          */
642         poperror();
643         rlock(&lck);
644         if(waserror()){
645                 runlock(&lck);
646 Fail:
647                 for(i = 1; i < cb->nf; i++)
648                         if(idev != nil && idev[i-1] != nil)
649                                 cclose(idev[i-1]);
650                 if(mp != nil)
651                         mdeldev(mp);
652                 free(idev);
653                 free(ilen);
654                 free(cb);
655                 nexterror();
656         }
657         idev = smalloc(sizeof(Chan*) * Ndevs);
658         ilen = smalloc(sizeof(vlong) * Ndevs);
659         for(i = 1; i < cb->nf; i++){
660                 idev[i-1] = namec(cb->f[i], Aopen, ORDWR, 0);
661                 ilen[i-1] = getlen(idev[i-1]);
662         }
663         poperror();
664         runlock(&lck);
665
666         /*
667          * Get a write lock and add the device if we can.
668          */
669         wlock(&lck);
670         if(waserror()){
671                 wunlock(&lck);
672                 goto Fail;
673         }
674
675         t = lookuptree(tname);
676         if(t != nil)
677                 validdevname(t, dname);
678         else{
679                 t = treealloc(tname);
680                 if(t == nil)
681                         error("no more trees");
682         }
683         mp = devalloc(t, dname);
684         if(mp == nil){
685                 if(t->ndevs == 0)       /* it was created for us */
686                         deltree(t);     /* but we will not mdeldev() */
687                 error(Enomem);
688         }
689
690         mp->type = ct->index;
691         if(mp->type == Fpart){
692                 mp->start = start * sectorsz;
693                 mp->size = size * sectorsz;
694         }
695         if(mp->type == Fcrypt) {
696                 Key *k = mallocz(sizeof(Key), 1);
697                 if(k == nil)
698                         error(Enomem);
699                 setupAESstate(&k->tweak, &key[0], 16, nil);
700                 setupAESstate(&k->ecb, &key[16], 16, nil);
701                 memset(key, 0, 32);
702                 mp->extra = k;
703         }
704         for(i = 1; i < cb->nf; i++){
705                 inprv = mp->inner[i-1] = mallocz(sizeof(Inner), 1);
706                 if(inprv == nil)
707                         error(Enomem);
708                 mp->ndevs++;
709                 kstrdup(&inprv->iname, cb->f[i]);
710                 inprv->idev = idev[i-1];
711                 idev[i-1] = nil;
712         }
713         setdsize(mp, ilen);
714
715
716
717         poperror();
718         wunlock(&lck);
719         free(idev);
720         free(ilen);
721         free(cb);
722 }
723
724 static void
725 rdconf(void)
726 {
727         int mustrd;
728         char *c, *e, *p, *s;
729         Chan *cc;
730         static int configed;
731
732         /* only read config file once */
733         if (configed)
734                 return;
735         configed = 1;
736
737         dprint("rdconf\n");
738         /* add the std "fs" tree */
739         trees[0] = &fstree;
740         ntrees++;
741         fstree.name = "fs";
742
743         /* identify the config file */
744         s = getconf("fsconfig");
745         if (s == nil){
746                 mustrd = 0;
747                 s = "/dev/sdC0/fscfg";
748         } else
749                 mustrd = 1;
750
751         if(waserror()){
752                 if(!mustrd)
753                         return;
754                 nexterror();
755         }
756
757         /* read it */
758         cc = namec(s, Aopen, OREAD, 0);
759         if(waserror()){
760                 cclose(cc);
761                 nexterror();
762         }
763         devtab[cc->type]->read(cc, confstr, sizeof confstr, 0);
764         poperror();
765         cclose(cc);
766
767         /* validate, copy and erase config; mconfig will repopulate confstr */
768         if (strncmp(confstr, cfgstr, sizeof cfgstr - 1) != 0)
769                 error("bad #k config, first line must be: 'fsdev:\\n'");
770
771         c = nil;
772         kstrdup(&c, confstr + sizeof cfgstr - 1);
773         if(waserror()){
774                 free(c);
775                 nexterror();
776         }
777         memset(confstr, 0, sizeof confstr);
778         /* process config copy one line at a time */
779         for (p = c; p != nil && *p != '\0'; p = e){
780                 e = strchr(p, '\n');
781                 if (e == nil)
782                         e = p + strlen(p);
783                 else
784                         e++;
785                 mconfig(p, e - p);
786         }
787         poperror();
788         free(c);
789
790         poperror();     /* mustrd */
791 }
792
793 static int
794 mgen(Chan *c, char*, Dirtab*, int, int i, Dir *dp)
795 {
796         int     treeno;
797         Fsdev   *mp;
798         Qid     qid;
799         Tree    *t;
800
801         dprint("mgen %#ullx %d\n", c->qid.path, i);
802         qid.type = QTDIR;
803         qid.vers = 0;
804         if(c->qid.path == Qtop){
805                 if(i == DEVDOTDOT){
806                         devdir(c, tqid, "#k", 0, eve, DMDIR|0775, dp);
807                         return 1;
808                 }
809                 t = gettree(i, Optional);
810                 if(t == nil){
811                         dprint("no\n");
812                         return -1;
813                 }
814                 qid.path = mkpath(i, Qdir);
815                 devdir(c, qid, t->name, 0, eve, DMDIR|0775, dp);
816                 return 1;
817         }
818
819         treeno = path2treeno(c->qid.path);
820         t = gettree(treeno, Optional);
821         if(t == nil){
822                 dprint("no\n");
823                 return -1;
824         }
825         if((c->qid.type & QTDIR) != 0){
826                 if(i == DEVDOTDOT){
827                         devdir(c, tqid, "#k", 0, eve, DMDIR|0775, dp);
828                         return 1;
829                 }
830                 if(treeno == 0){
831                         /* take care of #k/fs/ctl */
832                         if(i == 0){
833                                 devdir(c, cqid, "ctl", 0, eve, 0664, dp);
834                                 return 1;
835                         }
836                         i--;
837                 }
838                 mp = getdev(t, i, Optional);
839                 if(mp == nil){
840                         dprint("no\n");
841                         return -1;
842                 }
843                 qid.type = QTFILE;
844                 qid.vers = mp->vers;
845                 qid.path = mkpath(treeno, Qfirst+i);
846                 devdir(c, qid, mp->name, mp->size, eve, 0664, dp);
847                 return 1;
848         }
849
850         if(i == DEVDOTDOT){
851                 qid.path = mkpath(treeno, Qdir);
852                 devdir(c, qid, t->name, 0, eve, DMDIR|0775, dp);
853                 return 1;
854         }
855         dprint("no\n");
856         return -1;
857 }
858
859 static Chan*
860 mattach(char *spec)
861 {
862         dprint("mattach\n");
863         return devattach(fsdevtab.dc, spec);
864 }
865
866 static Walkqid*
867 mwalk(Chan *c, Chan *nc, char **name, int nname)
868 {
869         Walkqid *wq;
870
871         rdconf();
872
873         dprint("mwalk %llux\n", c->qid.path);
874         rlock(&lck);
875         if(waserror()){
876                 runlock(&lck);
877                 nexterror();
878         }
879         wq = devwalk(c, nc, name, nname, 0, 0, mgen);
880         poperror();
881         runlock(&lck);
882         return wq;
883 }
884
885 static int
886 mstat(Chan *c, uchar *db, int n)
887 {
888         int     p;
889         Dir     d;
890         Fsdev   *mp;
891         Qid     q;
892         Tree    *t;
893
894         dprint("mstat %llux\n", c->qid.path);
895         rlock(&lck);
896         if(waserror()){
897                 runlock(&lck);
898                 nexterror();
899         }
900         p = c->qid.path;
901         memset(&d, 0, sizeof d);
902         switch(p){
903         case Qtop:
904                 devdir(c, tqid, "#k", 0, eve, DMDIR|0775, &d);
905                 break;
906         case Qctl:
907                 devdir(c, cqid, "ctl", 0, eve, 0664, &d);
908                 break;
909         default:
910                 t = gettree(path2treeno(p), Mustexist);
911                 if(c->qid.type & QTDIR)
912                         devdir(c, c->qid, t->name, 0, eve, DMDIR|0775, &d);
913                 else{
914                         mp = getdev(t, path2devno(p) - Qfirst, Mustexist);
915                         q = c->qid;
916                         q.vers = mp->vers;
917                         devdir(c, q, mp->name, mp->size, eve, 0664, &d);
918                 }
919         }
920         n = convD2M(&d, db, n);
921         if (n == 0)
922                 error(Ebadarg);
923         poperror();
924         runlock(&lck);
925         return n;
926 }
927
928 static Chan*
929 mopen(Chan *c, int omode)
930 {
931         int     q;
932         Fsdev   *mp;
933
934         dprint("mopen %llux\n", c->qid.path);
935         if((c->qid.type & QTDIR) && omode != OREAD)
936                 error(Eperm);
937         if(c->qid.path != Qctl && (c->qid.type&QTDIR) == 0){
938                 rlock(&lck);
939                 if(waserror()){
940                         runlock(&lck);
941                         nexterror();
942                 }
943                 q = c->qid.path;
944                 mp = path2dev(q);
945                 if(mp->gone)
946                         error(Egone);
947                 incref(mp);
948                 poperror();
949                 runlock(&lck);
950         }
951         /*
952          * Our mgen does not return the info for the qid
953          * but only for its children. Don't use devopen here.
954          */
955         c->offset = 0;
956         c->mode = openmode(omode);
957         c->flag |= COPEN;
958         return c;
959 }
960
961 static void
962 mclose(Chan *c)
963 {
964         int     mustdel, q;
965         Fsdev   *mp;
966
967         dprint("mclose %llux\n", c->qid.path);
968         if(c->qid.type & QTDIR || !(c->flag & COPEN))
969                 return;
970         rlock(&lck);
971         if(waserror()){
972                 runlock(&lck);
973                 nexterror();
974         }
975         mustdel = 0;
976         mp = nil;
977         q = c->qid.path;
978         if(q == Qctl){
979                 free(disk);
980                 disk = nil;     /* restore defaults */
981                 free(source);
982                 source = nil;
983                 sectorsz = Sectorsz;
984         }else{
985                 mp = path2dev(q);
986                 if(mp->gone != 0 && mp->ref == 1)
987                         mustdel = 1;
988                 else
989                         decref(mp);
990         }
991         poperror();
992         runlock(&lck);
993         if(mustdel)
994                 mdeldev(mp);
995 }
996
997 static long
998 io(Fsdev *mp, Inner *in, int isread, void *a, long l, vlong off)
999 {
1000         long wl;
1001         Chan    *mc;
1002
1003         mc = in->idev;
1004         if(mc == nil)
1005                 error(Egone);
1006         if (waserror()) {
1007                 print("#k: %s: byte %,lld count %ld (of #k/%s): %s error: %s\n",
1008                         in->iname, off, l, mp->name, (isread? "read": "write"),
1009                         (up && up->errstr? up->errstr: ""));
1010                 nexterror();
1011         }
1012         if (isread)
1013                 wl = devtab[mc->type]->read(mc, a, l, off);
1014         else
1015                 wl = devtab[mc->type]->write(mc, a, l, off);
1016         poperror();
1017         return wl;
1018 }
1019
1020 static long
1021 cryptio(Fsdev *mp, int isread, uchar *a, long l, vlong off)
1022 {
1023         long wl, ws, wo, wb;
1024         uchar *buf;
1025         Chan *mc;
1026         Inner *in;
1027         Key *k;
1028         enum {
1029                 Sectsz = 512,
1030                 Maxbuf = 32*Sectsz,
1031         };
1032
1033         if(off < 0 || l <= 0 || ((off|l) & (Sectsz-1)))
1034                 error(Ebadarg);
1035
1036         k = mp->extra;
1037         in = mp->inner[0];
1038         mc = in->idev;
1039         if(mc == nil)
1040                 error(Egone);
1041         off += 64*1024; // Header
1042         wb = l;
1043         if(wb > Maxbuf)
1044                 wb = Maxbuf;
1045         buf = smalloc(wb);
1046         if(waserror()) {
1047                 free(buf);
1048                 print("#k: %s: byte %,lld count %ld (of #k/%s): %s error: %s\n",
1049                         in->iname, off, l, mp->name, (isread? "read": "write"),
1050                         (up && up->errstr? up->errstr: ""));
1051                 nexterror();
1052         }
1053         for(ws = 0; ws < l; ws += wo){
1054                 wo = l - ws;
1055                 if(wo > wb)
1056                         wo = wb;
1057                 if (isread) {
1058                         wo = devtab[mc->type]->read(mc, buf, wo, off);
1059                         if(wo < Sectsz)
1060                                 break;
1061                         wo &= ~(Sectsz-1);
1062                         for(wl=0; wl<wo; wl+=Sectsz)
1063                                 aes_xts_decrypt(k->tweak.ekey, k->ecb.dkey, off+wl, buf+wl, a+wl, Sectsz);
1064                 } else {
1065                         for(wl=0; wl<wo; wl+=Sectsz)
1066                                 aes_xts_encrypt(k->tweak.ekey, k->ecb.ekey, off+wl, a+wl, buf+wl, Sectsz);
1067                         if(devtab[mc->type]->write(mc, buf, wo, off) != wo)
1068                                 error(Eio);
1069                 }
1070                 off += wo;
1071                 a += wo;
1072         }
1073         poperror();
1074         free(buf);
1075
1076         return ws;
1077 }
1078
1079 /* NB: a transfer could span multiple inner devices */
1080 static long
1081 catio(Fsdev *mp, int isread, void *a, long n, vlong off)
1082 {
1083         int     i;
1084         long    l, res;
1085         Inner   *in;
1086
1087         if(debug)
1088                 print("catio %d %p %ld %lld\n", isread, a, n, off);
1089         res = n;
1090         for (i = 0; n > 0 && i < mp->ndevs; i++){
1091                 in = mp->inner[i];
1092                 if (off >= in->isize){
1093                         off -= in->isize;
1094                         continue;               /* not there yet */
1095                 }
1096                 if (off + n > in->isize)
1097                         l = in->isize - off;
1098                 else
1099                         l = n;
1100                 if(debug)
1101                         print("\tdev %d %p %ld %lld\n", i, a, l, off);
1102
1103                 if (io(mp, in, isread, a, l, off) != l)
1104                         error(Eio);
1105
1106                 a = (char*)a + l;
1107                 off = 0;
1108                 n -= l;
1109         }
1110         if(debug)
1111                 print("\tres %ld\n", res - n);
1112         return res - n;
1113 }
1114
1115 static long
1116 interio(Fsdev *mp, int isread, void *a, long n, vlong off)
1117 {
1118         int     i;
1119         long    boff, res, l, wl, wsz;
1120         vlong   woff, blk, mblk;
1121
1122         blk  = off / Blksize;
1123         boff = off % Blksize;
1124         wsz  = Blksize - boff;
1125         res = n;
1126         while(n > 0){
1127                 mblk = blk / mp->ndevs;
1128                 i    = blk % mp->ndevs;
1129                 woff = mblk*Blksize + boff;
1130                 if (n > wsz)
1131                         l = wsz;
1132                 else
1133                         l = n;
1134
1135                 wl = io(mp, mp->inner[i], isread, a, l, woff);
1136                 if (wl != l)
1137                         error(Eio);
1138
1139                 blk++;
1140                 boff = 0;
1141                 wsz = Blksize;
1142                 a = (char*)a + l;
1143                 n -= l;
1144         }
1145         return res;
1146 }
1147
1148 static char*
1149 seprintconf(char *s, char *e)
1150 {
1151         int     i, j;
1152         Tree    *t;
1153
1154         *s = 0;
1155         for(i = 0; i < ntrees; i++){
1156                 t = trees[i];
1157                 if(t != nil)
1158                         for(j = 0; j < t->nadevs; j++)
1159                                 if(t->devs[j] != nil)
1160                                         s = seprintdev(s, e, t->devs[j]);
1161         }
1162         return s;
1163 }
1164
1165 static long
1166 mread(Chan *c, void *a, long n, vlong off)
1167 {
1168         int     i, retry;
1169         long    l, res;
1170         Fsdev   *mp;
1171         Tree    *t;
1172
1173         dprint("mread %llux\n", c->qid.path);
1174         rlock(&lck);
1175         if(waserror()){
1176                 runlock(&lck);
1177                 nexterror();
1178         }
1179         res = -1;
1180         if(c->qid.type & QTDIR){
1181                 res = devdirread(c, a, n, 0, 0, mgen);
1182                 goto Done;
1183         }
1184         if(c->qid.path == Qctl){
1185                 seprintconf(confstr, confstr + sizeof(confstr));
1186                 res = readstr((long)off, a, n, confstr);
1187                 goto Done;
1188         }
1189
1190         t = gettree(path2treeno(c->qid.path), Mustexist);
1191         mp = getdev(t, path2devno(c->qid.path) - Qfirst, Mustexist);
1192
1193         if(off >= mp->size){
1194                 res = 0;
1195                 goto Done;
1196         }
1197         if(off + n > mp->size)
1198                 n = mp->size - off;
1199         if(n == 0){
1200                 res = 0;
1201                 goto Done;
1202         }
1203
1204         switch(mp->type){
1205         case Fcat:
1206                 res = catio(mp, Isread, a, n, off);
1207                 break;
1208         case Finter:
1209                 res = interio(mp, Isread, a, n, off);
1210                 break;
1211         case Fpart:
1212                 res = io(mp, mp->inner[0], Isread, a, n, mp->start + off);
1213                 break;
1214         case Fmirror:
1215                 retry = 0;
1216                 do {
1217                         if (retry > 0) {
1218                                 print("#k/%s: retry %d read for byte %,lld "
1219                                         "count %ld: %s\n", mp->name, retry, off,
1220                                         n, (up && up->errstr? up->errstr: ""));
1221                                 /*
1222                                  * pause before retrying in case it's due to
1223                                  * a transient bus or controller problem.
1224                                  */
1225                                 tsleep(&up->sleep, return0, 0, Retrypause);
1226                         }
1227                         for (i = 0; i < mp->ndevs; i++){
1228                                 if (waserror())
1229                                         continue;
1230                                 l = io(mp, mp->inner[i], Isread, a, n, off);
1231                                 poperror();
1232                                 if (l >= 0){
1233                                         res = l;
1234                                         break;          /* read a good copy */
1235                                 }
1236                         }
1237                 } while (i == mp->ndevs && ++retry <= Maxretries);
1238                 if (retry > Maxretries) {
1239                         /* no mirror had a good copy of the block */
1240                         print("#k/%s: byte %,lld count %ld: CAN'T READ "
1241                                 "from mirror: %s\n", mp->name, off, n,
1242                                 (up && up->errstr? up->errstr: ""));
1243                         error(Eio);
1244                 } else if (retry > 0)
1245                         print("#k/%s: byte %,lld count %ld: retry read OK "
1246                                 "from mirror: %s\n", mp->name, off, n,
1247                                 (up && up->errstr? up->errstr: ""));
1248                 break;
1249         case Fcrypt:
1250                 res = cryptio(mp, Isread, a, n, off);
1251                 break;
1252         }
1253 Done:
1254         poperror();
1255         runlock(&lck);
1256         return res;
1257 }
1258
1259 static long
1260 mwrite(Chan *c, void *a, long n, vlong off)
1261 {
1262         int     i, allbad, anybad, retry;
1263         long    l, res;
1264         Fsdev   *mp;
1265         Tree    *t;
1266
1267         dprint("mwrite %llux\n", c->qid.path);
1268         if (c->qid.type & QTDIR)
1269                 error(Eisdir);
1270         if (c->qid.path == Qctl){
1271                 mconfig(a, n);
1272                 return n;
1273         }
1274
1275         rlock(&lck);
1276         if(waserror()){
1277                 runlock(&lck);
1278                 nexterror();
1279         }
1280
1281         t = gettree(path2treeno(c->qid.path), Mustexist);
1282         mp = getdev(t, path2devno(c->qid.path) - Qfirst, Mustexist);
1283
1284         if(off >= mp->size){
1285                 res = 0;
1286                 goto Done;
1287         }
1288         if(off + n > mp->size)
1289                 n = mp->size - off;
1290         if(n == 0){
1291                 res = 0;
1292                 goto Done;
1293         }
1294         res = n;
1295         switch(mp->type){
1296         case Fcat:
1297                 res = catio(mp, Iswrite, a, n, off);
1298                 break;
1299         case Finter:
1300                 res = interio(mp, Iswrite, a, n, off);
1301                 break;
1302         case Fpart:
1303                 res = io(mp, mp->inner[0], Iswrite, a, n, mp->start + off);
1304                 if (res != n)
1305                         error(Eio);
1306                 break;
1307         case Fmirror:
1308                 retry = 0;
1309                 do {
1310                         if (retry > 0) {
1311                                 print("#k/%s: retry %d write for byte %,lld "
1312                                         "count %ld: %s\n", mp->name, retry, off,
1313                                         n, (up && up->errstr? up->errstr: ""));
1314                                 /*
1315                                  * pause before retrying in case it's due to
1316                                  * a transient bus or controller problem.
1317                                  */
1318                                 tsleep(&up->sleep, return0, 0, Retrypause);
1319                         }
1320                         allbad = 1;
1321                         anybad = 0;
1322                         for (i = mp->ndevs - 1; i >= 0; i--){
1323                                 if (waserror()) {
1324                                         anybad = 1;
1325                                         continue;
1326                                 }
1327                                 l = io(mp, mp->inner[i], Iswrite, a, n, off);
1328                                 poperror();
1329                                 if (l == n)
1330                                         allbad = 0;     /* wrote a good copy */
1331                                 else
1332                                         anybad = 1;
1333                         }
1334                 } while (anybad && ++retry <= Maxretries);
1335                 if (allbad) {
1336                         /* no mirror took a good copy of the block */
1337                         print("#k/%s: byte %,lld count %ld: CAN'T WRITE "
1338                                 "to mirror: %s\n", mp->name, off, n,
1339                                 (up && up->errstr? up->errstr: ""));
1340                         error(Eio);
1341                 } else if (retry > 0)
1342                         print("#k/%s: byte %,lld count %ld: retry wrote OK "
1343                                 "to mirror: %s\n", mp->name, off, n,
1344                                 (up && up->errstr? up->errstr: ""));
1345
1346                 break;
1347         case Fcrypt:
1348                 res = cryptio(mp, Iswrite, a, n, off);
1349                 break;
1350         }
1351 Done:
1352         poperror();
1353         runlock(&lck);
1354         return res;
1355 }
1356
1357 Dev fsdevtab = {
1358         'k',
1359         "fs",
1360
1361         devreset,
1362         devinit,
1363         devshutdown,
1364         mattach,
1365         mwalk,
1366         mstat,
1367         mopen,
1368         devcreate,
1369         mclose,
1370         mread,
1371         devbread,
1372         mwrite,
1373         devbwrite,
1374         devremove,
1375         devwstat,
1376         devpower,
1377         devconfig,
1378 };