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