cache.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "../port/error.h"
  7. enum
  8. {
  9. NHASH = 128,
  10. MAXCACHE = 1024*1024,
  11. NFILE = 4096,
  12. NEXTENT = 200, /* extent allocation size */
  13. };
  14. typedef struct Extent Extent;
  15. struct Extent
  16. {
  17. int bid;
  18. ulong start;
  19. int len;
  20. Page *cache;
  21. Extent *next;
  22. };
  23. typedef struct Mntcache Mntcache;
  24. struct Mntcache
  25. {
  26. Qid qid;
  27. int dev;
  28. int type;
  29. QLock;
  30. Extent *list;
  31. Mntcache *hash;
  32. Mntcache *prev;
  33. Mntcache *next;
  34. };
  35. typedef struct Cache Cache;
  36. struct Cache
  37. {
  38. Lock;
  39. int pgno;
  40. Mntcache *head;
  41. Mntcache *tail;
  42. Mntcache *hash[NHASH];
  43. };
  44. typedef struct Ecache Ecache;
  45. struct Ecache
  46. {
  47. Lock;
  48. int total;
  49. int free;
  50. Extent* head;
  51. };
  52. static Image fscache;
  53. static Cache cache;
  54. static Ecache ecache;
  55. static int maxcache = MAXCACHE;
  56. static void
  57. extentfree(Extent* e)
  58. {
  59. lock(&ecache);
  60. e->next = ecache.head;
  61. ecache.head = e;
  62. ecache.free++;
  63. unlock(&ecache);
  64. }
  65. static Extent*
  66. extentalloc(void)
  67. {
  68. Extent *e;
  69. int i;
  70. lock(&ecache);
  71. if(ecache.head == nil){
  72. e = xalloc(NEXTENT*sizeof(Extent));
  73. if(e == nil){
  74. unlock(&ecache);
  75. return nil;
  76. }
  77. for(i = 0; i < NEXTENT; i++){
  78. e->next = ecache.head;
  79. ecache.head = e;
  80. e++;
  81. }
  82. ecache.free += NEXTENT;
  83. ecache.total += NEXTENT;
  84. }
  85. e = ecache.head;
  86. ecache.head = e->next;
  87. memset(e, 0, sizeof(Extent));
  88. ecache.free--;
  89. unlock(&ecache);
  90. return e;
  91. }
  92. void
  93. cinit(void)
  94. {
  95. int i;
  96. Mntcache *m;
  97. cache.head = xalloc(sizeof(Mntcache)*NFILE);
  98. m = cache.head;
  99. /* a better algorithm would be nice */
  100. // if(conf.npage*BY2PG > 200*MB)
  101. // maxcache = 10*MAXCACHE;
  102. // if(conf.npage*BY2PG > 400*MB)
  103. // maxcache = 50*MAXCACHE;
  104. for(i = 0; i < NFILE-1; i++) {
  105. m->next = m+1;
  106. m->prev = m-1;
  107. m++;
  108. }
  109. cache.tail = m;
  110. cache.tail->next = 0;
  111. cache.head->prev = 0;
  112. fscache.notext = 1;
  113. }
  114. void
  115. cprint(Chan *c, Mntcache *m, char *s)
  116. {
  117. ulong o;
  118. int nb, ct;
  119. Extent *e;
  120. nb = 0;
  121. ct = 1;
  122. o = 0;
  123. if(m->list)
  124. o = m->list->start;
  125. for(e = m->list; e; e = e->next) {
  126. nb += e->len;
  127. if(o != e->start)
  128. ct = 0;
  129. o = e->start+e->len;
  130. }
  131. pprint("%s: 0x%lux.0x%lux %d %d %s (%d %c)\n",
  132. s, m->qid.path, m->qid.vers, m->type, m->dev, c->path, nb, ct ? 'C' : 'N');
  133. for(e = m->list; e; e = e->next) {
  134. pprint("\t%4d %5d %4d %lux\n",
  135. e->bid, e->start, e->len, e->cache);
  136. }
  137. }
  138. Page*
  139. cpage(Extent *e)
  140. {
  141. /* Easy consistency check */
  142. if(e->cache->daddr != e->bid)
  143. return 0;
  144. return lookpage(&fscache, e->bid);
  145. }
  146. void
  147. cnodata(Mntcache *m)
  148. {
  149. Extent *e, *n;
  150. /*
  151. * Invalidate all extent data
  152. * Image lru will waste the pages
  153. */
  154. for(e = m->list; e; e = n) {
  155. n = e->next;
  156. extentfree(e);
  157. }
  158. m->list = 0;
  159. }
  160. void
  161. ctail(Mntcache *m)
  162. {
  163. /* Unlink and send to the tail */
  164. if(m->prev)
  165. m->prev->next = m->next;
  166. else
  167. cache.head = m->next;
  168. if(m->next)
  169. m->next->prev = m->prev;
  170. else
  171. cache.tail = m->prev;
  172. if(cache.tail) {
  173. m->prev = cache.tail;
  174. cache.tail->next = m;
  175. m->next = 0;
  176. cache.tail = m;
  177. }
  178. else {
  179. cache.head = m;
  180. cache.tail = m;
  181. m->prev = 0;
  182. m->next = 0;
  183. }
  184. }
  185. void
  186. copen(Chan *c)
  187. {
  188. int h;
  189. Extent *e, *next;
  190. Mntcache *m, *f, **l;
  191. /* directories aren't cacheable and append-only files confuse us */
  192. if(c->qid.type&(QTDIR|QTAPPEND))
  193. return;
  194. h = c->qid.path%NHASH;
  195. lock(&cache);
  196. for(m = cache.hash[h]; m; m = m->hash) {
  197. if(m->qid.path == c->qid.path)
  198. if(m->qid.type == c->qid.type)
  199. if(m->dev == c->dev && m->type == c->type) {
  200. c->mcp = m;
  201. ctail(m);
  202. unlock(&cache);
  203. /* File was updated, invalidate cache */
  204. if(m->qid.vers != c->qid.vers) {
  205. m->qid.vers = c->qid.vers;
  206. qlock(m);
  207. cnodata(m);
  208. qunlock(m);
  209. }
  210. return;
  211. }
  212. }
  213. /* LRU the cache headers */
  214. m = cache.head;
  215. l = &cache.hash[m->qid.path%NHASH];
  216. for(f = *l; f; f = f->hash) {
  217. if(f == m) {
  218. *l = m->hash;
  219. break;
  220. }
  221. l = &f->hash;
  222. }
  223. m->qid = c->qid;
  224. m->dev = c->dev;
  225. m->type = c->type;
  226. l = &cache.hash[h];
  227. m->hash = *l;
  228. *l = m;
  229. ctail(m);
  230. qlock(m);
  231. c->mcp = m;
  232. e = m->list;
  233. m->list = 0;
  234. unlock(&cache);
  235. while(e) {
  236. next = e->next;
  237. extentfree(e);
  238. e = next;
  239. }
  240. qunlock(m);
  241. }
  242. static int
  243. cdev(Mntcache *m, Chan *c)
  244. {
  245. if(m->qid.path != c->qid.path)
  246. return 0;
  247. if(m->qid.type != c->qid.type)
  248. return 0;
  249. if(m->dev != c->dev)
  250. return 0;
  251. if(m->type != c->type)
  252. return 0;
  253. if(m->qid.vers != c->qid.vers)
  254. return 0;
  255. return 1;
  256. }
  257. int
  258. cread(Chan *c, uchar *buf, int len, vlong off)
  259. {
  260. KMap *k;
  261. Page *p;
  262. Mntcache *m;
  263. Extent *e, **t;
  264. int o, l, total;
  265. ulong offset;
  266. if(off+len > maxcache)
  267. return 0;
  268. m = c->mcp;
  269. if(m == 0)
  270. return 0;
  271. qlock(m);
  272. if(cdev(m, c) == 0) {
  273. qunlock(m);
  274. return 0;
  275. }
  276. offset = off;
  277. t = &m->list;
  278. for(e = *t; e; e = e->next) {
  279. if(offset >= e->start && offset < e->start+e->len)
  280. break;
  281. t = &e->next;
  282. }
  283. if(e == 0) {
  284. qunlock(m);
  285. return 0;
  286. }
  287. total = 0;
  288. while(len) {
  289. p = cpage(e);
  290. if(p == 0) {
  291. *t = e->next;
  292. extentfree(e);
  293. qunlock(m);
  294. return total;
  295. }
  296. o = offset - e->start;
  297. l = len;
  298. if(l > e->len-o)
  299. l = e->len-o;
  300. k = kmap(p);
  301. if(waserror()) {
  302. kunmap(k);
  303. putpage(p);
  304. qunlock(m);
  305. nexterror();
  306. }
  307. memmove(buf, (uchar*)VA(k) + o, l);
  308. poperror();
  309. kunmap(k);
  310. putpage(p);
  311. buf += l;
  312. len -= l;
  313. offset += l;
  314. total += l;
  315. t = &e->next;
  316. e = e->next;
  317. if(e == 0 || e->start != offset)
  318. break;
  319. }
  320. qunlock(m);
  321. return total;
  322. }
  323. Extent*
  324. cchain(uchar *buf, ulong offset, int len, Extent **tail)
  325. {
  326. int l;
  327. Page *p;
  328. KMap *k;
  329. Extent *e, *start, **t;
  330. start = 0;
  331. *tail = 0;
  332. t = &start;
  333. while(len) {
  334. e = extentalloc();
  335. if(e == 0)
  336. break;
  337. p = auxpage();
  338. if(p == 0) {
  339. extentfree(e);
  340. break;
  341. }
  342. l = len;
  343. if(l > BY2PG)
  344. l = BY2PG;
  345. e->cache = p;
  346. e->start = offset;
  347. e->len = l;
  348. lock(&cache);
  349. e->bid = cache.pgno;
  350. cache.pgno += BY2PG;
  351. /* wrap the counter; low bits are unused by pghash but checked by lookpage */
  352. if((cache.pgno & ~(BY2PG-1)) == 0){
  353. if(cache.pgno == BY2PG-1){
  354. print("cache wrapped\n");
  355. cache.pgno = 0;
  356. }else
  357. cache.pgno++;
  358. }
  359. unlock(&cache);
  360. p->daddr = e->bid;
  361. k = kmap(p);
  362. if(waserror()) { /* buf may be virtual */
  363. kunmap(k);
  364. nexterror();
  365. }
  366. memmove((void*)VA(k), buf, l);
  367. poperror();
  368. kunmap(k);
  369. cachepage(p, &fscache);
  370. putpage(p);
  371. buf += l;
  372. offset += l;
  373. len -= l;
  374. *t = e;
  375. *tail = e;
  376. t = &e->next;
  377. }
  378. return start;
  379. }
  380. int
  381. cpgmove(Extent *e, uchar *buf, int boff, int len)
  382. {
  383. Page *p;
  384. KMap *k;
  385. p = cpage(e);
  386. if(p == 0)
  387. return 0;
  388. k = kmap(p);
  389. if(waserror()) { /* Since buf may be virtual */
  390. kunmap(k);
  391. nexterror();
  392. }
  393. memmove((uchar*)VA(k)+boff, buf, len);
  394. poperror();
  395. kunmap(k);
  396. putpage(p);
  397. return 1;
  398. }
  399. void
  400. cupdate(Chan *c, uchar *buf, int len, vlong off)
  401. {
  402. Mntcache *m;
  403. Extent *tail;
  404. Extent *e, *f, *p;
  405. int o, ee, eblock;
  406. ulong offset;
  407. if(off > maxcache || len == 0)
  408. return;
  409. m = c->mcp;
  410. if(m == 0)
  411. return;
  412. qlock(m);
  413. if(cdev(m, c) == 0) {
  414. qunlock(m);
  415. return;
  416. }
  417. /*
  418. * Find the insertion point
  419. */
  420. offset = off;
  421. p = 0;
  422. for(f = m->list; f; f = f->next) {
  423. if(f->start > offset)
  424. break;
  425. p = f;
  426. }
  427. /* trim if there is a successor */
  428. eblock = offset+len;
  429. if(f != 0 && eblock > f->start) {
  430. len -= (eblock - f->start);
  431. if(len <= 0) {
  432. qunlock(m);
  433. return;
  434. }
  435. }
  436. if(p == 0) { /* at the head */
  437. e = cchain(buf, offset, len, &tail);
  438. if(e != 0) {
  439. m->list = e;
  440. tail->next = f;
  441. }
  442. qunlock(m);
  443. return;
  444. }
  445. /* trim to the predecessor */
  446. ee = p->start+p->len;
  447. if(offset < ee) {
  448. o = ee - offset;
  449. len -= o;
  450. if(len <= 0) {
  451. qunlock(m);
  452. return;
  453. }
  454. buf += o;
  455. offset += o;
  456. }
  457. /* try and pack data into the predecessor */
  458. if(offset == ee && p->len < BY2PG) {
  459. o = len;
  460. if(o > BY2PG - p->len)
  461. o = BY2PG - p->len;
  462. if(cpgmove(p, buf, p->len, o)) {
  463. p->len += o;
  464. buf += o;
  465. len -= o;
  466. offset += o;
  467. if(len <= 0) {
  468. if(f && p->start + p->len > f->start) print("CACHE: p->start=%uld p->len=%d f->start=%uld\n", p->start, p->len, f->start);
  469. qunlock(m);
  470. return;
  471. }
  472. }
  473. }
  474. e = cchain(buf, offset, len, &tail);
  475. if(e != 0) {
  476. p->next = e;
  477. tail->next = f;
  478. }
  479. qunlock(m);
  480. }
  481. void
  482. cwrite(Chan* c, uchar *buf, int len, vlong off)
  483. {
  484. int o, eo;
  485. Mntcache *m;
  486. ulong eblock, ee;
  487. Extent *p, *f, *e, *tail;
  488. ulong offset;
  489. if(off > maxcache || len == 0)
  490. return;
  491. m = c->mcp;
  492. if(m == 0)
  493. return;
  494. qlock(m);
  495. if(cdev(m, c) == 0) {
  496. qunlock(m);
  497. return;
  498. }
  499. offset = off;
  500. m->qid.vers++;
  501. c->qid.vers++;
  502. p = 0;
  503. for(f = m->list; f; f = f->next) {
  504. if(f->start >= offset)
  505. break;
  506. p = f;
  507. }
  508. if(p != 0) {
  509. ee = p->start+p->len;
  510. eo = offset - p->start;
  511. /* pack in predecessor if there is space */
  512. if(offset <= ee && eo < BY2PG) {
  513. o = len;
  514. if(o > BY2PG - eo)
  515. o = BY2PG - eo;
  516. if(cpgmove(p, buf, eo, o)) {
  517. if(eo+o > p->len)
  518. p->len = eo+o;
  519. buf += o;
  520. len -= o;
  521. offset += o;
  522. }
  523. }
  524. }
  525. /* free the overlap -- it's a rare case */
  526. eblock = offset+len;
  527. while(f && f->start < eblock) {
  528. e = f->next;
  529. extentfree(f);
  530. f = e;
  531. }
  532. /* link the block (if any) into the middle */
  533. e = cchain(buf, offset, len, &tail);
  534. if(e != 0) {
  535. tail->next = f;
  536. f = e;
  537. }
  538. if(p == 0)
  539. m->list = f;
  540. else
  541. p->next = f;
  542. qunlock(m);
  543. }