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