file.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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. int wrinode;
  50. ulong fbno;
  51. Bbuf *dbb; /* data block */
  52. Bbuf *ibb; /* indirect block */
  53. Dptr *p;
  54. Dptr t;
  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. if(wrinode)
  138. if(iwrite(ic, b) < 0)
  139. return -1;
  140. return len;
  141. }
  142. /*
  143. * write `n' bytes to the cache
  144. *
  145. * return number of bytes written
  146. */
  147. long
  148. fwrite(Icache *ic, Ibuf *b, char *a, ulong off, long n)
  149. {
  150. int len;
  151. long sofar;
  152. for(sofar = 0; sofar < n; sofar += len){
  153. len = ic->bsize - ((off+sofar)%ic->bsize);
  154. if(len > n - sofar)
  155. len = n - sofar;
  156. if(fbwrite(ic, b, a+sofar, off+sofar, len) < 0)
  157. return sofar;
  158. }
  159. return sofar;
  160. }
  161. /*
  162. * get a pointer to the next valid data at or after `off'
  163. */
  164. Dptr *
  165. fpget(Icache *ic, Ibuf *b, ulong off)
  166. {
  167. ulong fbno;
  168. long doff;
  169. Bbuf *ibb; /* indirect block */
  170. Dptr *p, *p0, *pf;
  171. fbno = off / ic->bsize;
  172. p = &b->inode.ptr;
  173. /*
  174. * are there any pages for this inode?
  175. */
  176. if(p->bno == Notabno)
  177. return 0;
  178. /*
  179. * if it's a direct block, life is easy?
  180. */
  181. if(!(p->bno & Indbno)){
  182. /*
  183. * a direct block, return p if it's at least past what we want
  184. */
  185. if(p->fbno > fbno)
  186. return p;
  187. if(p->fbno < fbno)
  188. return 0;
  189. doff = off % ic->bsize;
  190. if(doff>=p->start && doff<p->end)
  191. return p;
  192. else
  193. return 0;
  194. }
  195. /*
  196. * read the indirect block
  197. */
  198. ibb = bcread(ic, p->bno);
  199. if(ibb == 0)
  200. return 0;
  201. /*
  202. * find the next valid pointer
  203. */
  204. p0 = (Dptr*)ibb->data;
  205. pf = p0 + (fbno % ic->p2b);
  206. if(pf->bno!=Notabno && pf->fbno==fbno){
  207. doff = off % ic->bsize;
  208. if(doff<pf->end)
  209. return pf;
  210. }
  211. for(p = pf+1; p < p0 + ic->p2b; p++){
  212. fbno++;
  213. if(p->fbno==fbno && p->bno!=Notabno && p->start<p->end)
  214. return p;
  215. }
  216. for(p = p0; p < pf; p++){
  217. fbno++;
  218. if(p->fbno==fbno && p->bno!=Notabno && p->start<p->end)
  219. return p;
  220. }
  221. return 0;
  222. }
  223. /*
  224. * read `n' bytes from the cache.
  225. *
  226. * if we hit a gap and we've read something,
  227. * return number of bytes read so far.
  228. *
  229. * if we start with a gap, return minus the number of bytes
  230. * to the next data.
  231. *
  232. * if there are no bytes cached, return 0.
  233. */
  234. long
  235. fread(Icache *ic, Ibuf *b, char *a, ulong off, long n)
  236. {
  237. int len, start;
  238. long sofar, gap;
  239. Dptr *p;
  240. Bbuf *bb;
  241. for(sofar = 0; sofar < n; sofar += len, off += len){
  242. /*
  243. * get pointer to next data
  244. */
  245. len = n - sofar;
  246. p = fpget(ic, b, off);
  247. /*
  248. * if no more data, return what we have so far
  249. */
  250. if(p == 0)
  251. return sofar;
  252. /*
  253. * if there's a gap, return the size of the gap
  254. */
  255. gap = (ic->bsize*p->fbno + p->start) - off;
  256. if(gap>0)
  257. if(sofar == 0)
  258. return -gap;
  259. else
  260. return sofar;
  261. /*
  262. * return what we have
  263. */
  264. bb = bcread(ic, p->bno);
  265. if(bb == 0)
  266. return sofar;
  267. start = p->start - gap;
  268. if(p->end - start < len)
  269. len = p->end - start;
  270. memmove(a + sofar, bb->data + start, len);
  271. }
  272. return sofar;
  273. }