bcache.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #include <u.h>
  2. #include <libc.h>
  3. #include "cformat.h"
  4. #include "lru.h"
  5. #include "bcache.h"
  6. int
  7. bcinit(Bcache *bc, int f, int bsize)
  8. {
  9. Bbuf *b;
  10. /*
  11. * allocate space for all buffers
  12. * point all buffers into outer space
  13. */
  14. bc->dfirst = 0;
  15. bc->bsize = bsize;
  16. bc->f = f;
  17. lruinit(bc);
  18. for(b = bc->bb; b < &bc->bb[Nbcache]; b++){
  19. b->inuse = 0;
  20. b->next = 0;
  21. b->dirty = 0;
  22. if(b->data == 0)
  23. b->data = (char *)malloc(bc->bsize);
  24. if(b->data == 0)
  25. return -1;
  26. lruadd(bc, b);
  27. }
  28. return 0;
  29. }
  30. /*
  31. * Find a buffer for block b. If it's dirty, write it out.
  32. */
  33. Bbuf *
  34. bcfind(Bcache *bc, ulong bno)
  35. {
  36. Bbuf *b;
  37. if(bno == Notabno)
  38. error("bcfind: Notabno");
  39. bno &= ~Indbno;
  40. /*
  41. * if we already have a buffer for this bno, use it
  42. */
  43. for(b = bc->bb; b < &bc->bb[Nbcache]; b++){
  44. if(b->inuse && b->bno==bno)
  45. goto out;
  46. }
  47. /*
  48. * get least recently used block
  49. */
  50. b = (Bbuf*)bc->lnext;
  51. out:
  52. /*
  53. * if dirty, write it out
  54. */
  55. if(b->dirty){
  56. if(bcwrite(bc, b) < 0)
  57. warning("writing dirty page");
  58. }
  59. lruref(bc, b);
  60. return b;
  61. }
  62. /*
  63. * allocate a buffer block for a block. it's guaranteed to be there till
  64. * the next Nbcache bcread's.
  65. */
  66. Bbuf *
  67. bcalloc(Bcache *bc, ulong bno)
  68. {
  69. Bbuf *b;
  70. b = bcfind(bc, bno);
  71. bno &= ~Indbno;
  72. b->bno = bno;
  73. b->inuse = 1;
  74. return b;
  75. }
  76. /*
  77. * read a block into a buffer cache. it's guaranteed to be there till
  78. * the next Nbcache bcread's.
  79. */
  80. Bbuf *
  81. bcread(Bcache *bc, ulong bno)
  82. {
  83. Bbuf *b;
  84. b = bcfind(bc, bno);
  85. bno &= ~Indbno;
  86. if(b->bno!=bno || !b->inuse){
  87. /*
  88. * read in the one we really want
  89. */
  90. if(bread(bc, bno, b->data) < 0){
  91. b->inuse = 0;
  92. return 0;
  93. }
  94. }
  95. b->bno = bno;
  96. b->inuse = 1;
  97. return b;
  98. }
  99. /*
  100. * mark a page dirty, if it's already dirty force a write
  101. *
  102. * N.B: ordering is important.
  103. */
  104. void
  105. bcmark(Bcache *bc, Bbuf *b)
  106. {
  107. lruref(bc, b);
  108. if(b->dirty){
  109. bcwrite(bc, b);
  110. return;
  111. }
  112. b->dirty = 1;
  113. if(bc->dfirst)
  114. bc->dlast->next = b;
  115. else
  116. bc->dfirst = b;
  117. bc->dlast = b;
  118. }
  119. /*
  120. * write out a page (and all preceeding dirty ones)
  121. */
  122. int
  123. bcwrite(Bcache *bc, Bbuf *b)
  124. {
  125. Bbuf *nb;
  126. /*
  127. * write out all preceeding pages
  128. */
  129. while(nb = bc->dfirst){
  130. if(bwrite(bc, nb->bno, nb->data) < 0)
  131. return -1;
  132. nb->dirty = 0;
  133. bc->dfirst = nb->next;
  134. nb->next = 0;
  135. if(nb == b)
  136. return 0;
  137. }
  138. /*
  139. * write out this page
  140. */
  141. if(bwrite(bc, b->bno, b->data) < 0)
  142. return -1;
  143. b->dirty = 0;
  144. b->next = 0;
  145. return 0;
  146. }
  147. /*
  148. * write out all dirty pages (in order)
  149. */
  150. int
  151. bcsync(Bcache *bc)
  152. {
  153. if(bc->dfirst)
  154. return bcwrite(bc, bc->dlast);
  155. return 0;
  156. }
  157. /*
  158. * read a block from disk
  159. */
  160. int
  161. bread(Bcache *bc, ulong bno, void *buf)
  162. {
  163. ulong x = bno*bc->bsize;
  164. if(pread(bc->f, buf, bc->bsize, x) != bc->bsize)
  165. return -1;
  166. return 0;
  167. }
  168. /*
  169. * write a block to disk
  170. */
  171. int
  172. bwrite(Bcache *bc, ulong bno, void *buf)
  173. {
  174. ulong x = bno*bc->bsize;
  175. if(pwrite(bc->f, buf, bc->bsize, x) != bc->bsize)
  176. return -1;
  177. return 0;
  178. }