dentry.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. #include "all.h"
  2. Dentry*
  3. getdir(Iobuf *p, int slot)
  4. {
  5. if(!p)
  6. return 0;
  7. return (Dentry*)p->iobuf + slot%DIRPERBUF;
  8. }
  9. void
  10. accessdir(Iobuf *p, Dentry *d, int f, int uid)
  11. {
  12. Timet t;
  13. if(p && p->dev->type != Devro) {
  14. p->flags |= Bmod;
  15. t = time(nil);
  16. if(f & (FREAD|FWRITE))
  17. d->atime = t;
  18. if(f & FWRITE) {
  19. d->mtime = t;
  20. d->muid = uid;
  21. d->qid.version++;
  22. }
  23. }
  24. }
  25. void
  26. preread(Device *d, Off addr)
  27. {
  28. Rabuf *rb;
  29. if(addr == 0)
  30. return;
  31. if(raheadq->count+10 >= raheadq->size) /* ugly knowing layout */
  32. return;
  33. lock(&rabuflock);
  34. rb = rabuffree;
  35. if(rb == 0) {
  36. unlock(&rabuflock);
  37. return;
  38. }
  39. rabuffree = rb->link;
  40. unlock(&rabuflock);
  41. rb->dev = d;
  42. rb->addr = addr;
  43. fs_send(raheadq, rb);
  44. }
  45. Off
  46. rel2abs(Iobuf *p, Dentry *d, Off a, int tag, int putb, int uid)
  47. {
  48. int i;
  49. Off addr, qpath, indaddrs = 1, div;
  50. Device *dev;
  51. if(a < 0) {
  52. print("rel2abs: neg offset\n");
  53. if(putb)
  54. putbuf(p);
  55. return 0;
  56. }
  57. dev = p->dev;
  58. qpath = d->qid.path;
  59. /* is `a' a direct block? */
  60. if(a < NDBLOCK) {
  61. addr = d->dblock[a];
  62. if(!addr && tag) {
  63. addr = bufalloc(dev, tag, qpath, uid);
  64. d->dblock[a] = addr;
  65. p->flags |= Bmod|Bimm;
  66. }
  67. if(putb)
  68. putbuf(p);
  69. return addr;
  70. }
  71. a -= NDBLOCK;
  72. /*
  73. * loop through indirect block depths.
  74. */
  75. for (i = 0; i < NIBLOCK; i++) {
  76. indaddrs *= INDPERBUF;
  77. /* is a's disk addr in this indir block or one of its kids? */
  78. if (a < indaddrs) {
  79. addr = d->iblocks[i];
  80. if(!addr && tag) {
  81. addr = bufalloc(dev, Tind1+i, qpath, uid);
  82. d->iblocks[i] = addr;
  83. p->flags |= Bmod|Bimm;
  84. }
  85. if(putb)
  86. putbuf(p);
  87. div = indaddrs;
  88. for (; i >= 0; i--) {
  89. div /= INDPERBUF;
  90. if (div <= 0)
  91. panic("rel2abs: non-positive divisor");
  92. addr = indfetch(dev, qpath, addr,
  93. (a/div)%INDPERBUF, Tind1+i,
  94. (i == 0? tag: Tind1+i-1), uid);
  95. }
  96. return addr;
  97. }
  98. a -= indaddrs;
  99. }
  100. if(putb)
  101. putbuf(p);
  102. /* quintuple-indirect blocks not implemented. */
  103. print("rel2abs: no %d-deep indirect\n", NIBLOCK+1);
  104. return 0;
  105. }
  106. /*
  107. * read-ahead strategy
  108. * on second block, read RAGAP blocks,
  109. * thereafter, read RAGAP ahead of current pos
  110. */
  111. Off
  112. dbufread(Iobuf *p, Dentry *d, Off a, Off ra, int uid)
  113. {
  114. Off addr;
  115. if(a == 0)
  116. return 1;
  117. if(a == 1 && ra == 1) {
  118. while(ra < a+RAGAP) {
  119. ra++;
  120. addr = rel2abs(p, d, ra, 0, 0, uid);
  121. if(!addr)
  122. return 0;
  123. preread(p->dev, addr);
  124. }
  125. return ra+1;
  126. }
  127. if(ra == a+RAGAP) {
  128. addr = rel2abs(p, d, ra, 0, 0, uid);
  129. if(!addr)
  130. return 0;
  131. preread(p->dev, addr);
  132. return ra+1;
  133. }
  134. return ra;
  135. }
  136. Iobuf*
  137. dnodebuf(Iobuf *p, Dentry *d, Off a, int tag, int uid)
  138. {
  139. Off addr;
  140. addr = rel2abs(p, d, a, tag, 0, uid);
  141. if(addr)
  142. return getbuf(p->dev, addr, Brd);
  143. return 0;
  144. }
  145. /*
  146. * same as dnodebuf but it calls putbuf(p)
  147. * to reduce interference.
  148. */
  149. Iobuf*
  150. dnodebuf1(Iobuf *p, Dentry *d, Off a, int tag, int uid)
  151. {
  152. Off addr;
  153. Device *dev;
  154. dev = p->dev;
  155. addr = rel2abs(p, d, a, tag, 1, uid);
  156. if(addr)
  157. return getbuf(dev, addr, Brd);
  158. return 0;
  159. }
  160. Off
  161. indfetch(Device* d, Off qpath, Off addr, Off a, int itag, int tag, int uid)
  162. {
  163. Iobuf *bp;
  164. if(!addr)
  165. return 0;
  166. bp = getbuf(d, addr, Brd);
  167. if(!bp || checktag(bp, itag, qpath)) {
  168. if(!bp) {
  169. print("ind fetch bp = 0\n");
  170. return 0;
  171. }
  172. print("ind fetch tag\n");
  173. putbuf(bp);
  174. return 0;
  175. }
  176. addr = ((Off *)bp->iobuf)[a];
  177. if(!addr && tag) {
  178. addr = bufalloc(d, tag, qpath, uid);
  179. if(addr) {
  180. ((Off *)bp->iobuf)[a] = addr;
  181. bp->flags |= Bmod;
  182. if(tag == Tdir)
  183. bp->flags |= Bimm;
  184. settag(bp, itag, qpath);
  185. }
  186. }
  187. putbuf(bp);
  188. return addr;
  189. }
  190. /* return INDPERBUF^exp */
  191. Off
  192. ibbpow(int exp)
  193. {
  194. static Off pows[] = {
  195. 1,
  196. INDPERBUF,
  197. (Off)INDPERBUF*INDPERBUF,
  198. (Off)INDPERBUF*(Off)INDPERBUF*INDPERBUF,
  199. (Off)INDPERBUF*(Off)INDPERBUF*(Off)INDPERBUF*INDPERBUF,
  200. };
  201. if (exp < 0)
  202. return 0;
  203. else if (exp >= nelem(pows)) { /* not in table? do it long-hand */
  204. Off indpow = 1;
  205. while (exp-- > 0 && indpow > 0)
  206. indpow *= INDPERBUF;
  207. return indpow;
  208. } else
  209. return pows[exp];
  210. }
  211. /* return sum of INDPERBUF^n for 1 ≤ n ≤ exp */
  212. Off
  213. ibbpowsum(int exp)
  214. {
  215. Off indsum = 0;
  216. for (; exp > 0; exp--)
  217. indsum += ibbpow(exp);
  218. return indsum;
  219. }
  220. /* zero bytes past new file length; return an error code */
  221. int
  222. trunczero(Truncstate *ts)
  223. {
  224. int blkoff = ts->newsize % BUFSIZE;
  225. Iobuf *pd;
  226. pd = dnodebuf(ts->p, ts->d, ts->lastblk, Tfile, ts->uid);
  227. if (pd == nil || checktag(pd, Tfile, QPNONE)) {
  228. if (pd != nil)
  229. putbuf(pd);
  230. ts->err = Ephase;
  231. return Ephase;
  232. }
  233. memset(pd->iobuf+blkoff, 0, BUFSIZE - blkoff);
  234. putbuf(pd);
  235. return 0;
  236. }
  237. /*
  238. * truncate d (in p) to length `newsize'.
  239. * if larger, just increase size.
  240. * if smaller, deallocate blocks after last one
  241. * still in file at new size. last byte to keep
  242. * is newsize-1, due to zero origin.
  243. * we free in forward order because it's simpler to get right.
  244. * if the final block at the new size is partially-filled,
  245. * zero the remainder.
  246. */
  247. int
  248. dtrunclen(Iobuf *p, Dentry *d, Off newsize, int uid)
  249. {
  250. int i, pastlast;
  251. Truncstate trunc;
  252. if (newsize <= 0) {
  253. dtrunc(p, d, uid);
  254. return 0;
  255. }
  256. memset(&trunc, 0, sizeof trunc);
  257. trunc.d = d;
  258. trunc.p = p;
  259. trunc.uid = uid;
  260. trunc.newsize = newsize;
  261. trunc.lastblk = newsize/BUFSIZE;
  262. if (newsize % BUFSIZE == 0)
  263. trunc.lastblk--;
  264. else
  265. trunczero(&trunc);
  266. for (i = 0; i < NDBLOCK; i++)
  267. if (trunc.pastlast) {
  268. trunc.relblk = i;
  269. buffree(p->dev, d->dblock[i], 0, &trunc);
  270. d->dblock[i] = 0;
  271. } else if (i == trunc.lastblk)
  272. trunc.pastlast = 1;
  273. trunc.relblk = NDBLOCK;
  274. for (i = 0; i < NIBLOCK; i++) {
  275. pastlast = trunc.pastlast;
  276. buffree(p->dev, d->iblocks[i], i+1, &trunc);
  277. if (pastlast)
  278. d->iblocks[i] = 0;
  279. }
  280. d->size = newsize;
  281. p->flags |= Bmod|Bimm;
  282. accessdir(p, d, FWRITE, uid);
  283. return trunc.err;
  284. }
  285. /*
  286. * truncate d (in p) to zero length.
  287. * freeing blocks in reverse order is traditional, from Unix,
  288. * in an attempt to keep the free list contiguous.
  289. */
  290. void
  291. dtrunc(Iobuf *p, Dentry *d, int uid)
  292. {
  293. int i;
  294. for (i = NIBLOCK-1; i >= 0; i--) {
  295. buffree(p->dev, d->iblocks[i], i+1, nil);
  296. d->iblocks[i] = 0;
  297. }
  298. for (i = NDBLOCK-1; i >= 0; i--) {
  299. buffree(p->dev, d->dblock[i], 0, nil);
  300. d->dblock[i] = 0;
  301. }
  302. d->size = 0;
  303. p->flags |= Bmod|Bimm;
  304. accessdir(p, d, FWRITE, uid);
  305. }