bcache.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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. * get least recently used block
  48. */
  49. b = (Bbuf*)bc->lnext;
  50. out:
  51. /*
  52. * if dirty, write it out
  53. */
  54. if(b->dirty)
  55. if(bcwrite(bc, b) < 0)
  56. warning("writing dirty page");
  57. lruref(bc, b);
  58. return b;
  59. }
  60. /*
  61. * allocate a buffer block for a block. it's guaranteed to be there till
  62. * the next Nbcache bcread's.
  63. */
  64. Bbuf *
  65. bcalloc(Bcache *bc, ulong bno)
  66. {
  67. Bbuf *b;
  68. b = bcfind(bc, bno);
  69. bno &= ~Indbno;
  70. b->bno = bno;
  71. b->inuse = 1;
  72. return b;
  73. }
  74. /*
  75. * read a block into a buffer cache. it's guaranteed to be there till
  76. * the next Nbcache bcread's.
  77. */
  78. Bbuf *
  79. bcread(Bcache *bc, ulong bno)
  80. {
  81. Bbuf *b;
  82. b = bcfind(bc, bno);
  83. bno &= ~Indbno;
  84. if(b->bno!=bno || !b->inuse)
  85. /*
  86. * read in the one we really want
  87. */
  88. if(bread(bc, bno, b->data) < 0){
  89. b->inuse = 0;
  90. return 0;
  91. }
  92. b->bno = bno;
  93. b->inuse = 1;
  94. return b;
  95. }
  96. /*
  97. * mark a page dirty, if it's already dirty force a write
  98. *
  99. * N.B: ordering is important.
  100. */
  101. void
  102. bcmark(Bcache *bc, Bbuf *b)
  103. {
  104. lruref(bc, b);
  105. if(b->dirty){
  106. bcwrite(bc, b);
  107. return;
  108. }
  109. b->dirty = 1;
  110. if(bc->dfirst)
  111. bc->dlast->next = b;
  112. else
  113. bc->dfirst = b;
  114. bc->dlast = b;
  115. }
  116. /*
  117. * write out a page (and all preceding dirty ones)
  118. */
  119. int
  120. bcwrite(Bcache *bc, Bbuf *b)
  121. {
  122. Bbuf *nb;
  123. /*
  124. * write out all preceding pages
  125. */
  126. while(nb = bc->dfirst){
  127. if(bwrite(bc, nb->bno, nb->data) < 0)
  128. return -1;
  129. nb->dirty = 0;
  130. bc->dfirst = nb->next;
  131. nb->next = 0;
  132. if(nb == b)
  133. return 0;
  134. }
  135. /*
  136. * write out this page
  137. */
  138. if(bwrite(bc, b->bno, b->data) < 0)
  139. return -1;
  140. b->dirty = 0;
  141. b->next = 0;
  142. return 0;
  143. }
  144. /*
  145. * write out all dirty pages (in order)
  146. */
  147. int
  148. bcsync(Bcache *bc)
  149. {
  150. if(bc->dfirst)
  151. return bcwrite(bc, bc->dlast);
  152. return 0;
  153. }
  154. /*
  155. * read a block from disk
  156. */
  157. int
  158. bread(Bcache *bc, ulong bno, void *buf)
  159. {
  160. uvlong x = (uvlong)bno * bc->bsize;
  161. if(pread(bc->f, buf, bc->bsize, x) != bc->bsize)
  162. return -1;
  163. return 0;
  164. }
  165. /*
  166. * write a block to disk
  167. */
  168. int
  169. bwrite(Bcache *bc, ulong bno, void *buf)
  170. {
  171. uvlong x = (uvlong)bno * bc->bsize;
  172. if(pwrite(bc->f, buf, bc->bsize, x) != bc->bsize)
  173. return -1;
  174. return 0;
  175. }