devfs.c 11 KB

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