]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devfs.c
pc kernel: fix wrong simd exception mask (fixes go bootstrap)
[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 "../port/sd.h"
25 #include <libsec.h>
26
27 enum
28 {
29         Fnone,
30         Fmirror,                /* mirror of others */
31         Fcat,                   /* catenation of others */
32         Finter,                 /* interleaving of others */
33         Fpart,                  /* part of other */
34         Fclear,                 /* start over */
35         Fdel,                   /* delete a configure device */
36         Fdisk,                  /* set default tree and sector sz*/
37         Fcrypt,                 /* encrypted device */
38
39         Sectorsz = 1,
40         Blksize = 8*1024,       /* for Finter only */
41         Cryptsectsz = 512,      /* for Fcrypt 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         Key     *key;           /* crypt key */
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         secfree(mp->key);
355         free(mp->name);
356         for(i = 0; i < mp->ndevs; i++){
357                 in = mp->inner[i];
358                 if(in->idev != nil)
359                         cclose(in->idev);
360                 free(in->iname);
361                 free(in);
362         }
363         free(mp);
364 }
365
366 /*
367  * Delete one or all devices in one or all trees.
368  */
369 static void
370 mdelctl(char *tname, char *dname)
371 {
372         int i, alldevs, alltrees, some;
373         Fsdev *mp;
374         Tree *t;
375
376         dprint("delctl %s\n", dname);
377         alldevs = strcmp(dname, "*") == 0;
378         alltrees = strcmp(tname, "*") == 0;
379         some = 0;
380 Again:
381         wlock(&lck);
382         for(i = 0; i < ntrees; i++){
383                 t = trees[i];
384                 if(t == nil)
385                         continue;
386                 if(alltrees == 0 && strcmp(t->name, tname) != 0)
387                         continue;
388                 for(i = 0; i < t->nadevs; i++){
389                         mp = t->devs[i];
390                         if(t->devs[i] == nil)
391                                 continue;
392                         if(alldevs == 0 && strcmp(mp->name, dname) != 0)
393                                 continue;
394                         /*
395                          * Careful: must close outside locks and that
396                          * may change the file tree we are looking at.
397                          */
398                         some++;
399                         mp->gone = 1;
400                         if(mp->ref == 0){
401                                 incref(mp);     /* keep it there */
402                                 wunlock(&lck);
403                                 mdeldev(mp);
404                                 goto Again;     /* tree can change */
405                         }
406                 }
407         }
408         wunlock(&lck);
409         if(some == 0 && alltrees == 0)
410                 error(Enonexist);
411 }
412
413 static void
414 setdsize(Fsdev* mp, vlong *ilen)
415 {
416         int     i;
417         vlong   inlen;
418         Inner   *in;
419
420         dprint("setdsize %s\n", mp->name);
421         for (i = 0; i < mp->ndevs; i++){
422                 in = mp->inner[i];
423                 in->isize = ilen[i];
424                 inlen = in->isize;
425                 switch(mp->type){
426                 case Finter:
427                         /* truncate to multiple of Blksize */
428                         inlen &= ~(Blksize-1);
429                         in->isize = inlen;
430                         /* fall through */
431                 case Fmirror:
432                         /* use size of smallest inner device */
433                         if (mp->size == 0 || mp->size > inlen)
434                                 mp->size = inlen;
435                         break;
436                 case Fcat:
437                         mp->size += inlen;
438                         break;
439                 case Fpart:
440                         if(mp->start > inlen)
441                                 error("partition starts after device end");
442                         if(inlen < mp->start + mp->size){
443                                 print("#k: %s: partition truncated from "
444                                         "%lld to %lld bytes\n", mp->name,
445                                         mp->size, inlen - mp->start);
446                                 mp->size = inlen - mp->start;
447                         }
448                         break;
449                 case Fcrypt:
450                         if(mp->start > inlen)
451                                 error("crypt starts after device end");
452                         mp->size = (inlen - mp->start) & ~((vlong)Cryptsectsz-1);
453                         break;
454                 }
455         }
456         if(mp->type == Finter)
457                 mp->size *= mp->ndevs;
458 }
459
460 static void
461 validdevname(Tree *t, char *dname)
462 {
463         int i;
464
465         for(i = 0; i < t->nadevs; i++)
466                 if(t->devs[i] != nil && strcmp(t->devs[i]->name, dname) == 0)
467                         error(Eexist);
468 }
469
470 static void
471 parseconfig(char *a, long n, Cmdbuf **cbp, Cmdtab **ctp)
472 {
473         Cmdbuf  *cb;
474         Cmdtab  *ct;
475
476         *cbp = cb = parsecmd(a, n);
477         *ctp = ct = lookupcmd(cb, configs, nelem(configs));
478
479         cb->f++;                        /* skip command */
480         cb->nf--;
481         switch(ct->index){
482         case Fmirror:
483         case Fcat:
484         case Finter:
485                 if(cb->nf < 2)
486                         error("too few arguments for ctl");
487                 if(cb->nf - 1 > Ndevs)
488                         error("too many devices in ctl");
489                 break;
490         case Fdisk:
491                 if(cb->nf < 1 || cb->nf > 3)
492                         error("ctl usage: disk name [sz dev]");
493                 break;
494         case Fpart:
495                 if(cb->nf != 4 && (cb->nf != 3 || source == nil))
496                         error("ctl usage: part new [file] off len");
497                 break;
498         case Fcrypt:
499                 if(cb->nf != 3)
500                         error("ctl usage: crypt newname device keyhex");
501                 break;
502         }
503 }
504
505 static void
506 parsename(char *name, char *disk, char **tree, char **dev)
507 {
508         char *slash;
509
510         slash = strchr(name, '/');
511         if(slash == nil){
512                 if(disk != nil)
513                         *tree = disk;
514                 else
515                         *tree = "fs";
516                 *dev = name;
517         }else{
518                 *tree = name;
519                 *slash++ = 0;
520                 *dev = slash;
521         }
522         validname(*tree, 0);
523         validname(*dev, 0);
524 }
525
526 static vlong
527 getlen(Chan *c)
528 {
529         uchar   buf[128];       /* old DIRLEN plus a little should be plenty */
530         Dir     d;
531         long    l;
532
533         l = devtab[c->type]->stat(c, buf, sizeof buf);
534         convM2D(buf, l, &d, nil);
535         return d.length;
536 }
537
538 /*
539  * Process a single line of configuration,
540  * often of the form "cmd newname idev0 idev1".
541  * locking is tricky, because we need a write lock to
542  * add/remove devices yet adding/removing them may lead
543  * to calls to this driver that require a read lock (when
544  * inner devices are also provided by us).
545  */
546 static void
547 mconfig(char* a, long n)
548 {
549         int     i;
550         vlong   size, start;
551         vlong   *ilen;
552         char    *tname, *dname, *fakef[4];
553         uchar   key[2*256/8];
554         int     keylen;
555         Chan    **idev;
556         Cmdbuf  *cb;
557         Cmdtab  *ct;
558         Fsdev   *mp;
559         Inner   *inprv;
560         Tree    *t;
561
562         /* ignore comments & empty lines */
563         if (*a == '\0' || *a == '#' || *a == '\n')
564                 return;
565
566         dprint("mconfig\n");
567         size = 0;
568         start = 0;
569         mp = nil;
570         cb = nil;
571         idev = nil;
572         ilen = nil;
573         keylen = 0;
574
575         if(waserror()){
576                 free(cb);
577                 nexterror();
578         }
579
580         parseconfig(a, n, &cb, &ct);
581         switch (ct->index) {
582         case Fdisk:
583                 kstrdup(&disk, cb->f[0]);
584                 if(cb->nf >= 2)
585                         sectorsz = strtoul(cb->f[1], 0, 0);
586                 else
587                         sectorsz = Sectorsz;
588                 if(cb->nf == 3)
589                         kstrdup(&source, cb->f[2]);
590                 else{
591                         free(source);
592                         source = nil;
593                 }
594                 poperror();
595                 free(cb);
596                 return;
597         case Fclear:
598                 poperror();
599                 free(cb);
600                 mdelctl("*", "*");              /* del everything */
601                 return;
602         case Fcrypt:
603                 if(cb->nf >= 4) {
604                         start = strtoul(cb->f[3], 0, 0);
605                         cb->nf = 3;
606                 } else
607                         start = 64*1024;        /* cryptsetup header */
608                 keylen = dec16(key, sizeof(key), cb->f[2], strlen(cb->f[2]));
609                 switch(keylen){
610                 default:
611                         error("bad hexkey");
612                 case 2*128/8:
613                 case 2*256/8:
614                         break;
615                 }
616                 cb->nf -= 1;
617                 break;
618         case Fpart:
619                 if(cb->nf == 3){
620                         /*
621                          * got a request in the format of sd(3),
622                          * pretend we got one in our format.
623                          * later we change end to be len.
624                          */
625                         fakef[0] = cb->f[0];
626                         fakef[1] = source;
627                         fakef[2] = cb->f[1];
628                         fakef[3] = cb->f[2];
629                         cb->f = fakef;
630                         cb->nf = 4;
631                 }
632                 start = strtoll(cb->f[2], nil, 10);
633                 size =  strtoll(cb->f[3], nil, 10);
634                 if(cb->f == fakef)
635                         size -= start;          /* it was end */
636                 cb->nf -= 2;
637                 break;
638         }
639         parsename(cb->f[0], disk, &tname, &dname);
640         for(i = 1; i < cb->nf; i++)
641                 validname(cb->f[i], 1);
642
643         if(ct->index == Fdel){
644                 mdelctl(tname, dname);
645                 poperror();
646                 free(cb);
647                 return;
648         }
649
650         /*
651          * Open all inner devices while we have only a read lock.
652          */
653         poperror();
654         rlock(&lck);
655         if(waserror()){
656                 runlock(&lck);
657 Fail:
658                 for(i = 1; i < cb->nf; i++)
659                         if(idev != nil && idev[i-1] != nil)
660                                 cclose(idev[i-1]);
661                 if(mp != nil)
662                         mdeldev(mp);
663                 free(idev);
664                 free(ilen);
665                 free(cb);
666                 nexterror();
667         }
668         idev = smalloc(sizeof(Chan*) * Ndevs);
669         ilen = smalloc(sizeof(vlong) * Ndevs);
670         for(i = 1; i < cb->nf; i++){
671                 idev[i-1] = namec(cb->f[i], Aopen, ORDWR, 0);
672                 ilen[i-1] = getlen(idev[i-1]);
673         }
674         poperror();
675         runlock(&lck);
676
677         /*
678          * Get a write lock and add the device if we can.
679          */
680         wlock(&lck);
681         if(waserror()){
682                 wunlock(&lck);
683                 goto Fail;
684         }
685
686         t = lookuptree(tname);
687         if(t != nil)
688                 validdevname(t, dname);
689         else{
690                 t = treealloc(tname);
691                 if(t == nil)
692                         error("no more trees");
693         }
694         mp = devalloc(t, dname);
695         if(mp == nil){
696                 if(t->ndevs == 0)       /* it was created for us */
697                         deltree(t);     /* but we will not mdeldev() */
698                 error(Enomem);
699         }
700
701         mp->type = ct->index;
702         if(mp->type == Fpart){
703                 mp->start = start * sectorsz;
704                 mp->size = size * sectorsz;
705         }
706         if(mp->type == Fcrypt) {
707                 Key *k = secalloc(sizeof(Key));
708                 setupAESstate(&k->tweak, &key[0], keylen/2, nil);
709                 setupAESstate(&k->ecb, &key[keylen/2], keylen/2, nil);
710                 memset(key, 0, sizeof(key));
711                 mp->key = k;
712                 mp->start = start;
713         }
714         for(i = 1; i < cb->nf; i++){
715                 inprv = mp->inner[i-1] = mallocz(sizeof(Inner), 1);
716                 if(inprv == nil)
717                         error(Enomem);
718                 mp->ndevs++;
719                 kstrdup(&inprv->iname, cb->f[i]);
720                 inprv->idev = idev[i-1];
721                 idev[i-1] = nil;
722         }
723         setdsize(mp, ilen);
724
725         poperror();
726         wunlock(&lck);
727         free(idev);
728         free(ilen);
729         free(cb);
730 }
731
732 static void
733 rdconf(void)
734 {
735         int mustrd;
736         char *c, *e, *p, *s;
737         Chan *cc;
738         static int configed;
739
740         /* only read config file once */
741         if (configed)
742                 return;
743         configed = 1;
744
745         dprint("rdconf\n");
746         /* add the std "fs" tree */
747         trees[0] = &fstree;
748         ntrees++;
749         fstree.name = "fs";
750
751         /* identify the config file */
752         s = getconf("fsconfig");
753         if (s == nil){
754                 mustrd = 0;
755                 s = "/dev/sdC0/fscfg";
756         } else
757                 mustrd = 1;
758
759         if(waserror()){
760                 if(!mustrd)
761                         return;
762                 nexterror();
763         }
764
765         /* read it */
766         cc = namec(s, Aopen, OREAD, 0);
767         if(waserror()){
768                 cclose(cc);
769                 nexterror();
770         }
771         devtab[cc->type]->read(cc, confstr, sizeof confstr, 0);
772         poperror();
773         cclose(cc);
774
775         /* validate, copy and erase config; mconfig will repopulate confstr */
776         if (strncmp(confstr, cfgstr, sizeof cfgstr - 1) != 0)
777                 error("bad #k config, first line must be: 'fsdev:\\n'");
778
779         c = nil;
780         kstrdup(&c, confstr + sizeof cfgstr - 1);
781         if(waserror()){
782                 free(c);
783                 nexterror();
784         }
785         memset(confstr, 0, sizeof confstr);
786         /* process config copy one line at a time */
787         for (p = c; p != nil && *p != '\0'; p = e){
788                 e = strchr(p, '\n');
789                 if (e == nil)
790                         e = p + strlen(p);
791                 else
792                         e++;
793                 mconfig(p, e - p);
794         }
795         poperror();
796         free(c);
797
798         poperror();     /* mustrd */
799 }
800
801 static int
802 mgen(Chan *c, char*, Dirtab*, int, int i, Dir *dp)
803 {
804         int     treeno;
805         Fsdev   *mp;
806         Qid     qid;
807         Tree    *t;
808
809         dprint("mgen %#ullx %d\n", c->qid.path, i);
810         qid.type = QTDIR;
811         qid.vers = 0;
812         if(c->qid.path == Qtop){
813                 if(i == DEVDOTDOT){
814                         devdir(c, tqid, "#k", 0, eve, DMDIR|0775, dp);
815                         return 1;
816                 }
817                 t = gettree(i, Optional);
818                 if(t == nil){
819                         dprint("no\n");
820                         return -1;
821                 }
822                 qid.path = mkpath(i, Qdir);
823                 devdir(c, qid, t->name, 0, eve, DMDIR|0775, dp);
824                 return 1;
825         }
826
827         treeno = path2treeno(c->qid.path);
828         t = gettree(treeno, Optional);
829         if(t == nil){
830                 dprint("no\n");
831                 return -1;
832         }
833         if((c->qid.type & QTDIR) != 0){
834                 if(i == DEVDOTDOT){
835                         devdir(c, tqid, "#k", 0, eve, DMDIR|0775, dp);
836                         return 1;
837                 }
838                 if(treeno == 0){
839                         /* take care of #k/fs/ctl */
840                         if(i == 0){
841                                 devdir(c, cqid, "ctl", 0, eve, 0664, dp);
842                                 return 1;
843                         }
844                         i--;
845                 }
846                 mp = getdev(t, i, Optional);
847                 if(mp == nil){
848                         dprint("no\n");
849                         return -1;
850                 }
851                 qid.type = QTFILE;
852                 qid.vers = mp->vers;
853                 qid.path = mkpath(treeno, Qfirst+i);
854                 devdir(c, qid, mp->name, mp->size, eve, 0664, dp);
855                 return 1;
856         }
857
858         if(i == DEVDOTDOT){
859                 qid.path = mkpath(treeno, Qdir);
860                 devdir(c, qid, t->name, 0, eve, DMDIR|0775, dp);
861                 return 1;
862         }
863         dprint("no\n");
864         return -1;
865 }
866
867 static Chan*
868 mattach(char *spec)
869 {
870         dprint("mattach\n");
871         return devattach(fsdevtab.dc, spec);
872 }
873
874 static Walkqid*
875 mwalk(Chan *c, Chan *nc, char **name, int nname)
876 {
877         Walkqid *wq;
878
879         rdconf();
880
881         dprint("mwalk %llux\n", c->qid.path);
882         rlock(&lck);
883         if(waserror()){
884                 runlock(&lck);
885                 nexterror();
886         }
887         wq = devwalk(c, nc, name, nname, 0, 0, mgen);
888         poperror();
889         runlock(&lck);
890         return wq;
891 }
892
893 static int
894 mstat(Chan *c, uchar *db, int n)
895 {
896         int     p;
897         Dir     d;
898         Fsdev   *mp;
899         Qid     q;
900         Tree    *t;
901
902         dprint("mstat %llux\n", c->qid.path);
903         rlock(&lck);
904         if(waserror()){
905                 runlock(&lck);
906                 nexterror();
907         }
908         p = c->qid.path;
909         memset(&d, 0, sizeof d);
910         switch(p){
911         case Qtop:
912                 devdir(c, tqid, "#k", 0, eve, DMDIR|0775, &d);
913                 break;
914         case Qctl:
915                 devdir(c, cqid, "ctl", 0, eve, 0664, &d);
916                 break;
917         default:
918                 t = gettree(path2treeno(p), Mustexist);
919                 if(c->qid.type & QTDIR)
920                         devdir(c, c->qid, t->name, 0, eve, DMDIR|0775, &d);
921                 else{
922                         mp = getdev(t, path2devno(p) - Qfirst, Mustexist);
923                         q = c->qid;
924                         q.vers = mp->vers;
925                         devdir(c, q, mp->name, mp->size, eve, 0664, &d);
926                 }
927         }
928         n = convD2M(&d, db, n);
929         if (n == 0)
930                 error(Ebadarg);
931         poperror();
932         runlock(&lck);
933         return n;
934 }
935
936 static Chan*
937 mopen(Chan *c, int omode)
938 {
939         int     q;
940         Fsdev   *mp;
941
942         dprint("mopen %llux\n", c->qid.path);
943         if((c->qid.type & QTDIR) && omode != OREAD)
944                 error(Eperm);
945         if(c->qid.path != Qctl && (c->qid.type&QTDIR) == 0){
946                 rlock(&lck);
947                 if(waserror()){
948                         runlock(&lck);
949                         nexterror();
950                 }
951                 q = c->qid.path;
952                 mp = path2dev(q);
953                 if(mp->gone)
954                         error(Egone);
955                 incref(mp);
956                 poperror();
957                 runlock(&lck);
958         }
959         /*
960          * Our mgen does not return the info for the qid
961          * but only for its children. Don't use devopen here.
962          */
963         c->offset = 0;
964         c->mode = openmode(omode);
965         c->flag |= COPEN;
966         return c;
967 }
968
969 static void
970 mclose(Chan *c)
971 {
972         int     mustdel, q;
973         Fsdev   *mp;
974
975         dprint("mclose %llux\n", c->qid.path);
976         if(c->qid.type & QTDIR || !(c->flag & COPEN))
977                 return;
978         rlock(&lck);
979         if(waserror()){
980                 runlock(&lck);
981                 nexterror();
982         }
983         mustdel = 0;
984         mp = nil;
985         q = c->qid.path;
986         if(q == Qctl){
987                 free(disk);
988                 disk = nil;     /* restore defaults */
989                 free(source);
990                 source = nil;
991                 sectorsz = Sectorsz;
992         }else{
993                 mp = path2dev(q);
994                 if(mp->gone != 0 && mp->ref == 1)
995                         mustdel = 1;
996                 else
997                         decref(mp);
998         }
999         poperror();
1000         runlock(&lck);
1001         if(mustdel)
1002                 mdeldev(mp);
1003 }
1004
1005 static long
1006 io(Fsdev *mp, Inner *in, int isread, void *a, long l, vlong off)
1007 {
1008         long wl;
1009         Chan    *mc;
1010
1011         mc = in->idev;
1012         if(mc == nil)
1013                 error(Egone);
1014         if (waserror()) {
1015                 print("#k: %s: byte %,lld count %ld (of #k/%s): %s error: %s\n",
1016                         in->iname, off, l, mp->name, (isread? "read": "write"),
1017                         (up && up->errstr? up->errstr: ""));
1018                 nexterror();
1019         }
1020         if (isread)
1021                 wl = devtab[mc->type]->read(mc, a, l, off);
1022         else
1023                 wl = devtab[mc->type]->write(mc, a, l, off);
1024         poperror();
1025         return wl;
1026 }
1027
1028 static long
1029 cryptio(Fsdev *mp, int isread, uchar *a, long n, vlong off)
1030 {
1031         long l, m, o, nb;
1032         uchar *b;
1033
1034         if((((ulong)off|n) & (Cryptsectsz-1)))
1035                 error(Ebadarg);
1036         if(isread){
1037                 l = io(mp, mp->inner[0], Isread, a, n, off);
1038                 if(l > 0){
1039                         l &= ~(Cryptsectsz-1);
1040                         for(o=0; o<l; o+=Cryptsectsz)
1041                                 aes_xts_decrypt(&mp->key->tweak, &mp->key->ecb,
1042                                         off+o, a+o, a+o, Cryptsectsz);
1043                 }
1044                 return l;
1045         }
1046         nb = n < SDmaxio ? n : SDmaxio;
1047         while((b = sdmalloc(nb)) == nil){
1048                 if(!waserror()){
1049                         resrcwait("no memory for cryptio");
1050                         poperror();
1051                 }
1052         }
1053         if(waserror()) {
1054                 sdfree(b);
1055                 nexterror();
1056         }
1057         for(l = 0; (m = n - l) > 0; l += m){
1058                 if(m > nb) m = nb;
1059                 for(o=0; o<m; o+=Cryptsectsz)
1060                         aes_xts_encrypt(&mp->key->tweak, &mp->key->ecb,
1061                                 off+o, a+o, b+o, Cryptsectsz);
1062                 if(io(mp, mp->inner[0], Iswrite, b, m, off) != m)
1063                         error(Eio);
1064                 off += m;
1065                 a += m;
1066         }
1067         sdfree(b);
1068         poperror();
1069         return l;
1070 }
1071
1072 /* NB: a transfer could span multiple inner devices */
1073 static long
1074 catio(Fsdev *mp, int isread, void *a, long n, vlong off)
1075 {
1076         int     i;
1077         long    l, res;
1078         Inner   *in;
1079
1080         if(debug)
1081                 print("catio %d %p %ld %lld\n", isread, a, n, off);
1082         res = n;
1083         for (i = 0; n > 0 && i < mp->ndevs; i++){
1084                 in = mp->inner[i];
1085                 if (off >= in->isize){
1086                         off -= in->isize;
1087                         continue;               /* not there yet */
1088                 }
1089                 if (off + n > in->isize)
1090                         l = in->isize - off;
1091                 else
1092                         l = n;
1093                 if(debug)
1094                         print("\tdev %d %p %ld %lld\n", i, a, l, off);
1095
1096                 if (io(mp, in, isread, a, l, off) != l)
1097                         error(Eio);
1098
1099                 a = (char*)a + l;
1100                 off = 0;
1101                 n -= l;
1102         }
1103         if(debug)
1104                 print("\tres %ld\n", res - n);
1105         return res - n;
1106 }
1107
1108 static long
1109 interio(Fsdev *mp, int isread, void *a, long n, vlong off)
1110 {
1111         int     i;
1112         long    boff, res, l, wl, wsz;
1113         vlong   woff, blk, mblk;
1114
1115         blk  = off / Blksize;
1116         boff = off % Blksize;
1117         wsz  = Blksize - boff;
1118         res = n;
1119         while(n > 0){
1120                 mblk = blk / mp->ndevs;
1121                 i    = blk % mp->ndevs;
1122                 woff = mblk*Blksize + boff;
1123                 if (n > wsz)
1124                         l = wsz;
1125                 else
1126                         l = n;
1127
1128                 wl = io(mp, mp->inner[i], isread, a, l, woff);
1129                 if (wl != l)
1130                         error(Eio);
1131
1132                 blk++;
1133                 boff = 0;
1134                 wsz = Blksize;
1135                 a = (char*)a + l;
1136                 n -= l;
1137         }
1138         return res;
1139 }
1140
1141 static char*
1142 seprintconf(char *s, char *e)
1143 {
1144         int     i, j;
1145         Tree    *t;
1146
1147         *s = 0;
1148         for(i = 0; i < ntrees; i++){
1149                 t = trees[i];
1150                 if(t != nil)
1151                         for(j = 0; j < t->nadevs; j++)
1152                                 if(t->devs[j] != nil)
1153                                         s = seprintdev(s, e, t->devs[j]);
1154         }
1155         return s;
1156 }
1157
1158 static long
1159 mread(Chan *c, void *a, long n, vlong off)
1160 {
1161         int     i, retry;
1162         long    l, res;
1163         Fsdev   *mp;
1164         Tree    *t;
1165
1166         dprint("mread %llux\n", c->qid.path);
1167         rlock(&lck);
1168         if(waserror()){
1169                 runlock(&lck);
1170                 nexterror();
1171         }
1172         res = -1;
1173         if(c->qid.type & QTDIR){
1174                 res = devdirread(c, a, n, 0, 0, mgen);
1175                 goto Done;
1176         }
1177         if(c->qid.path == Qctl){
1178                 seprintconf(confstr, confstr + sizeof(confstr));
1179                 res = readstr((long)off, a, n, confstr);
1180                 goto Done;
1181         }
1182
1183         t = gettree(path2treeno(c->qid.path), Mustexist);
1184         mp = getdev(t, path2devno(c->qid.path) - Qfirst, Mustexist);
1185
1186         if(off >= mp->size){
1187                 res = 0;
1188                 goto Done;
1189         }
1190         if(off + n > mp->size)
1191                 n = mp->size - off;
1192         if(n == 0){
1193                 res = 0;
1194                 goto Done;
1195         }
1196
1197         switch(mp->type){
1198         case Fcat:
1199                 res = catio(mp, Isread, a, n, off);
1200                 break;
1201         case Finter:
1202                 res = interio(mp, Isread, a, n, off);
1203                 break;
1204         case Fpart:
1205                 res = io(mp, mp->inner[0], Isread, a, n, mp->start + off);
1206                 break;
1207         case Fmirror:
1208                 retry = 0;
1209                 do {
1210                         if (retry > 0) {
1211                                 print("#k/%s: retry %d read for byte %,lld "
1212                                         "count %ld: %s\n", mp->name, retry, off,
1213                                         n, (up && up->errstr? up->errstr: ""));
1214                                 /*
1215                                  * pause before retrying in case it's due to
1216                                  * a transient bus or controller problem.
1217                                  */
1218                                 tsleep(&up->sleep, return0, 0, Retrypause);
1219                         }
1220                         for (i = 0; i < mp->ndevs; i++){
1221                                 if (waserror())
1222                                         continue;
1223                                 l = io(mp, mp->inner[i], Isread, a, n, off);
1224                                 poperror();
1225                                 if (l >= 0){
1226                                         res = l;
1227                                         break;          /* read a good copy */
1228                                 }
1229                         }
1230                 } while (i == mp->ndevs && ++retry <= Maxretries);
1231                 if (retry > Maxretries) {
1232                         /* no mirror had a good copy of the block */
1233                         print("#k/%s: byte %,lld count %ld: CAN'T READ "
1234                                 "from mirror: %s\n", mp->name, off, n,
1235                                 (up && up->errstr? up->errstr: ""));
1236                         error(Eio);
1237                 } else if (retry > 0)
1238                         print("#k/%s: byte %,lld count %ld: retry read OK "
1239                                 "from mirror: %s\n", mp->name, off, n,
1240                                 (up && up->errstr? up->errstr: ""));
1241                 break;
1242         case Fcrypt:
1243                 res = cryptio(mp, Isread, a, n, mp->start + off);
1244                 break;
1245         }
1246 Done:
1247         poperror();
1248         runlock(&lck);
1249         return res;
1250 }
1251
1252 static long
1253 mwrite(Chan *c, void *a, long n, vlong off)
1254 {
1255         int     i, allbad, anybad, retry;
1256         long    l, res;
1257         Fsdev   *mp;
1258         Tree    *t;
1259
1260         dprint("mwrite %llux\n", c->qid.path);
1261         if (c->qid.type & QTDIR)
1262                 error(Eisdir);
1263         if (c->qid.path == Qctl){
1264                 mconfig(a, n);
1265                 return n;
1266         }
1267
1268         rlock(&lck);
1269         if(waserror()){
1270                 runlock(&lck);
1271                 nexterror();
1272         }
1273
1274         t = gettree(path2treeno(c->qid.path), Mustexist);
1275         mp = getdev(t, path2devno(c->qid.path) - Qfirst, Mustexist);
1276
1277         if(off >= mp->size){
1278                 res = 0;
1279                 goto Done;
1280         }
1281         if(off + n > mp->size)
1282                 n = mp->size - off;
1283         if(n == 0){
1284                 res = 0;
1285                 goto Done;
1286         }
1287         res = n;
1288         switch(mp->type){
1289         case Fcat:
1290                 res = catio(mp, Iswrite, a, n, off);
1291                 break;
1292         case Finter:
1293                 res = interio(mp, Iswrite, a, n, off);
1294                 break;
1295         case Fpart:
1296                 res = io(mp, mp->inner[0], Iswrite, a, n, mp->start + off);
1297                 if (res != n)
1298                         error(Eio);
1299                 break;
1300         case Fmirror:
1301                 retry = 0;
1302                 do {
1303                         if (retry > 0) {
1304                                 print("#k/%s: retry %d write for byte %,lld "
1305                                         "count %ld: %s\n", mp->name, retry, off,
1306                                         n, (up && up->errstr? up->errstr: ""));
1307                                 /*
1308                                  * pause before retrying in case it's due to
1309                                  * a transient bus or controller problem.
1310                                  */
1311                                 tsleep(&up->sleep, return0, 0, Retrypause);
1312                         }
1313                         allbad = 1;
1314                         anybad = 0;
1315                         for (i = mp->ndevs - 1; i >= 0; i--){
1316                                 if (waserror()) {
1317                                         anybad = 1;
1318                                         continue;
1319                                 }
1320                                 l = io(mp, mp->inner[i], Iswrite, a, n, off);
1321                                 poperror();
1322                                 if (l == n)
1323                                         allbad = 0;     /* wrote a good copy */
1324                                 else
1325                                         anybad = 1;
1326                         }
1327                 } while (anybad && ++retry <= Maxretries);
1328                 if (allbad) {
1329                         /* no mirror took a good copy of the block */
1330                         print("#k/%s: byte %,lld count %ld: CAN'T WRITE "
1331                                 "to mirror: %s\n", mp->name, off, n,
1332                                 (up && up->errstr? up->errstr: ""));
1333                         error(Eio);
1334                 } else if (retry > 0)
1335                         print("#k/%s: byte %,lld count %ld: retry wrote OK "
1336                                 "to mirror: %s\n", mp->name, off, n,
1337                                 (up && up->errstr? up->errstr: ""));
1338
1339                 break;
1340         case Fcrypt:
1341                 res = cryptio(mp, Iswrite, a, n, mp->start + off);
1342                 break;
1343         }
1344 Done:
1345         poperror();
1346         runlock(&lck);
1347         return res;
1348 }
1349
1350 Dev fsdevtab = {
1351         'k',
1352         "fs",
1353
1354         devreset,
1355         devinit,
1356         devshutdown,
1357         mattach,
1358         mwalk,
1359         mstat,
1360         mopen,
1361         devcreate,
1362         mclose,
1363         mread,
1364         devbread,
1365         mwrite,
1366         devbwrite,
1367         devremove,
1368         devwstat,
1369         devpower,
1370         devconfig,
1371 };