file.c 5.4 KB

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