disk.c 6.0 KB

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