disksim.c 11 KB

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