disksim.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <fcall.h>
  5. #include <thread.h>
  6. #include <9p.h>
  7. typedef struct Part Part;
  8. typedef struct Trip Trip;
  9. typedef struct Dbl Dbl;
  10. typedef struct Ind Ind;
  11. /*
  12. * with 8192-byte blocks and 4-byte pointers,
  13. * double-indirect gets us 34 GB.
  14. * triple-indirect gets us 70,368 GB.
  15. */
  16. enum
  17. {
  18. LOGBLKSZ = 13,
  19. BLKSZ = 1<<LOGBLKSZ, /* 8192 */
  20. LOGNPTR = LOGBLKSZ-2, /* assume sizeof(void*) == 4 */
  21. NPTR = 1<<LOGNPTR,
  22. };
  23. struct Trip
  24. {
  25. Dbl *dbl[NPTR];
  26. };
  27. struct Dbl
  28. {
  29. Ind *ind[NPTR];
  30. };
  31. struct Ind
  32. {
  33. uchar *blk[NPTR];
  34. };
  35. Trip trip;
  36. struct Part
  37. {
  38. int inuse;
  39. int vers;
  40. ulong mode;
  41. char *name;
  42. vlong offset; /* in sectors */
  43. vlong length; /* in sectors */
  44. };
  45. enum
  46. {
  47. Qroot = 0,
  48. Qdir,
  49. Qctl,
  50. Qpart,
  51. };
  52. Part tab[64];
  53. char *sdname = "sdXX";
  54. ulong ctlmode = 0666;
  55. char *inquiry = "aux/disksim hard drive";
  56. vlong nsect, sectsize, c, h, s;
  57. ulong time0;
  58. char*
  59. ctlstring(void)
  60. {
  61. int i;
  62. Fmt fmt;
  63. fmtstrinit(&fmt);
  64. fmtprint(&fmt, "inquiry %s\n", inquiry);
  65. fmtprint(&fmt, "geometry %lld %lld %lld %lld %lld\n", nsect, sectsize, c, h, s);
  66. for(i=0; i<nelem(tab); i++)
  67. if(tab[i].inuse)
  68. fmtprint(&fmt, "part %s %lld %lld\n", tab[i].name, tab[i].offset, tab[i].length);
  69. return fmtstrflush(&fmt);
  70. }
  71. int
  72. addpart(char *name, vlong start, vlong end)
  73. {
  74. int i;
  75. if(start < 0 || start > end || end > nsect){
  76. werrstr("bad partition boundaries");
  77. return -1;
  78. }
  79. for(i=0; i<nelem(tab); i++)
  80. if(tab[i].inuse == 0)
  81. break;
  82. if(i == nelem(tab)){
  83. werrstr("no free partition slots");
  84. return -1;
  85. }
  86. free(tab[i].name);
  87. tab[i].inuse = 1;
  88. tab[i].name = estrdup9p(name);
  89. tab[i].offset = start;
  90. tab[i].length = end - start;
  91. tab[i].mode = ctlmode;
  92. tab[i].vers++;
  93. return 0;
  94. }
  95. int
  96. delpart(char *s)
  97. {
  98. int i;
  99. for(i=0; i<nelem(tab); i++)
  100. if(tab[i].inuse && strcmp(tab[i].name, s) == 0)
  101. break;
  102. if(i==nelem(tab)){
  103. werrstr("partition not found");
  104. return -1;
  105. }
  106. tab[i].inuse = 0;
  107. free(tab[i].name);
  108. tab[i].name = 0;
  109. return 0;
  110. }
  111. void
  112. ctlwrite(Req *r)
  113. {
  114. int i;
  115. Cmdbuf *cb;
  116. vlong start, end;
  117. r->ofcall.count = r->ifcall.count;
  118. cb = parsecmd(r->ifcall.data, r->ifcall.count);
  119. if(cb->nf < 1){
  120. respond(r, "empty control message");
  121. free(cb);
  122. return;
  123. }
  124. if(strcmp(cb->f[0], "part") == 0){
  125. if(cb->nf != 4){
  126. respondcmderror(r, cb, "part takes 3 args");
  127. free(cb);
  128. return;
  129. }
  130. start = strtoll(cb->f[2], 0, 0);
  131. end = strtoll(cb->f[3], 0, 0);
  132. if(addpart(cb->f[1], start, end) < 0){
  133. respondcmderror(r, cb, "%r");
  134. free(cb);
  135. return;
  136. }
  137. }
  138. else if(strcmp(cb->f[0], "delpart") == 0){
  139. if(cb->nf != 2){
  140. respondcmderror(r, cb, "delpart takes 1 arg");
  141. free(cb);
  142. return;
  143. }
  144. if(delpart(cb->f[1]) < 0){
  145. respondcmderror(r, cb, "%r");
  146. free(cb);
  147. return;
  148. }
  149. }
  150. else if(strcmp(cb->f[0], "inquiry") == 0){
  151. if(cb->nf != 2){
  152. respondcmderror(r, cb, "inquiry takes 1 arg");
  153. free(cb);
  154. return;
  155. }
  156. free(inquiry);
  157. inquiry = estrdup9p(cb->f[1]);
  158. }
  159. else if(strcmp(cb->f[0], "geometry") == 0){
  160. if(cb->nf != 6){
  161. respondcmderror(r, cb, "geometry takes 5 args");
  162. free(cb);
  163. return;
  164. }
  165. nsect = strtoll(cb->f[1], 0, 0);
  166. sectsize = strtoll(cb->f[2], 0, 0);
  167. c = strtoll(cb->f[3], 0, 0);
  168. h = strtoll(cb->f[4], 0, 0);
  169. s = strtoll(cb->f[5], 0, 0);
  170. if(tab[0].inuse && strcmp(tab[0].name, "data") == 0 && tab[0].vers == 0){
  171. tab[0].offset = 0;
  172. tab[0].length = nsect;
  173. }
  174. for(i=0; i<nelem(tab); i++){
  175. if(tab[i].inuse && tab[i].offset+tab[i].length > nsect){
  176. tab[i].inuse = 0;
  177. free(tab[i].name);
  178. tab[i].name = 0;
  179. }
  180. }
  181. }
  182. else{
  183. respondcmderror(r, cb, "unknown control message");
  184. free(cb);
  185. return;
  186. }
  187. free(cb);
  188. respond(r, nil);
  189. }
  190. void*
  191. allocblk(void)
  192. {
  193. uchar *op;
  194. static uchar *p;
  195. static ulong n;
  196. if(n == 0){
  197. p = malloc(4*1024*1024);
  198. if(p == 0)
  199. sysfatal("out of memory");
  200. n = 4*1024*1024;
  201. }
  202. op = p;
  203. p += BLKSZ;
  204. n -= BLKSZ;
  205. memset(op, 0, BLKSZ);
  206. return op;
  207. }
  208. uchar*
  209. getblock(vlong addr, int alloc)
  210. {
  211. static uchar zero[BLKSZ];
  212. Dbl *p2;
  213. Ind *p1;
  214. uchar *p0;
  215. uint i0, i1, i2;
  216. addr >>= LOGBLKSZ;
  217. i0 = addr & (NPTR-1);
  218. addr >>= LOGNPTR;
  219. i1 = addr & (NPTR-1);
  220. addr >>= LOGNPTR;
  221. i2 = addr & (NPTR-1);
  222. addr >>= LOGNPTR;
  223. assert(addr == 0);
  224. if((p2 = trip.dbl[i2]) == 0){
  225. if(!alloc)
  226. return zero;
  227. trip.dbl[i2] = p2 = allocblk();
  228. }
  229. if((p1 = p2->ind[i1]) == 0){
  230. if(!alloc)
  231. return zero;
  232. p2->ind[i1] = p1 = allocblk();
  233. }
  234. if((p0 = p1->blk[i0]) == 0){
  235. if(!alloc)
  236. return zero;
  237. p1->blk[i0] = p0 = allocblk();
  238. }
  239. return p0;
  240. }
  241. int
  242. rootgen(int off, Dir *d, void*)
  243. {
  244. memset(d, 0, sizeof *d);
  245. d->atime = time0;
  246. d->mtime = time0;
  247. if(off == 0){
  248. d->name = estrdup9p(sdname);
  249. d->mode = DMDIR|0777;
  250. d->qid.path = Qdir;
  251. d->qid.type = QTDIR;
  252. d->uid = estrdup9p("disksim");
  253. d->gid = estrdup9p("disksim");
  254. d->muid = estrdup9p("");
  255. return 0;
  256. }
  257. return -1;
  258. }
  259. int
  260. dirgen(int off, Dir *d, void*)
  261. {
  262. int n, j;
  263. memset(d, 0, sizeof *d);
  264. d->atime = time0;
  265. d->mtime = time0;
  266. if(off == 0){
  267. d->name = estrdup9p("ctl");
  268. d->mode = ctlmode;
  269. d->qid.path = Qctl;
  270. goto Have;
  271. }
  272. off--;
  273. n = 0;
  274. for(j=0; j<nelem(tab); j++){
  275. if(tab[j].inuse==0)
  276. continue;
  277. if(n == off){
  278. d->name = estrdup9p(tab[j].name);
  279. d->length = tab[j].length*sectsize;
  280. d->mode = tab[j].mode;
  281. d->qid.path = Qpart+j;
  282. d->qid.vers = tab[j].vers;
  283. goto Have;
  284. }
  285. n++;
  286. }
  287. return -1;
  288. Have:
  289. d->uid = estrdup9p("disksim");
  290. d->gid = estrdup9p("disksim");
  291. d->muid = estrdup9p("");
  292. return 0;
  293. }
  294. void*
  295. evommem(void *a, void *b, ulong n)
  296. {
  297. return memmove(b, a, n);
  298. }
  299. int
  300. rdwrpart(Req *r)
  301. {
  302. int q;
  303. Part *p;
  304. vlong offset;
  305. long count, tot, n, o;
  306. uchar *blk, *dat;
  307. void *(*move)(void*, void*, ulong);
  308. q = r->fid->qid.path-Qpart;
  309. if(q < 0 || q > nelem(tab) || !tab[q].inuse || tab[q].vers != r->fid->qid.vers){
  310. respond(r, "unknown partition");
  311. return -1;
  312. }
  313. p = &tab[q];
  314. offset = r->ifcall.offset;
  315. count = r->ifcall.count;
  316. if(offset < 0){
  317. respond(r, "negative offset");
  318. return -1;
  319. }
  320. if(count < 0){
  321. respond(r, "negative count");
  322. return -1;
  323. }
  324. if(offset > p->length*sectsize){
  325. respond(r, "offset past end of partition");
  326. return -1;
  327. }
  328. if(offset+count > p->length*sectsize)
  329. count = p->length*sectsize - offset;
  330. offset += p->offset*sectsize;
  331. if(r->ifcall.type == Tread)
  332. move = memmove;
  333. else
  334. move = evommem;
  335. tot = 0;
  336. if(r->ifcall.type == Tread)
  337. dat = (uchar*)r->ofcall.data;
  338. else
  339. dat = (uchar*)r->ifcall.data;
  340. o = offset & (BLKSZ-1);
  341. /* left fringe block */
  342. if(o && count){
  343. blk = getblock(offset, r->ifcall.type==Twrite);
  344. if(blk == nil)
  345. abort();
  346. n = BLKSZ - o;
  347. if(n > count)
  348. n = count;
  349. (*move)(dat, blk+o, n);
  350. tot += n;
  351. }
  352. /* full and right fringe blocks */
  353. while(tot < count){
  354. blk = getblock(offset+tot, r->ifcall.type==Twrite);
  355. if(blk == nil)
  356. abort();
  357. n = BLKSZ;
  358. if(n > count)
  359. n = count;
  360. (*move)(dat+tot, blk, n);
  361. tot += n;
  362. }
  363. r->ofcall.count = tot;
  364. respond(r, nil);
  365. return 0;
  366. }
  367. void
  368. fsread(Req *r)
  369. {
  370. char *s;
  371. switch((int)r->fid->qid.path){
  372. case Qroot:
  373. dirread9p(r, rootgen, nil);
  374. respond(r, nil);
  375. break;
  376. case Qdir:
  377. dirread9p(r, dirgen, nil);
  378. respond(r, nil);
  379. break;
  380. case Qctl:
  381. s = ctlstring();
  382. readstr(r, s);
  383. free(s);
  384. respond(r, nil);
  385. break;
  386. default:
  387. rdwrpart(r);
  388. break;
  389. }
  390. }
  391. void
  392. fswrite(Req *r)
  393. {
  394. switch((int)r->fid->qid.path){
  395. case Qroot:
  396. case Qdir:
  397. respond(r, "write to a directory?");
  398. break;
  399. case Qctl:
  400. ctlwrite(r);
  401. break;
  402. default:
  403. rdwrpart(r);
  404. break;
  405. }
  406. }
  407. void
  408. fsopen(Req *r)
  409. {
  410. if(r->ifcall.mode&ORCLOSE)
  411. respond(r, "cannot open ORCLOSE");
  412. switch((int)r->fid->qid.path){
  413. case Qroot:
  414. case Qdir:
  415. if(r->ifcall.mode != OREAD){
  416. respond(r, "bad mode for directory open");
  417. return;
  418. }
  419. }
  420. respond(r, nil);
  421. }
  422. void
  423. fsstat(Req *r)
  424. {
  425. int q;
  426. Dir *d;
  427. Part *p;
  428. d = &r->d;
  429. memset(d, 0, sizeof *d);
  430. d->qid = r->fid->qid;
  431. d->atime = d->mtime = time0;
  432. q = r->fid->qid.path;
  433. switch(q){
  434. case Qroot:
  435. d->name = estrdup9p("/");
  436. d->mode = DMDIR|0777;
  437. break;
  438. case Qdir:
  439. d->name = estrdup9p(sdname);
  440. d->mode = DMDIR|0777;
  441. break;
  442. default:
  443. q -= Qpart;
  444. if(q < 0 || q > nelem(tab) || tab[q].inuse==0 || r->fid->qid.vers != tab[q].vers){
  445. respond(r, "partition no longer exists");
  446. return;
  447. }
  448. p = &tab[q];
  449. d->name = estrdup9p(p->name);
  450. d->length = p->length * sectsize;
  451. d->mode = p->mode;
  452. break;
  453. }
  454. d->uid = estrdup9p("disksim");
  455. d->gid = estrdup9p("disksim");
  456. d->muid = estrdup9p("");
  457. respond(r, nil);
  458. }
  459. void
  460. fsattach(Req *r)
  461. {
  462. char *spec;
  463. spec = r->ifcall.aname;
  464. if(spec && spec[0]){
  465. respond(r, "invalid attach specifier");
  466. return;
  467. }
  468. r->ofcall.qid = (Qid){Qroot, 0, QTDIR};
  469. r->fid->qid = r->ofcall.qid;
  470. respond(r, nil);
  471. }
  472. char*
  473. fswalk1(Fid *fid, char *name, Qid *qid)
  474. {
  475. int i;
  476. switch((int)fid->qid.path){
  477. case Qroot:
  478. if(strcmp(name, sdname) == 0){
  479. fid->qid.path = Qdir;
  480. fid->qid.type = QTDIR;
  481. *qid = fid->qid;
  482. return nil;
  483. }
  484. break;
  485. case Qdir:
  486. if(strcmp(name, "ctl") == 0){
  487. fid->qid.path = Qctl;
  488. fid->qid.vers = 0;
  489. fid->qid.type = 0;
  490. *qid = fid->qid;
  491. return nil;
  492. }
  493. for(i=0; i<nelem(tab); i++){
  494. if(tab[i].inuse && strcmp(tab[i].name, name) == 0){
  495. fid->qid.path = i+Qpart;
  496. fid->qid.vers = tab[i].vers;
  497. fid->qid.type = 0;
  498. *qid = fid->qid;
  499. return nil;
  500. }
  501. }
  502. break;
  503. }
  504. return "file not found";
  505. }
  506. Srv fs = {
  507. .attach= fsattach,
  508. .open= fsopen,
  509. .read= fsread,
  510. .write= fswrite,
  511. .stat= fsstat,
  512. .walk1= fswalk1,
  513. };
  514. char *mtpt = "/dev";
  515. char *srvname;
  516. void
  517. usage(void)
  518. {
  519. fprint(2, "usage: aux/disksim [-D] [-s srvname] [-m mtpt] [sdXX]\n");
  520. fprint(2, "\tdefault mtpt is /dev\n");
  521. exits("usage");
  522. }
  523. void
  524. main(int argc, char **argv)
  525. {
  526. quotefmtinstall();
  527. time0 = time(0);
  528. if(NPTR != BLKSZ/sizeof(void*))
  529. sysfatal("unexpected pointer size");
  530. ARGBEGIN{
  531. case 'D':
  532. chatty9p++;
  533. break;
  534. case 's':
  535. srvname = EARGF(usage());
  536. break;
  537. case 'm':
  538. mtpt = EARGF(usage());
  539. break;
  540. default:
  541. usage();
  542. }ARGEND
  543. if(argc > 1)
  544. usage();
  545. if(argc == 1)
  546. sdname = argv[0];
  547. inquiry = estrdup9p(inquiry);
  548. tab[0].name = estrdup9p("data");
  549. tab[0].inuse = 1;
  550. tab[0].mode = 0666;
  551. postmountsrv(&fs, srvname, mtpt, MBEFORE);
  552. exits(nil);
  553. }