disksim.c 11 KB

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