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