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 */ 7 8 #include "u.h" 9 #include "../port/lib.h" 10 #include "mem.h" 11 #include "dat.h" 12 #include "fns.h" 13 #include "io.h" 14 #include "ureg.h" 15 #include "../port/error.h" 16 17 enum { 18 Fmirror, /* mirror of others */ 19 Fcat, /* catenation of others */ 20 Finter, /* interleaving of others */ 21 Fpart, /* part of others */ 22 Fclear, /* start over */ 23 24 Blksize = 8*1024, /* for Finter only */ 25 26 Qtop = 0, /* top dir (contains "fs") */ 27 Qdir, /* actual dir */ 28 Qctl, /* ctl file */ 29 Qfirst, /* first fs file */ 30 31 /* tunable parameters */ 32 Maxconf = 4*1024, /* max length for config */ 33 Ndevs = 32, /* max. inner devs per command */ 34 Nfsdevs = 128, /* max. created devs, total */ 35 }; 36 37 #define Cfgstr "fsdev:\n" 38 39 typedef struct Fsdev Fsdev; 40 struct Fsdev 41 { 42 int type; 43 char *name; /* name for this fsdev */ 44 vlong start; /* start address (for Fpart) */ 45 vlong size; /* min(idev sizes) */ 46 int ndevs; /* number of inner devices */ 47 char *iname[Ndevs]; /* inner device names */ 48 Chan *idev[Ndevs]; /* inner devices */ 49 vlong isize[Ndevs]; /* sizes for inner devices */ 50 }; 51 52 extern Dev fsdevtab; /* forward */ 53 54 /* 55 * Once configured, a fsdev is never removed. The name of those 56 * configured is never nil. We have no locks here. 57 */ 58 static Fsdev fsdev[Nfsdevs]; 59 60 static Qid tqid = {Qtop, 0, QTDIR}; 61 static Qid dqid = {Qdir, 0, QTDIR}; 62 static Qid cqid = {Qctl, 0, 0}; 63 64 static Cmdtab configs[] = { 65 Fmirror,"mirror", 0, 66 Fcat, "cat", 0, 67 Finter, "inter", 0, 68 Fpart, "part", 5, 69 Fclear, "clear", 1, 70 }; 71 72 static char confstr[Maxconf]; 73 static int configed; 74 75 76 static Fsdev* 77 path2dev(int i, int mustexist) 78 { 79 if (i < 0 || i >= nelem(fsdev)) 80 error("bug: bad index in devfsdev"); 81 if (mustexist && fsdev[i].name == nil) 82 error(Enonexist); 83 84 if (fsdev[i].name == nil) 85 return nil; 86 else 87 return &fsdev[i]; 88 } 89 90 static Fsdev* 91 devalloc(void) 92 { 93 int i; 94 95 for (i = 0; i < nelem(fsdev); i++) 96 if (fsdev[i].name == nil) 97 break; 98 if (i == nelem(fsdev)) 99 error(Enodev); 100 101 return &fsdev[i]; 102 } 103 104 static void 105 setdsize(Fsdev* mp) 106 { 107 int i; 108 long l; 109 uchar buf[128]; /* old DIRLEN plus a little should be plenty */ 110 Chan *mc; 111 Dir d; 112 113 if (mp->type != Fpart){ 114 mp->start= 0; 115 mp->size = 0; 116 } 117 for (i = 0; i < mp->ndevs; i++){ 118 mc = mp->idev[i]; 119 l = devtab[mc->type]->stat(mc, buf, sizeof(buf)); 120 convM2D(buf, l, &d, nil); 121 mp->isize[i] = d.length; 122 switch(mp->type){ 123 case Fmirror: 124 if (mp->size == 0 || mp->size > d.length) 125 mp->size = d.length; 126 break; 127 case Fcat: 128 mp->size += d.length; 129 break; 130 case Finter: 131 /* truncate to multiple of Blksize */ 132 d.length &= ~(Blksize-1); 133 mp->isize[i] = d.length; 134 mp->size += d.length; 135 break; 136 case Fpart: 137 /* should raise errors here? */ 138 if (mp->start > d.length) 139 mp->start = d.length; 140 if (d.length < mp->start + mp->size) 141 mp->size = d.length - mp->start; 142 break; 143 } 144 } 145 } 146 147 static void 148 mpshut(Fsdev *mp) 149 { 150 int i; 151 char *nm; 152 153 nm = mp->name; 154 mp->name = nil; /* prevent others from using this. */ 155 if (nm) 156 free(nm); 157 for (i = 0; i < mp->ndevs; i++){ 158 if (mp->idev[i] != nil) 159 cclose(mp->idev[i]); 160 if (mp->iname[i]) 161 free(mp->iname[i]); 162 } 163 memset(mp, 0, sizeof(*mp)); 164 } 165 166 167 static void 168 mconfig(char* a, long n) /* "name idev0 idev1" */ 169 { 170 int i; 171 vlong size, start; 172 char *c, *oldc; 173 Cmdbuf *cb; 174 Cmdtab *ct; 175 Fsdev *mp; 176 static QLock lck; 177 178 size = 0; 179 start = 0; 180 if (confstr[0] == 0) 181 seprint(confstr, confstr + sizeof confstr, Cfgstr); 182 mp = nil; 183 cb = nil; 184 oldc = confstr + strlen(confstr); 185 if (*a == '\0' || *a == '#' || *a == '\n') 186 return; 187 188 qlock(&lck); 189 if (waserror()){ 190 *oldc = 0; 191 if (mp != nil) 192 mpshut(mp); 193 qunlock(&lck); 194 if (cb) 195 free(cb); 196 nexterror(); 197 } 198 199 cb = parsecmd(a, n); 200 c = oldc; 201 for (i = 0; i < cb->nf; i++) 202 c = seprint(c, confstr + sizeof confstr, "%s ", cb->f[i]); 203 if (c > confstr) 204 c[-1] = '\n'; 205 ct = lookupcmd(cb, configs, nelem(configs)); 206 cb->f++; /* skip command */ 207 cb->nf--; 208 if (cb->nf < 0) /* nothing to see here, move along */ 209 ct->index = -1; 210 switch (ct->index) { 211 case Fpart: 212 if (cb->nf < 4) 213 error("too few fields in fs config"); 214 start = strtoll(cb->f[2], nil, 10); 215 size = strtoll(cb->f[3], nil, 10); 216 cb->nf -= 2; 217 break; 218 case Fclear: 219 for (mp = fsdev; mp < fsdev + nelem(fsdev); mp++) 220 mpshut(mp); 221 *confstr = '\0'; 222 /* FALL THROUGH */ 223 case -1: 224 poperror(); 225 qunlock(&lck); 226 free(cb); 227 return; 228 } 229 if (cb->nf < 2) 230 error("too few fields in fs config"); 231 232 /* reject name if already in use */ 233 for (i = 0; i < nelem(fsdev); i++) 234 if (fsdev[i].name != nil && strcmp(fsdev[i].name, cb->f[0])==0) 235 error(Eexist); 236 237 if (cb->nf - 1 > Ndevs) 238 error("too many devices; fix me, increase Ndevs"); 239 for (i = 0; i < cb->nf; i++) 240 validname(cb->f[i], (i != 0)); 241 242 mp = devalloc(); 243 mp->type = ct->index; 244 if (mp->type == Fpart){ 245 mp->start = start; 246 mp->size = size; 247 } 248 kstrdup(&mp->name, cb->f[0]); 249 for (i = 1; i < cb->nf; i++){ 250 kstrdup(&mp->iname[i-1], cb->f[i]); 251 mp->idev[i-1] = namec(mp->iname[i-1], Aopen, ORDWR, 0); 252 if (mp->idev[i-1] == nil) 253 error(Egreg); 254 mp->ndevs++; 255 } 256 setdsize(mp); 257 configed = 1; 258 259 poperror(); 260 qunlock(&lck); 261 free(cb); 262 } 263 264 static void 265 rdconf(void) 266 { 267 int mustrd; 268 char *c, *e, *p, *s; 269 Chan *cc; 270 Chan **ccp; 271 272 s = getconf("fsconfig"); 273 if (s == nil){ 274 mustrd = 0; 275 s = "/dev/sdC0/fscfg"; 276 } else 277 mustrd = 1; 278 ccp = &cc; 279 *ccp = nil; 280 c = nil; 281 if (waserror()){ 282 configed = 1; 283 if (*ccp != nil) 284 cclose(*ccp); 285 if (c) 286 free(c); 287 if (!mustrd) 288 return; 289 nexterror(); 290 } 291 *ccp = namec(s, Aopen, OREAD, 0); 292 devtab[(*ccp)->type]->read(*ccp, confstr, sizeof confstr, 0); 293 cclose(*ccp); 294 *ccp = nil; 295 if (strncmp(confstr, Cfgstr, strlen(Cfgstr)) != 0) 296 error("Bad config, first line must be: 'fsdev:\\n'"); 297 kstrdup(&c, confstr + strlen(Cfgstr)); 298 memset(confstr, 0, sizeof confstr); 299 for (p = c; p != nil && *p != 0; p = e){ 300 e = strchr(p, '\n'); 301 if (e == nil) 302 e = p + strlen(p); 303 if (e == p) { 304 e++; 305 continue; 306 } 307 mconfig(p, e - p); 308 } 309 poperror(); 310 } 311 312 313 static int 314 mgen(Chan *c, char*, Dirtab*, int, int i, Dir *dp) 315 { 316 Qid qid; 317 Fsdev *mp; 318 319 if (c->qid.path == Qtop) 320 switch(i){ 321 case DEVDOTDOT: 322 devdir(c, tqid, "#k", 0, eve, DMDIR|0775, dp); 323 return 1; 324 case 0: 325 devdir(c, dqid, "fs", 0, eve, DMDIR|0775, dp); 326 return 1; 327 default: 328 return -1; 329 } 330 if (c->qid.path != Qdir) 331 switch(i){ 332 case DEVDOTDOT: 333 devdir(c, dqid, "fs", 0, eve, DMDIR|0775, dp); 334 return 1; 335 default: 336 return -1; 337 } 338 switch(i){ 339 case DEVDOTDOT: 340 devdir(c, tqid, "#k", 0, eve, DMDIR|0775, dp); 341 return 1; 342 case 0: 343 devdir(c, cqid, "ctl", 0, eve, 0664, dp); 344 return 1; 345 } 346 i--; /* for ctl */ 347 qid.path = Qfirst + i; 348 qid.vers = 0; 349 qid.type = 0; 350 mp = path2dev(i, 0); 351 if (mp == nil) 352 return -1; 353 kstrcpy(up->genbuf, mp->name, sizeof(up->genbuf)); 354 devdir(c, qid, up->genbuf, mp->size, eve, 0664, dp); 355 return 1; 356 } 357 358 static Chan* 359 mattach(char *spec) 360 { 361 *confstr = 0; 362 return devattach(fsdevtab.dc, spec); 363 } 364 365 static Walkqid* 366 mwalk(Chan *c, Chan *nc, char **name, int nname) 367 { 368 if (!configed) 369 rdconf(); 370 return devwalk(c, nc, name, nname, 0, 0, mgen); 371 } 372 373 static int 374 mstat(Chan *c, uchar *db, int n) 375 { 376 Dir d; 377 Fsdev *mp; 378 int p; 379 380 p = c->qid.path; 381 memset(&d, 0, sizeof d); 382 switch(p){ 383 case Qtop: 384 devdir(c, tqid, "#k", 0, eve, DMDIR|0775, &d); 385 break; 386 case Qdir: 387 devdir(c, dqid, "fs", 0, eve, DMDIR|0775, &d); 388 break; 389 case Qctl: 390 devdir(c, cqid, "ctl", 0, eve, 0664, &d); 391 break; 392 default: 393 mp = path2dev(p - Qfirst, 1); 394 devdir(c, c->qid, mp->name, mp->size, eve, 0664, &d); 395 } 396 n = convD2M(&d, db, n); 397 if (n == 0) 398 error(Ebadarg); 399 return n; 400 } 401 402 static Chan* 403 mopen(Chan *c, int omode) 404 { 405 if((c->qid.type & QTDIR) && omode != OREAD) 406 error(Eperm); 407 if (omode & OTRUNC) 408 omode &= ~OTRUNC; 409 c->mode = openmode(omode); 410 c->flag |= COPEN; 411 c->offset = 0; 412 return c; 413 } 414 415 static void 416 mclose(Chan*) 417 { 418 /* that's easy */ 419 } 420 421 static long 422 catio(Fsdev *mp, int isread, void *a, long n, vlong off) 423 { 424 int i; 425 Chan* mc; 426 long l, wl, res; 427 428 // print("catio %d %p %ld %lld\n", isread, a, n, off); 429 res = n; 430 for (i = 0; n >= 0 && i < mp->ndevs ; i++){ 431 mc = mp->idev[i]; 432 if (off > mp->isize[i]){ 433 off -= mp->isize[i]; 434 continue; 435 } 436 if (off + n > mp->isize[i]) 437 l = mp->isize[i] - off; 438 else 439 l = n; 440 // print("\tdev %d %p %ld %lld\n", i, a, l, off); 441 442 if (isread) 443 wl = devtab[mc->type]->read(mc, a, l, off); 444 else 445 wl = devtab[mc->type]->write(mc, a, l, off); 446 if (wl != l) 447 error("#k: write failed"); 448 a = (char*)a + l; 449 off = 0; 450 n -= l; 451 } 452 // print("\tres %ld\n", res - n); 453 return res - n; 454 } 455 456 static long 457 interio(Fsdev *mp, int isread, void *a, long n, vlong off) 458 { 459 int i; 460 long boff, res, l, wl, wsz; 461 vlong woff, blk, mblk; 462 Chan* mc; 463 464 blk = off / Blksize; 465 boff = off % Blksize; 466 wsz = Blksize - boff; 467 res = n; 468 while(n > 0){ 469 mblk = blk / mp->ndevs; 470 i = blk % mp->ndevs; 471 mc = mp->idev[i]; 472 woff = mblk*Blksize + boff; 473 if (n > wsz) 474 l = wsz; 475 else 476 l = n; 477 if (isread) 478 wl = devtab[mc->type]->read(mc, a, l, woff); 479 else 480 wl = devtab[mc->type]->write(mc, a, l, woff); 481 if (wl != l || l == 0) 482 error(Eio); 483 a = (char*)a + l; 484 n -= l; 485 blk++; 486 boff = 0; 487 wsz = Blksize; 488 } 489 return res; 490 } 491 492 static long 493 mread(Chan *c, void *a, long n, vlong off) 494 { 495 int i; 496 long l, res; 497 Chan *mc; 498 Fsdev *mp; 499 500 if (c->qid.type & QTDIR) 501 return devdirread(c, a, n, 0, 0, mgen); 502 if (c->qid.path == Qctl) 503 return readstr((long)off, a, n, confstr + strlen(Cfgstr)); 504 i = c->qid.path - Qfirst; 505 mp = path2dev(i, 1); 506 507 if (off >= mp->size) 508 return 0; 509 if (off + n > mp->size) 510 n = mp->size - off; 511 if (n == 0) 512 return 0; 513 514 res = -1; 515 switch(mp->type){ 516 case Fmirror: 517 for (i = 0; i < mp->ndevs; i++){ 518 mc = mp->idev[i]; 519 if (waserror()){ 520 /* 521 * if a read fails we let the user know and try 522 * another device. 523 */ 524 print("#k: mread: (%llx %d): %s\n", 525 c->qid.path, i, up->errstr); 526 continue; 527 } 528 l = devtab[mc->type]->read(mc, a, n, off); 529 poperror(); 530 if (l >= 0){ 531 res = l; 532 break; 533 } 534 } 535 if (i == mp->ndevs) 536 error(Eio); 537 break; 538 case Fcat: 539 res = catio(mp, 1, a, n, off); 540 break; 541 case Finter: 542 res = interio(mp, 1, a, n, off); 543 break; 544 case Fpart: 545 off += mp->start; 546 mc = mp->idev[0]; 547 res = devtab[mc->type]->read(mc, a, n, off); 548 break; 549 } 550 return res; 551 } 552 553 static long 554 mwrite(Chan *c, void *a, long n, vlong off) 555 { 556 int i; 557 long l, res; 558 Chan *mc; 559 Fsdev *mp; 560 561 if (c->qid.type & QTDIR) 562 error(Eperm); 563 if (c->qid.path == Qctl){ 564 mconfig(a, n); 565 return n; 566 } 567 mp = path2dev(c->qid.path - Qfirst, 1); 568 569 if (off >= mp->size) 570 return 0; 571 if (off + n > mp->size) 572 n = mp->size - off; 573 if (n == 0) 574 return 0; 575 res = n; 576 switch(mp->type){ 577 case Fmirror: 578 for (i = mp->ndevs - 1; i >= 0; i--){ 579 mc = mp->idev[i]; 580 l = devtab[mc->type]->write(mc, a, n, off); 581 if (l < res) 582 res = l; 583 } 584 break; 585 case Fcat: 586 res = catio(mp, 0, a, n, off); 587 break; 588 case Finter: 589 res = interio(mp, 0, a, n, off); 590 break; 591 case Fpart: 592 mc = mp->idev[0]; 593 off += mp->start; 594 l = devtab[mc->type]->write(mc, a, n, off); 595 if (l < res) 596 res = l; 597 break; 598 } 599 return res; 600 } 601 602 Dev fsdevtab = { 603 'k', 604 "devfs", 605 606 devreset, 607 devinit, 608 devshutdown, 609 mattach, 610 mwalk, 611 mstat, 612 mopen, 613 devcreate, 614 mclose, 615 mread, 616 devbread, 617 mwrite, 618 devbwrite, 619 devremove, 620 devwstat, 621 devpower, 622 devconfig, 623 }; 624