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 Ndevs = 64, 28 Nfsdevs = 2*Ndevs, 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 inner 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, increase Ndevs"); 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 if (c->qid.path != Qdir) 306 switch(i){ 307 case DEVDOTDOT: 308 devdir(c, dqid, "fs", 0, eve, DMDIR|0775, dp); 309 return 1; 310 default: 311 return -1; 312 } 313 switch(i){ 314 case DEVDOTDOT: 315 devdir(c, tqid, "#k", 0, eve, DMDIR|0775, dp); 316 return 1; 317 case 0: 318 devdir(c, cqid, "ctl", 0, eve, 0664, dp); 319 return 1; 320 } 321 i--; /* for ctl */ 322 qid.path = Qfirst + i; 323 qid.vers = 0; 324 qid.type = 0; 325 mp = path2dev(i, 0); 326 if (mp == nil) 327 return -1; 328 kstrcpy(up->genbuf, mp->name, sizeof(up->genbuf)); 329 devdir(c, qid, up->genbuf, mp->size, eve, 0664, dp); 330 return 1; 331 } 332 333 static Chan* 334 mattach(char *spec) 335 { 336 *confstr = 0; 337 return devattach(L'k', spec); 338 } 339 340 static Walkqid* 341 mwalk(Chan *c, Chan *nc, char **name, int nname) 342 { 343 if (!configed) 344 rdconf(); 345 return devwalk(c, nc, name, nname, 0, 0, mgen); 346 } 347 348 static int 349 mstat(Chan *c, uchar *db, int n) 350 { 351 Dir d; 352 Fsdev *mp; 353 int p; 354 355 p = c->qid.path; 356 memset(&d, 0, sizeof(d)); 357 switch(p){ 358 case Qtop: 359 devdir(c, tqid, "#k", 0, eve, DMDIR|0775, &d); 360 break; 361 case Qdir: 362 devdir(c, dqid, "fs", 0, eve, DMDIR|0775, &d); 363 break; 364 case Qctl: 365 devdir(c, cqid, "ctl", 0, eve, 0664, &d); 366 break; 367 default: 368 mp = path2dev(p - Qfirst, 1); 369 devdir(c, c->qid, mp->name, mp->size, eve, 0664, &d); 370 } 371 n = convD2M(&d, db, n); 372 if (n == 0) 373 error(Ebadarg); 374 return n; 375 } 376 377 static Chan* 378 mopen(Chan *c, int omode) 379 { 380 if((c->qid.type & QTDIR) && omode != OREAD) 381 error(Eperm); 382 if (omode & OTRUNC) 383 omode &= ~OTRUNC; 384 c->mode = openmode(omode); 385 c->flag |= COPEN; 386 c->offset = 0; 387 return c; 388 } 389 390 static void 391 mclose(Chan*) 392 { 393 /* that's easy */ 394 } 395 396 static long 397 catio(Fsdev *mp, int isread, void *a, long n, vlong off) 398 { 399 int i; 400 Chan* mc; 401 long l, wl, res; 402 403 // print("catio %d %p %ld %lld\n", isread, a, n, off); 404 res = n; 405 for (i = 0; n >= 0 && i < mp->ndevs ; i++){ 406 mc = mp->idev[i]; 407 if (off > mp->isize[i]){ 408 off -= mp->isize[i]; 409 continue; 410 } 411 if (off + n > mp->isize[i]) 412 l = mp->isize[i] - off; 413 else 414 l = n; 415 // print("\tdev %d %p %ld %lld\n", i, a, l, off); 416 417 if (isread) 418 wl = devtab[mc->type]->read(mc, a, l, off); 419 else 420 wl = devtab[mc->type]->write(mc, a, l, off); 421 if (wl != l) 422 error("#k: write failed"); 423 a = (char*)a + l; 424 off = 0; 425 n -= l; 426 } 427 // print("\tres %ld\n", res - n); 428 return res - n; 429 } 430 431 static long 432 interio(Fsdev *mp, int isread, void *a, long n, vlong off) 433 { 434 int i; 435 Chan* mc; 436 long l, wl, wsz; 437 vlong woff, blk, mblk; 438 long boff, res; 439 440 blk = off / Blksize; 441 boff = off % Blksize; 442 wsz = Blksize - boff; 443 res = n; 444 while(n > 0){ 445 i = blk % mp->ndevs; 446 mc = mp->idev[i]; 447 mblk = blk / mp->ndevs; 448 woff = mblk * Blksize + boff; 449 if (n > wsz) 450 l = wsz; 451 else 452 l = n; 453 if (isread) 454 wl = devtab[mc->type]->read(mc, a, l, woff); 455 else 456 wl = devtab[mc->type]->write(mc, a, l, woff); 457 if (wl != l || l == 0) 458 error(Eio); 459 a = (char*)a + l; 460 n -= l; 461 blk++; 462 boff = 0; 463 wsz = Blksize; 464 } 465 return res; 466 } 467 468 static long 469 mread(Chan *c, void *a, long n, vlong off) 470 { 471 int i; 472 Fsdev *mp; 473 Chan *mc; 474 long l; 475 long res; 476 477 if (c->qid.type & QTDIR) 478 return devdirread(c, a, n, 0, 0, mgen); 479 if (c->qid.path == Qctl) 480 return readstr((long)off, a, n, confstr + strlen(Cfgstr)); 481 i = c->qid.path - Qfirst; 482 mp = path2dev(i, 1); 483 484 if (off >= mp->size) 485 return 0; 486 if (off + n > mp->size) 487 n = mp->size - off; 488 if (n == 0) 489 return 0; 490 491 res = -1; 492 switch(mp->type){ 493 case Fmirror: 494 for (i = 0; i < mp->ndevs; i++){ 495 mc = mp->idev[i]; 496 if (waserror()){ 497 /* 498 * if a read fails we let the user know and try 499 * another device. 500 */ 501 print("#k: mread: (%llx %d): %s\n", 502 c->qid.path, i, up->errstr); 503 continue; 504 } 505 l = devtab[mc->type]->read(mc, a, n, off); 506 poperror(); 507 if (l >= 0){ 508 res = l; 509 break; 510 } 511 } 512 if (i == mp->ndevs) 513 error(Eio); 514 break; 515 case Fcat: 516 res = catio(mp, 1, a, n, off); 517 break; 518 case Finter: 519 res = interio(mp, 1, a, n, off); 520 break; 521 case Fpart: 522 off += mp->start; 523 mc = mp->idev[0]; 524 res = devtab[mc->type]->read(mc, a, n, off); 525 break; 526 } 527 return res; 528 } 529 530 static long 531 mwrite(Chan *c, void *a, long n, vlong off) 532 { 533 Fsdev *mp; 534 long l, res; 535 int i; 536 Chan *mc; 537 538 if (c->qid.type & QTDIR) 539 error(Eperm); 540 if (c->qid.path == Qctl){ 541 mconfig(a, n); 542 return n; 543 } 544 mp = path2dev(c->qid.path - Qfirst, 1); 545 546 if (off >= mp->size) 547 return 0; 548 if (off + n > mp->size) 549 n = mp->size - off; 550 if (n == 0) 551 return 0; 552 res = n; 553 switch(mp->type){ 554 case Fmirror: 555 for (i = mp->ndevs-1; i >=0; i--){ 556 mc = mp->idev[i]; 557 l = devtab[mc->type]->write(mc, a, n, off); 558 if (l < res) 559 res = l; 560 } 561 break; 562 case Fcat: 563 res = catio(mp, 0, a, n, off); 564 break; 565 case Finter: 566 res = interio(mp, 0, a, n, off); 567 break; 568 case Fpart: 569 mc = mp->idev[0]; 570 off += mp->start; 571 l = devtab[mc->type]->write(mc, a, n, off); 572 if (l < res) 573 res = l; 574 break; 575 } 576 return res; 577 } 578 579 Dev fsdevtab = { 580 'k', 581 "devfs", 582 583 devreset, 584 devinit, 585 devshutdown, 586 mattach, 587 mwalk, 588 mstat, 589 mopen, 590 devcreate, 591 mclose, 592 mread, 593 devbread, 594 mwrite, 595 devbwrite, 596 devremove, 597 devwstat, 598 devpower, 599 devconfig, 600 }; 601