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