file.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. #include <u.h>
  2. #include <libc.h>
  3. #include "cformat.h"
  4. #include "lru.h"
  5. #include "bcache.h"
  6. #include "disk.h"
  7. #include "inode.h"
  8. #include "file.h"
  9. /*
  10. * merge data with that which already exists in a block
  11. *
  12. * we allow only one range per block, always use the new
  13. * data if the ranges don't overlap.
  14. */
  15. void
  16. fmerge(Dptr *p, char *to, char *from, int start, int len)
  17. {
  18. int end;
  19. end = start + len;
  20. memmove(to+start, from, end-start);
  21. /*
  22. * if ranges do not overlap...
  23. */
  24. if(start>p->end || p->start>end){
  25. /*
  26. * just use the new data
  27. */
  28. p->start = start;
  29. p->end = end;
  30. } else {
  31. /*
  32. * merge ranges
  33. */
  34. if(start < p->start)
  35. p->start = start;
  36. if(end > p->end)
  37. p->end = end;
  38. }
  39. }
  40. /*
  41. * write a block (or less) of data onto a disk, follow it with any necessary
  42. * pointer writes.
  43. *
  44. * N.B. ordering is everything
  45. */
  46. int
  47. fbwrite(Icache *ic, Ibuf *b, char *a, ulong off, int len)
  48. {
  49. Bbuf *dbb; /* data block */
  50. Bbuf *ibb; /* indirect block */
  51. Dptr *p;
  52. Dptr t;
  53. ulong fbno;
  54. int wrinode;
  55. fbno = off / ic->bsize;
  56. p = &b->inode.ptr;
  57. ibb = 0;
  58. wrinode = 0;
  59. /*
  60. * are there any pages for this inode?
  61. */
  62. if(p->bno == Notabno){
  63. wrinode = 1;
  64. goto dowrite;
  65. }
  66. /*
  67. * is it an indirect block?
  68. */
  69. if(p->bno & Indbno){
  70. ibb = bcread(ic, p->bno);
  71. if(ibb == 0)
  72. return -1;
  73. p = (Dptr*)ibb->data;
  74. p += fbno % ic->p2b;
  75. goto dowrite;
  76. }
  77. /*
  78. * is it the wrong direct block?
  79. */
  80. if((p->fbno%ic->p2b) != (fbno%ic->p2b)){
  81. /*
  82. * yes, make an indirect block
  83. */
  84. t = *p;
  85. dpalloc(ic, p);
  86. if(p->bno == Notabno){
  87. *p = t;
  88. return -1;
  89. }
  90. ibb = bcalloc(ic, p->bno);
  91. if(ibb == 0){
  92. *p = t;
  93. return -1;
  94. }
  95. p = (Dptr*)ibb->data;
  96. p += t.fbno % ic->p2b;
  97. *p = t;
  98. p = (Dptr*)ibb->data;
  99. p += fbno % ic->p2b;
  100. }
  101. wrinode = 1;
  102. dowrite:
  103. /*
  104. * get the data block into the block cache
  105. */
  106. if(p->bno == Notabno){
  107. /*
  108. * create a new block
  109. */
  110. dalloc(ic, p);
  111. if(p->bno == Notabno)
  112. return -1; /* no blocks left (maybe) */
  113. dbb = bcalloc(ic, p->bno);
  114. } else {
  115. /*
  116. * use what's there
  117. */
  118. dbb = bcread(ic, p->bno);
  119. }
  120. if(dbb == 0)
  121. return -1;
  122. /*
  123. * merge in the new data
  124. */
  125. if(p->fbno != fbno){
  126. p->start = p->end = 0;
  127. p->fbno = fbno;
  128. }
  129. fmerge(p, dbb->data, a, off % ic->bsize, len);
  130. /*
  131. * write changed blocks back in the
  132. * correct order
  133. */
  134. bcmark(ic, dbb);
  135. if(ibb){
  136. bcmark(ic, ibb);
  137. }
  138. if(wrinode){
  139. if(iwrite(ic, b) < 0)
  140. return -1;
  141. }
  142. return len;
  143. }
  144. /*
  145. * write `n' bytes to the cache
  146. *
  147. * return number of bytes written
  148. */
  149. long
  150. fwrite(Icache *ic, Ibuf *b, char *a, ulong off, long n)
  151. {
  152. int len;
  153. long sofar;
  154. for(sofar = 0; sofar < n; sofar += len){
  155. len = ic->bsize - ((off+sofar)%ic->bsize);
  156. if(len > n - sofar)
  157. len = n - sofar;
  158. if(fbwrite(ic, b, a+sofar, off+sofar, len) < 0)
  159. return sofar;
  160. }
  161. return sofar;
  162. }
  163. /*
  164. * get a pointer to the next valid data at or after `off'
  165. */
  166. Dptr *
  167. fpget(Icache *ic, Ibuf *b, ulong off)
  168. {
  169. Bbuf *ibb; /* indirect block */
  170. ulong fbno;
  171. long doff;
  172. Dptr *p;
  173. Dptr *p0;
  174. Dptr *pf;
  175. fbno = off / ic->bsize;
  176. p = &b->inode.ptr;
  177. /*
  178. * are there any pages for this inode?
  179. */
  180. if(p->bno == Notabno)
  181. return 0;
  182. /*
  183. * if it's a direct block, life is easy?
  184. */
  185. if(!(p->bno & Indbno)){
  186. /*
  187. * a direct block, return p if it's at least past what we want
  188. */
  189. if(p->fbno > fbno)
  190. return p;
  191. if(p->fbno < fbno)
  192. return 0;
  193. doff = off % ic->bsize;
  194. if(doff>=p->start && doff<p->end)
  195. return p;
  196. else
  197. return 0;
  198. }
  199. /*
  200. * read the indirect block
  201. */
  202. ibb = bcread(ic, p->bno);
  203. if(ibb == 0)
  204. return 0;
  205. /*
  206. * find the next valid pointer
  207. */
  208. p0 = (Dptr*)ibb->data;
  209. pf = p0 + (fbno % ic->p2b);
  210. if(pf->bno!=Notabno && pf->fbno==fbno){
  211. doff = off % ic->bsize;
  212. if(doff<pf->end)
  213. return pf;
  214. }
  215. for(p = pf+1 ;p < p0 + ic->p2b; p++){
  216. fbno++;
  217. if(p->fbno==fbno && p->bno!=Notabno && p->start<p->end)
  218. return p;
  219. }
  220. for(p = p0 ;p < pf; p++){
  221. fbno++;
  222. if(p->fbno==fbno && p->bno!=Notabno && p->start<p->end)
  223. return p;
  224. }
  225. return 0;
  226. }
  227. /*
  228. * read `n' bytes from the cache.
  229. *
  230. * if we hit a gap and we've read something,
  231. * return number of bytes read so far.
  232. *
  233. * if we start with a gap, return minus the number of bytes
  234. * to the next data.
  235. *
  236. * if there are no bytes cached, return 0.
  237. */
  238. long
  239. fread(Icache *ic, Ibuf *b, char *a, ulong off, long n)
  240. {
  241. int len;
  242. Dptr *p;
  243. Bbuf *bb;
  244. long sofar;
  245. long gap;
  246. int start;
  247. for(sofar = 0; sofar < n; sofar += len, off += len){
  248. /*
  249. * get pointer to next data
  250. */
  251. len = n - sofar;
  252. p = fpget(ic, b, off);
  253. /*
  254. * if no more data, return what we have so far
  255. */
  256. if(p == 0)
  257. return sofar;
  258. /*
  259. * if there's a gap, return the size of the gap
  260. */
  261. gap = (ic->bsize*p->fbno + p->start) - off;
  262. if(gap>0){
  263. if(sofar == 0)
  264. return -gap;
  265. else
  266. return sofar;
  267. }
  268. /*
  269. * return what we have
  270. */
  271. bb = bcread(ic, p->bno);
  272. if(bb == 0)
  273. return sofar;
  274. start = p->start - gap;
  275. if(p->end - start < len)
  276. len = p->end - start;
  277. memmove(a + sofar, bb->data + start, len);
  278. }
  279. return sofar;
  280. }