]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devfs.c
devmouse: remove unneeded reference to kerndate
[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]);
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         /* read it */
752         cc = nil;
753         c = nil;
754         if (waserror()){
755                 if (cc != nil)
756                         cclose(cc);
757                 if (c)
758                         free(c);
759                 if (!mustrd)
760                         return;
761                 nexterror();
762         }
763         cc = namec(s, Aopen, OREAD, 0);
764         devtab[cc->type]->read(cc, confstr, sizeof confstr, 0);
765         cclose(cc);
766         cc = nil;
767
768         /* validate, copy and erase config; mconfig will repopulate confstr */
769         if (strncmp(confstr, cfgstr, sizeof cfgstr - 1) != 0)
770                 error("bad #k config, first line must be: 'fsdev:\\n'");
771         kstrdup(&c, confstr + sizeof cfgstr - 1);
772         memset(confstr, 0, sizeof confstr);
773
774         /* process config copy one line at a time */
775         for (p = c; p != nil && *p != '\0'; p = e){
776                 e = strchr(p, '\n');
777                 if (e == nil)
778                         e = p + strlen(p);
779                 else
780                         e++;
781                 mconfig(p, e - p);
782         }
783         USED(cc);               /* until now, can be used in waserror clause */
784         poperror();
785 }
786
787 static int
788 mgen(Chan *c, char*, Dirtab*, int, int i, Dir *dp)
789 {
790         int     treeno;
791         Fsdev   *mp;
792         Qid     qid;
793         Tree    *t;
794
795         dprint("mgen %#ullx %d\n", c->qid.path, i);
796         qid.type = QTDIR;
797         qid.vers = 0;
798         if(c->qid.path == Qtop){
799                 if(i == DEVDOTDOT){
800                         devdir(c, tqid, "#k", 0, eve, DMDIR|0775, dp);
801                         return 1;
802                 }
803                 t = gettree(i, Optional);
804                 if(t == nil){
805                         dprint("no\n");
806                         return -1;
807                 }
808                 qid.path = mkpath(i, Qdir);
809                 devdir(c, qid, t->name, 0, eve, DMDIR|0775, dp);
810                 return 1;
811         }
812
813         treeno = path2treeno(c->qid.path);
814         t = gettree(treeno, Optional);
815         if(t == nil){
816                 dprint("no\n");
817                 return -1;
818         }
819         if((c->qid.type & QTDIR) != 0){
820                 if(i == DEVDOTDOT){
821                         devdir(c, tqid, "#k", 0, eve, DMDIR|0775, dp);
822                         return 1;
823                 }
824                 if(treeno == 0){
825                         /* take care of #k/fs/ctl */
826                         if(i == 0){
827                                 devdir(c, cqid, "ctl", 0, eve, 0664, dp);
828                                 return 1;
829                         }
830                         i--;
831                 }
832                 mp = getdev(t, i, Optional);
833                 if(mp == nil){
834                         dprint("no\n");
835                         return -1;
836                 }
837                 qid.type = QTFILE;
838                 qid.vers = mp->vers;
839                 qid.path = mkpath(treeno, Qfirst+i);
840                 devdir(c, qid, mp->name, mp->size, eve, 0664, dp);
841                 return 1;
842         }
843
844         if(i == DEVDOTDOT){
845                 qid.path = mkpath(treeno, Qdir);
846                 devdir(c, qid, t->name, 0, eve, DMDIR|0775, dp);
847                 return 1;
848         }
849         dprint("no\n");
850         return -1;
851 }
852
853 static Chan*
854 mattach(char *spec)
855 {
856         dprint("mattach\n");
857         return devattach(fsdevtab.dc, spec);
858 }
859
860 static Walkqid*
861 mwalk(Chan *c, Chan *nc, char **name, int nname)
862 {
863         Walkqid *wq;
864
865         rdconf();
866
867         dprint("mwalk %llux\n", c->qid.path);
868         rlock(&lck);
869         if(waserror()){
870                 runlock(&lck);
871                 nexterror();
872         }
873         wq = devwalk(c, nc, name, nname, 0, 0, mgen);
874         poperror();
875         runlock(&lck);
876         return wq;
877 }
878
879 static int
880 mstat(Chan *c, uchar *db, int n)
881 {
882         int     p;
883         Dir     d;
884         Fsdev   *mp;
885         Qid     q;
886         Tree    *t;
887
888         dprint("mstat %llux\n", c->qid.path);
889         rlock(&lck);
890         if(waserror()){
891                 runlock(&lck);
892                 nexterror();
893         }
894         p = c->qid.path;
895         memset(&d, 0, sizeof d);
896         switch(p){
897         case Qtop:
898                 devdir(c, tqid, "#k", 0, eve, DMDIR|0775, &d);
899                 break;
900         case Qctl:
901                 devdir(c, cqid, "ctl", 0, eve, 0664, &d);
902                 break;
903         default:
904                 t = gettree(path2treeno(p), Mustexist);
905                 if(c->qid.type & QTDIR)
906                         devdir(c, c->qid, t->name, 0, eve, DMDIR|0775, &d);
907                 else{
908                         mp = getdev(t, path2devno(p) - Qfirst, Mustexist);
909                         q = c->qid;
910                         q.vers = mp->vers;
911                         devdir(c, q, mp->name, mp->size, eve, 0664, &d);
912                 }
913         }
914         n = convD2M(&d, db, n);
915         if (n == 0)
916                 error(Ebadarg);
917         poperror();
918         runlock(&lck);
919         return n;
920 }
921
922 static Chan*
923 mopen(Chan *c, int omode)
924 {
925         int     q;
926         Fsdev   *mp;
927
928         dprint("mopen %llux\n", c->qid.path);
929         if((c->qid.type & QTDIR) && omode != OREAD)
930                 error(Eperm);
931         if(c->qid.path != Qctl && (c->qid.type&QTDIR) == 0){
932                 rlock(&lck);
933                 if(waserror()){
934                         runlock(&lck);
935                         nexterror();
936                 }
937                 q = c->qid.path;
938                 mp = path2dev(q);
939                 if(mp->gone)
940                         error(Egone);
941                 incref(mp);
942                 poperror();
943                 runlock(&lck);
944         }
945         /*
946          * Our mgen does not return the info for the qid
947          * but only for its children. Don't use devopen here.
948          */
949         c->offset = 0;
950         c->mode = openmode(omode & ~OTRUNC);
951         c->flag |= COPEN;
952         return c;
953 }
954
955 static void
956 mclose(Chan *c)
957 {
958         int     mustdel, q;
959         Fsdev   *mp;
960
961         dprint("mclose %llux\n", c->qid.path);
962         if(c->qid.type & QTDIR || !(c->flag & COPEN))
963                 return;
964         rlock(&lck);
965         if(waserror()){
966                 runlock(&lck);
967                 nexterror();
968         }
969         mustdel = 0;
970         mp = nil;
971         q = c->qid.path;
972         if(q == Qctl){
973                 free(disk);
974                 disk = nil;     /* restore defaults */
975                 free(source);
976                 source = nil;
977                 sectorsz = Sectorsz;
978         }else{
979                 mp = path2dev(q);
980                 if(mp->gone != 0 && mp->ref == 1)
981                         mustdel = 1;
982                 else
983                         decref(mp);
984         }
985         poperror();
986         runlock(&lck);
987         if(mustdel)
988                 mdeldev(mp);
989 }
990
991 static long
992 io(Fsdev *mp, Inner *in, int isread, void *a, long l, vlong off)
993 {
994         long wl;
995         Chan    *mc;
996
997         mc = in->idev;
998         if(mc == nil)
999                 error(Egone);
1000         if (waserror()) {
1001                 print("#k: %s: byte %,lld count %ld (of #k/%s): %s error: %s\n",
1002                         in->iname, off, l, mp->name, (isread? "read": "write"),
1003                         (up && up->errstr? up->errstr: ""));
1004                 nexterror();
1005         }
1006         if (isread)
1007                 wl = devtab[mc->type]->read(mc, a, l, off);
1008         else
1009                 wl = devtab[mc->type]->write(mc, a, l, off);
1010         poperror();
1011         return wl;
1012 }
1013
1014 static long
1015 cryptio(Fsdev *mp, int isread, uchar *a, long l, vlong off)
1016 {
1017         long wl, ws, wo, wb;
1018         uchar *buf;
1019         Chan *mc;
1020         Inner *in;
1021         Key *k;
1022         enum {
1023                 Sectsz = 512,
1024                 Maxbuf = 32*Sectsz,
1025         };
1026
1027         if(off < 0 || l <= 0 || ((off|l) & (Sectsz-1)))
1028                 error(Ebadarg);
1029
1030         k = mp->extra;
1031         in = mp->inner[0];
1032         mc = in->idev;
1033         if(mc == nil)
1034                 error(Egone);
1035         off += 64*1024; // Header
1036         wb = l;
1037         if(wb > Maxbuf)
1038                 wb = Maxbuf;
1039         buf = smalloc(wb);
1040         if(waserror()) {
1041                 free(buf);
1042                 print("#k: %s: byte %,lld count %ld (of #k/%s): %s error: %s\n",
1043                         in->iname, off, l, mp->name, (isread? "read": "write"),
1044                         (up && up->errstr? up->errstr: ""));
1045                 nexterror();
1046         }
1047         for(ws = 0; ws < l; ws += wo){
1048                 wo = l - ws;
1049                 if(wo > wb)
1050                         wo = wb;
1051                 if (isread) {
1052                         wo = devtab[mc->type]->read(mc, buf, wo, off);
1053                         if(wo < Sectsz)
1054                                 break;
1055                         wo &= ~(Sectsz-1);
1056                         for(wl=0; wl<wo; wl+=Sectsz)
1057                                 aes_xts_decrypt(k->tweak.ekey, k->ecb.dkey, off+wl, buf+wl, a+wl, Sectsz);
1058                 } else {
1059                         for(wl=0; wl<wo; wl+=Sectsz)
1060                                 aes_xts_encrypt(k->tweak.ekey, k->ecb.ekey, off+wl, a+wl, buf+wl, Sectsz);
1061                         if(devtab[mc->type]->write(mc, buf, wo, off) != wo)
1062                                 error(Eio);
1063                 }
1064                 off += wo;
1065                 a += wo;
1066         }
1067         poperror();
1068         free(buf);
1069
1070         return ws;
1071 }
1072
1073 /* NB: a transfer could span multiple inner devices */
1074 static long
1075 catio(Fsdev *mp, int isread, void *a, long n, vlong off)
1076 {
1077         int     i;
1078         long    l, res;
1079         Inner   *in;
1080
1081         if(debug)
1082                 print("catio %d %p %ld %lld\n", isread, a, n, off);
1083         res = n;
1084         for (i = 0; n > 0 && i < mp->ndevs; i++){
1085                 in = mp->inner[i];
1086                 if (off >= in->isize){
1087                         off -= in->isize;
1088                         continue;               /* not there yet */
1089                 }
1090                 if (off + n > in->isize)
1091                         l = in->isize - off;
1092                 else
1093                         l = n;
1094                 if(debug)
1095                         print("\tdev %d %p %ld %lld\n", i, a, l, off);
1096
1097                 if (io(mp, in, isread, a, l, off) != l)
1098                         error(Eio);
1099
1100                 a = (char*)a + l;
1101                 off = 0;
1102                 n -= l;
1103         }
1104         if(debug)
1105                 print("\tres %ld\n", res - n);
1106         return res - n;
1107 }
1108
1109 static long
1110 interio(Fsdev *mp, int isread, void *a, long n, vlong off)
1111 {
1112         int     i;
1113         long    boff, res, l, wl, wsz;
1114         vlong   woff, blk, mblk;
1115
1116         blk  = off / Blksize;
1117         boff = off % Blksize;
1118         wsz  = Blksize - boff;
1119         res = n;
1120         while(n > 0){
1121                 mblk = blk / mp->ndevs;
1122                 i    = blk % mp->ndevs;
1123                 woff = mblk*Blksize + boff;
1124                 if (n > wsz)
1125                         l = wsz;
1126                 else
1127                         l = n;
1128
1129                 wl = io(mp, mp->inner[i], isread, a, l, woff);
1130                 if (wl != l)
1131                         error(Eio);
1132
1133                 blk++;
1134                 boff = 0;
1135                 wsz = Blksize;
1136                 a = (char*)a + l;
1137                 n -= l;
1138         }
1139         return res;
1140 }
1141
1142 static char*
1143 seprintconf(char *s, char *e)
1144 {
1145         int     i, j;
1146         Tree    *t;
1147
1148         *s = 0;
1149         for(i = 0; i < ntrees; i++){
1150                 t = trees[i];
1151                 if(t != nil)
1152                         for(j = 0; j < t->nadevs; j++)
1153                                 if(t->devs[j] != nil)
1154                                         s = seprintdev(s, e, t->devs[j]);
1155         }
1156         return s;
1157 }
1158
1159 static long
1160 mread(Chan *c, void *a, long n, vlong off)
1161 {
1162         int     i, retry;
1163         long    l, res;
1164         Fsdev   *mp;
1165         Tree    *t;
1166
1167         dprint("mread %llux\n", c->qid.path);
1168         rlock(&lck);
1169         if(waserror()){
1170                 runlock(&lck);
1171                 nexterror();
1172         }
1173         res = -1;
1174         if(c->qid.type & QTDIR){
1175                 res = devdirread(c, a, n, 0, 0, mgen);
1176                 goto Done;
1177         }
1178         if(c->qid.path == Qctl){
1179                 seprintconf(confstr, confstr + sizeof(confstr));
1180                 res = readstr((long)off, a, n, confstr);
1181                 goto Done;
1182         }
1183
1184         t = gettree(path2treeno(c->qid.path), Mustexist);
1185         mp = getdev(t, path2devno(c->qid.path) - Qfirst, Mustexist);
1186
1187         if(off >= mp->size){
1188                 res = 0;
1189                 goto Done;
1190         }
1191         if(off + n > mp->size)
1192                 n = mp->size - off;
1193         if(n == 0){
1194                 res = 0;
1195                 goto Done;
1196         }
1197
1198         switch(mp->type){
1199         case Fcat:
1200                 res = catio(mp, Isread, a, n, off);
1201                 break;
1202         case Finter:
1203                 res = interio(mp, Isread, a, n, off);
1204                 break;
1205         case Fpart:
1206                 res = io(mp, mp->inner[0], Isread, a, n, mp->start + off);
1207                 break;
1208         case Fmirror:
1209                 retry = 0;
1210                 do {
1211                         if (retry > 0) {
1212                                 print("#k/%s: retry %d read for byte %,lld "
1213                                         "count %ld: %s\n", mp->name, retry, off,
1214                                         n, (up && up->errstr? up->errstr: ""));
1215                                 /*
1216                                  * pause before retrying in case it's due to
1217                                  * a transient bus or controller problem.
1218                                  */
1219                                 tsleep(&up->sleep, return0, 0, Retrypause);
1220                         }
1221                         for (i = 0; i < mp->ndevs; i++){
1222                                 if (waserror())
1223                                         continue;
1224                                 l = io(mp, mp->inner[i], Isread, a, n, off);
1225                                 poperror();
1226                                 if (l >= 0){
1227                                         res = l;
1228                                         break;          /* read a good copy */
1229                                 }
1230                         }
1231                 } while (i == mp->ndevs && ++retry <= Maxretries);
1232                 if (retry > Maxretries) {
1233                         /* no mirror had a good copy of the block */
1234                         print("#k/%s: byte %,lld count %ld: CAN'T READ "
1235                                 "from mirror: %s\n", mp->name, off, n,
1236                                 (up && up->errstr? up->errstr: ""));
1237                         error(Eio);
1238                 } else if (retry > 0)
1239                         print("#k/%s: byte %,lld count %ld: retry read OK "
1240                                 "from mirror: %s\n", mp->name, off, n,
1241                                 (up && up->errstr? up->errstr: ""));
1242                 break;
1243         case Fcrypt:
1244                 res = cryptio(mp, Isread, a, n, off);
1245                 break;
1246         }
1247 Done:
1248         poperror();
1249         runlock(&lck);
1250         return res;
1251 }
1252
1253 static long
1254 mwrite(Chan *c, void *a, long n, vlong off)
1255 {
1256         int     i, allbad, anybad, retry;
1257         long    l, res;
1258         Fsdev   *mp;
1259         Tree    *t;
1260
1261         dprint("mwrite %llux\n", c->qid.path);
1262         if (c->qid.type & QTDIR)
1263                 error(Eisdir);
1264         if (c->qid.path == Qctl){
1265                 mconfig(a, n);
1266                 return n;
1267         }
1268
1269         rlock(&lck);
1270         if(waserror()){
1271                 runlock(&lck);
1272                 nexterror();
1273         }
1274
1275         t = gettree(path2treeno(c->qid.path), Mustexist);
1276         mp = getdev(t, path2devno(c->qid.path) - Qfirst, Mustexist);
1277
1278         if(off >= mp->size){
1279                 res = 0;
1280                 goto Done;
1281         }
1282         if(off + n > mp->size)
1283                 n = mp->size - off;
1284         if(n == 0){
1285                 res = 0;
1286                 goto Done;
1287         }
1288         res = n;
1289         switch(mp->type){
1290         case Fcat:
1291                 res = catio(mp, Iswrite, a, n, off);
1292                 break;
1293         case Finter:
1294                 res = interio(mp, Iswrite, a, n, off);
1295                 break;
1296         case Fpart:
1297                 res = io(mp, mp->inner[0], Iswrite, a, n, mp->start + off);
1298                 if (res != n)
1299                         error(Eio);
1300                 break;
1301         case Fmirror:
1302                 retry = 0;
1303                 do {
1304                         if (retry > 0) {
1305                                 print("#k/%s: retry %d write for byte %,lld "
1306                                         "count %ld: %s\n", mp->name, retry, off,
1307                                         n, (up && up->errstr? up->errstr: ""));
1308                                 /*
1309                                  * pause before retrying in case it's due to
1310                                  * a transient bus or controller problem.
1311                                  */
1312                                 tsleep(&up->sleep, return0, 0, Retrypause);
1313                         }
1314                         allbad = 1;
1315                         anybad = 0;
1316                         for (i = mp->ndevs - 1; i >= 0; i--){
1317                                 if (waserror()) {
1318                                         anybad = 1;
1319                                         continue;
1320                                 }
1321                                 l = io(mp, mp->inner[i], Iswrite, a, n, off);
1322                                 poperror();
1323                                 if (l == n)
1324                                         allbad = 0;     /* wrote a good copy */
1325                                 else
1326                                         anybad = 1;
1327                         }
1328                 } while (anybad && ++retry <= Maxretries);
1329                 if (allbad) {
1330                         /* no mirror took a good copy of the block */
1331                         print("#k/%s: byte %,lld count %ld: CAN'T WRITE "
1332                                 "to mirror: %s\n", mp->name, off, n,
1333                                 (up && up->errstr? up->errstr: ""));
1334                         error(Eio);
1335                 } else if (retry > 0)
1336                         print("#k/%s: byte %,lld count %ld: retry wrote OK "
1337                                 "to mirror: %s\n", mp->name, off, n,
1338                                 (up && up->errstr? up->errstr: ""));
1339
1340                 break;
1341         case Fcrypt:
1342                 res = cryptio(mp, Iswrite, a, n, off);
1343                 break;
1344         }
1345 Done:
1346         poperror();
1347         runlock(&lck);
1348         return res;
1349 }
1350
1351 Dev fsdevtab = {
1352         'k',
1353         "fs",
1354
1355         devreset,
1356         devinit,
1357         devshutdown,
1358         mattach,
1359         mwalk,
1360         mstat,
1361         mopen,
1362         devcreate,
1363         mclose,
1364         mread,
1365         devbread,
1366         mwrite,
1367         devbwrite,
1368         devremove,
1369         devwstat,
1370         devpower,
1371         devconfig,
1372 };