devfs.c 11 KB

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