disk.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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. int icformat(Disk*, uint32_t);
  16. /*
  17. * read in the disk structures, return -1 if the format
  18. * is inconsistent.
  19. */
  20. int
  21. dinit(Disk *d, int f, int psize, char *expname)
  22. {
  23. uint32_t i;
  24. uint64_t length;
  25. char buf[1024];
  26. Bbuf *b;
  27. Dalloc *ba;
  28. Dir *dir;
  29. /*
  30. * get disk size
  31. */
  32. dir = dirfstat(f);
  33. if(dir == nil){
  34. perror("dinit: stat");
  35. return -1;
  36. }
  37. length = dir->length;
  38. free(dir);
  39. /*
  40. * read first physical block to get logical block size, # of inodes,
  41. * and # of allocation blocks
  42. */
  43. if(seek(f, 0, 0) < 0){
  44. perror("dinit: seek");
  45. return -1;
  46. }
  47. if(read(f, buf, sizeof(buf)) != sizeof(buf)){
  48. perror("dinit: read");
  49. return -1;
  50. }
  51. ba = (Dalloc*)buf;
  52. if(ba->bsize <= 0){
  53. fprint(2, "dinit: bsize 0x%lx<= 0\n", ba->bsize);
  54. return -1;
  55. }
  56. if((ba->bsize % psize) != 0){
  57. fprint(2, "dinit: logical bsize (%lu) not multiple of physical (%u)\n",
  58. ba->bsize, psize);
  59. return -1;
  60. }
  61. d->bsize = ba->bsize;
  62. d->nb = length/d->bsize;
  63. d->b2b = (d->bsize - sizeof(Dahdr))*8;
  64. d->nab = (d->nb+d->b2b-1)/d->b2b;
  65. d->p2b = d->bsize/sizeof(Dptr);
  66. strncpy(d->name, ba->name, sizeof d->name);
  67. if (expname != nil && strncmp(d->name, expname, sizeof d->name) != 0) {
  68. /* Mismatch with recorded name; fail here to force a format */
  69. fprint(2, "cfs: name mismatch\n");
  70. return -1;
  71. }
  72. /*
  73. * check allocation blocks for consistency
  74. */
  75. if(bcinit(d, f, d->bsize) < 0){
  76. fprint(2, "dinit: couldn't init block cache\n");
  77. return -1;
  78. }
  79. for(i = 0; i < d->nab; i++){
  80. b = bcread(d, i);
  81. if(b == 0){
  82. perror("dinit: read");
  83. return -1;
  84. }
  85. ba = (Dalloc*)b->data;
  86. if(ba->magic != Amagic){
  87. fprint(2, "dinit: bad magic in alloc block %lu\n", i);
  88. return -1;
  89. }
  90. if(d->bsize != ba->bsize){
  91. fprint(2, "dinit: bad bsize in alloc block %lu\n", i);
  92. return -1;
  93. }
  94. if(d->nab != ba->nab){
  95. fprint(2, "dinit: bad nab in alloc block %lu\n", i);
  96. return -1;
  97. }
  98. if(strncmp(d->name, ba->name, sizeof(d->name))){
  99. fprint(2, "dinit: bad name in alloc block %lu\n", i);
  100. return -1;
  101. }
  102. }
  103. return 0;
  104. }
  105. /*
  106. * format the disk as a cache
  107. */
  108. int
  109. dformat(Disk *d, int f, char *name, uint32_t bsize, uint32_t psize)
  110. {
  111. int i;
  112. uint64_t length;
  113. Bbuf *b;
  114. Dalloc *ba;
  115. Dir *dir;
  116. Dptr dptr;
  117. fprint(2, "formatting disk\n");
  118. /*
  119. * calculate basic numbers
  120. */
  121. dir = dirfstat(f);
  122. if(dir == nil)
  123. return -1;
  124. length = dir->length;
  125. d->bsize = bsize;
  126. if((d->bsize % psize) != 0){
  127. fprint(2, "cfs: logical bsize not multiple of physical\n");
  128. return -1;
  129. }
  130. d->nb = length/d->bsize;
  131. d->b2b = (d->bsize - sizeof(Dahdr))*8;
  132. d->nab = (d->nb+d->b2b-1)/d->b2b;
  133. d->p2b = d->bsize/sizeof(Dptr);
  134. /*
  135. * init allocation blocks
  136. */
  137. if(bcinit(d, f, d->bsize) < 0)
  138. return -1;
  139. for(i = 0; i < d->nab; i++){
  140. b = bcalloc(d, i);
  141. if(b == 0){
  142. perror("cfs: bcalloc");
  143. return -1;
  144. }
  145. memset(b->data, 0, d->bsize);
  146. ba = (Dalloc*)b->data;
  147. ba->magic = Amagic;
  148. ba->bsize = d->bsize;
  149. ba->nab = d->nab;
  150. strncpy(ba->name, name, sizeof(ba->name));
  151. bcmark(d, b);
  152. }
  153. /*
  154. * allocate allocation blocks
  155. */
  156. for(i = 0; i < d->nab; i++)
  157. if(dalloc(d, &dptr) == Notabno){
  158. fprint(2, "can't allocate allocation blocks\n");
  159. return -1;
  160. }
  161. return bcsync(d);
  162. }
  163. /*
  164. * allocate a block from a bit vector page
  165. *
  166. * a return value of Notabno means no blocks left
  167. */
  168. static uint32_t
  169. _balloc(Dalloc *ba, uint32_t max)
  170. {
  171. int len; /* number of valid words */
  172. uint32_t i; /* bit position in long */
  173. uint32_t m; /* 1<<i */
  174. uint32_t v; /* old value of long */
  175. uint32_t *p, *e;
  176. /*
  177. * find a word with a 0 bit
  178. */
  179. len = (max+BtoUL-1)/BtoUL;
  180. for(p = ba->bits, e = p + len; p < e; p++)
  181. if(*p != 0xFFFFFFFF)
  182. break;
  183. if(p == e)
  184. return Notabno;
  185. /*
  186. * find the first 0 bit
  187. */
  188. v = *p;
  189. for(m = 1, i = 0; i < BtoUL; i++, m <<= 1)
  190. if((m|v) != v)
  191. break;
  192. /*
  193. * calculate block number
  194. */
  195. i += (p - ba->bits)*BtoUL;
  196. if(i >= max)
  197. return Notabno;
  198. /*
  199. * set bit to 1
  200. */
  201. *p = v | m;
  202. return i;
  203. }
  204. /*
  205. * allocate a block
  206. *
  207. * return Notabno if none left
  208. */
  209. uint32_t
  210. dalloc(Disk *d, Dptr *p)
  211. {
  212. uint32_t bno, max, rv;
  213. Bbuf *b;
  214. Dalloc *ba;
  215. max = d->nb;
  216. for(bno = 0; bno < d->nab; bno++){
  217. b = bcread(d, bno);
  218. ba = (Dalloc*)b->data;
  219. rv = _balloc(ba, max > d->b2b ? d->b2b : max);
  220. if(rv != Notabno){
  221. rv = bno*d->b2b + rv;
  222. if(p){
  223. p->start = p->end = 0;
  224. p->bno = rv;
  225. }
  226. bcmark(d, b);
  227. return rv;
  228. }
  229. max -= d->b2b;
  230. }
  231. if(p)
  232. p->bno = Notabno;
  233. return Notabno;
  234. }
  235. /*
  236. * allocate a block of pointers
  237. */
  238. uint32_t
  239. dpalloc(Disk *d, Dptr *p)
  240. {
  241. Bbuf *b;
  242. Dptr *sp, *ep;
  243. if(dalloc(d, p) == Notabno)
  244. return Notabno;
  245. /*
  246. * allocate the page and invalidate all the
  247. * pointers
  248. */
  249. b = bcalloc(d, p->bno);
  250. if(b == 0)
  251. return -1;
  252. sp = (Dptr*)b->data;
  253. for(ep = sp + d->p2b; sp < ep; sp++){
  254. sp->bno = Notabno;
  255. sp->start = sp->end = 0;
  256. }
  257. p->bno |= Indbno;
  258. p->start = 0;
  259. p->end = d->bsize;
  260. /*
  261. * mark the page as dirty
  262. */
  263. bcmark(d, b);
  264. return 0;
  265. }
  266. /*
  267. * free a block
  268. */
  269. int
  270. _bfree(Disk *d, uint32_t i)
  271. {
  272. uint32_t bno, m;
  273. uint32_t *p;
  274. Bbuf *b;
  275. Dalloc *ba;
  276. /*
  277. * get correct allocation block
  278. */
  279. bno = i/d->b2b;
  280. if(bno >= d->nab)
  281. return -1;
  282. b = bcread(d, bno);
  283. if(b == 0)
  284. return -1;
  285. ba = (Dalloc*)b->data;
  286. /*
  287. * change bit
  288. */
  289. i -= bno*d->b2b;
  290. p = ba->bits + (i/BtoUL);
  291. m = 1<<(i%BtoUL);
  292. *p &= ~m;
  293. bcmark(d, b);
  294. return 0;
  295. }
  296. /*
  297. * free a block (or blocks)
  298. */
  299. int
  300. dfree(Disk *d, Dptr *dp)
  301. {
  302. uint32_t bno;
  303. Dptr *sp, *ep;
  304. Bbuf *b;
  305. bno = dp->bno;
  306. dp->bno = Notabno;
  307. /*
  308. * nothing to free
  309. */
  310. if(bno == Notabno)
  311. return 0;
  312. /*
  313. * direct pointer
  314. */
  315. if((bno & Indbno) == 0)
  316. return _bfree(d, bno);
  317. /*
  318. * first indirect page
  319. */
  320. bno &= ~Indbno;
  321. _bfree(d, bno);
  322. /*
  323. * then all the pages it points to
  324. *
  325. * DANGER: this algorithm may fail if there are more
  326. * allocation blocks than block buffers
  327. */
  328. b = bcread(d, bno);
  329. if(b == 0)
  330. return -1;
  331. sp = (Dptr*)b->data;
  332. for(ep = sp + d->p2b; sp < ep; sp++)
  333. if(dfree(d, sp) < 0)
  334. return -1;
  335. return 0;
  336. }