13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 33e12c5d1SDavid du Colombier #include "cformat.h" 43e12c5d1SDavid du Colombier #include "lru.h" 53e12c5d1SDavid du Colombier #include "bcache.h" 63e12c5d1SDavid du Colombier #include "disk.h" 73e12c5d1SDavid du Colombier 83e12c5d1SDavid du Colombier int icformat(Disk*, ulong); 93e12c5d1SDavid du Colombier 103e12c5d1SDavid du Colombier /* 113e12c5d1SDavid du Colombier * read in the disk structures, return -1 if the format 123e12c5d1SDavid du Colombier * is inconsistent. 133e12c5d1SDavid du Colombier */ 143e12c5d1SDavid du Colombier int 153e12c5d1SDavid du Colombier dinit(Disk *d, int f, int psize) 163e12c5d1SDavid du Colombier { 173e12c5d1SDavid du Colombier Dir dir; 183e12c5d1SDavid du Colombier char buf[1024]; 193e12c5d1SDavid du Colombier Dalloc *ba; 203e12c5d1SDavid du Colombier ulong i; 213e12c5d1SDavid du Colombier Bbuf *b; 223e12c5d1SDavid du Colombier 233e12c5d1SDavid du Colombier /* 243e12c5d1SDavid du Colombier * get disk size 253e12c5d1SDavid du Colombier */ 263e12c5d1SDavid du Colombier if(dirfstat(f, &dir) < 0){ 273e12c5d1SDavid du Colombier perror("dinit: stat"); 283e12c5d1SDavid du Colombier return -1; 293e12c5d1SDavid du Colombier } 303e12c5d1SDavid du Colombier 313e12c5d1SDavid du Colombier /* 323e12c5d1SDavid du Colombier * read first physical block to get logical block size, number of inodes, 333e12c5d1SDavid du Colombier * and number of allocation blocks 343e12c5d1SDavid du Colombier */ 353e12c5d1SDavid du Colombier if(seek(f, 0, 0) < 0){ 363e12c5d1SDavid du Colombier perror("dinit: seek"); 373e12c5d1SDavid du Colombier return -1; 383e12c5d1SDavid du Colombier } 393e12c5d1SDavid du Colombier if(read(f, buf, sizeof(buf)) != sizeof(buf)){ 403e12c5d1SDavid du Colombier perror("dinit: read"); 413e12c5d1SDavid du Colombier return -1; 423e12c5d1SDavid du Colombier } 433e12c5d1SDavid du Colombier ba = (Dalloc*)buf; 443e12c5d1SDavid du Colombier if(ba->bsize <= 0){ 453e12c5d1SDavid du Colombier fprint(2, "dinit: bsize 0x%lux<= 0\n", ba->bsize); 463e12c5d1SDavid du Colombier return -1; 473e12c5d1SDavid du Colombier } 483e12c5d1SDavid du Colombier if((ba->bsize % psize) != 0){ 49*7dd7cddfSDavid du Colombier fprint(2, "dinit: logical bsize (%lud) not multiple of physical (%ud)\n", 503e12c5d1SDavid du Colombier ba->bsize, psize); 513e12c5d1SDavid du Colombier return -1; 523e12c5d1SDavid du Colombier } 533e12c5d1SDavid du Colombier d->bsize = ba->bsize; 543e12c5d1SDavid du Colombier d->nb = dir.length/d->bsize; 553e12c5d1SDavid du Colombier d->b2b = (d->bsize - sizeof(Dahdr))*8; 563e12c5d1SDavid du Colombier d->nab = (d->nb+d->b2b-1)/d->b2b; 573e12c5d1SDavid du Colombier d->p2b = d->bsize/sizeof(Dptr); 583e12c5d1SDavid du Colombier strncpy(d->name, ba->name, sizeof(d->name)); 593e12c5d1SDavid du Colombier 603e12c5d1SDavid du Colombier /* 613e12c5d1SDavid du Colombier * check allocation blocks for consistency 623e12c5d1SDavid du Colombier */ 633e12c5d1SDavid du Colombier if(bcinit(d, f, d->bsize) < 0){ 643e12c5d1SDavid du Colombier fprint(2, "dinit: couldn't init block cache\n"); 653e12c5d1SDavid du Colombier return -1; 663e12c5d1SDavid du Colombier } 673e12c5d1SDavid du Colombier for(i = 0; i < d->nab; i++){ 683e12c5d1SDavid du Colombier b = bcread(d, i); 693e12c5d1SDavid du Colombier if(b == 0){ 703e12c5d1SDavid du Colombier perror("dinit: read"); 713e12c5d1SDavid du Colombier return -1; 723e12c5d1SDavid du Colombier } 733e12c5d1SDavid du Colombier ba = (Dalloc*)b->data; 743e12c5d1SDavid du Colombier if(ba->magic != Amagic){ 75*7dd7cddfSDavid du Colombier fprint(2, "dinit: bad magic in alloc block %uld\n", i); 763e12c5d1SDavid du Colombier return -1; 773e12c5d1SDavid du Colombier } 783e12c5d1SDavid du Colombier if(d->bsize != ba->bsize){ 79*7dd7cddfSDavid du Colombier fprint(2, "dinit: bad bsize in alloc block %uld\n", i); 803e12c5d1SDavid du Colombier return -1; 813e12c5d1SDavid du Colombier } 823e12c5d1SDavid du Colombier if(d->nab != ba->nab){ 83*7dd7cddfSDavid du Colombier fprint(2, "dinit: bad nab in alloc block %uld\n", i); 843e12c5d1SDavid du Colombier return -1; 853e12c5d1SDavid du Colombier } 863e12c5d1SDavid du Colombier if(strncmp(d->name, ba->name, sizeof(d->name))){ 87*7dd7cddfSDavid du Colombier fprint(2, "dinit: bad name in alloc block %uld\n", i); 883e12c5d1SDavid du Colombier return -1; 893e12c5d1SDavid du Colombier } 903e12c5d1SDavid du Colombier 913e12c5d1SDavid du Colombier } 923e12c5d1SDavid du Colombier 933e12c5d1SDavid du Colombier return 0; 943e12c5d1SDavid du Colombier } 953e12c5d1SDavid du Colombier 963e12c5d1SDavid du Colombier /* 973e12c5d1SDavid du Colombier * format the disk as a cache 983e12c5d1SDavid du Colombier */ 993e12c5d1SDavid du Colombier int 1003e12c5d1SDavid du Colombier dformat(Disk *d, int f, char *name, ulong bsize, ulong psize) 1013e12c5d1SDavid du Colombier { 1023e12c5d1SDavid du Colombier int i; 1033e12c5d1SDavid du Colombier Dir dir; 1043e12c5d1SDavid du Colombier Bbuf *b; 1053e12c5d1SDavid du Colombier Dalloc *ba; 1063e12c5d1SDavid du Colombier Dptr dptr; 1073e12c5d1SDavid du Colombier 1083e12c5d1SDavid du Colombier fprint(2, "formatting disk\n"); 1093e12c5d1SDavid du Colombier 1103e12c5d1SDavid du Colombier /* 1113e12c5d1SDavid du Colombier * calculate basic numbers 1123e12c5d1SDavid du Colombier */ 1133e12c5d1SDavid du Colombier if(dirfstat(f, &dir) < 0) 1143e12c5d1SDavid du Colombier return -1; 1153e12c5d1SDavid du Colombier d->bsize = bsize; 1163e12c5d1SDavid du Colombier if((d->bsize % psize) != 0){ 1173e12c5d1SDavid du Colombier fprint(2, "cfs: logical bsize not multiple of physical\n"); 1183e12c5d1SDavid du Colombier return -1; 1193e12c5d1SDavid du Colombier } 1203e12c5d1SDavid du Colombier d->nb = dir.length/d->bsize; 1213e12c5d1SDavid du Colombier d->b2b = (d->bsize - sizeof(Dahdr))*8; 1223e12c5d1SDavid du Colombier d->nab = (d->nb+d->b2b-1)/d->b2b; 1233e12c5d1SDavid du Colombier d->p2b = d->bsize/sizeof(Dptr); 1243e12c5d1SDavid du Colombier 1253e12c5d1SDavid du Colombier /* 1263e12c5d1SDavid du Colombier * init allocation blocks 1273e12c5d1SDavid du Colombier */ 1283e12c5d1SDavid du Colombier if(bcinit(d, f, d->bsize) < 0) 1293e12c5d1SDavid du Colombier return -1; 1303e12c5d1SDavid du Colombier for(i = 0; i < d->nab; i++){ 1313e12c5d1SDavid du Colombier b = bcalloc(d, i); 1323e12c5d1SDavid du Colombier if(b == 0){ 1333e12c5d1SDavid du Colombier perror("cfs: bcalloc"); 1343e12c5d1SDavid du Colombier return -1; 1353e12c5d1SDavid du Colombier } 1363e12c5d1SDavid du Colombier memset(b->data, 0, d->bsize); 1373e12c5d1SDavid du Colombier ba = (Dalloc*)b->data; 1383e12c5d1SDavid du Colombier ba->magic = Amagic; 1393e12c5d1SDavid du Colombier ba->bsize = d->bsize; 1403e12c5d1SDavid du Colombier ba->nab = d->nab; 1413e12c5d1SDavid du Colombier strncpy(ba->name, name, sizeof(ba->name)); 1423e12c5d1SDavid du Colombier bcmark(d, b); 1433e12c5d1SDavid du Colombier } 1443e12c5d1SDavid du Colombier 1453e12c5d1SDavid du Colombier /* 1463e12c5d1SDavid du Colombier * allocate allocation blocks 1473e12c5d1SDavid du Colombier */ 1483e12c5d1SDavid du Colombier for(i = 0; i < d->nab; i++) 1493e12c5d1SDavid du Colombier if(dalloc(d, &dptr) < 0){ 1503e12c5d1SDavid du Colombier fprint(2, "can't allocate allocation blocks\n"); 1513e12c5d1SDavid du Colombier return -1; 1523e12c5d1SDavid du Colombier } 1533e12c5d1SDavid du Colombier 1543e12c5d1SDavid du Colombier return bcsync(d); 1553e12c5d1SDavid du Colombier } 1563e12c5d1SDavid du Colombier 1573e12c5d1SDavid du Colombier /* 1583e12c5d1SDavid du Colombier * allocate a block from a bit vector page 1593e12c5d1SDavid du Colombier * 1603e12c5d1SDavid du Colombier * a return value of Notabno means no blocks left 1613e12c5d1SDavid du Colombier */ 1623e12c5d1SDavid du Colombier static ulong 1633e12c5d1SDavid du Colombier _balloc(Dalloc *ba, ulong max) 1643e12c5d1SDavid du Colombier { 1653e12c5d1SDavid du Colombier ulong *p; 1663e12c5d1SDavid du Colombier ulong *e; 1673e12c5d1SDavid du Colombier ulong i; /* bit position in long */ 1683e12c5d1SDavid du Colombier ulong m; /* 1<<i */ 1693e12c5d1SDavid du Colombier ulong v; /* old value of long */ 1703e12c5d1SDavid du Colombier int len; /* number of valid words */ 1713e12c5d1SDavid du Colombier 1723e12c5d1SDavid du Colombier /* 1733e12c5d1SDavid du Colombier * find a word with a 0 bit 1743e12c5d1SDavid du Colombier */ 1753e12c5d1SDavid du Colombier len = (max+BtoUL-1)/BtoUL; 1763e12c5d1SDavid du Colombier for(p = ba->bits, e = p + len; p < e; p++) 1773e12c5d1SDavid du Colombier if(*p != 0xFFFFFFFF) 1783e12c5d1SDavid du Colombier break; 1793e12c5d1SDavid du Colombier if(p == e) 1803e12c5d1SDavid du Colombier return Notabno; 1813e12c5d1SDavid du Colombier 1823e12c5d1SDavid du Colombier /* 1833e12c5d1SDavid du Colombier * find the first 0 bit 1843e12c5d1SDavid du Colombier */ 1853e12c5d1SDavid du Colombier v = *p; 1863e12c5d1SDavid du Colombier for(m = 1, i = 0; i<BtoUL; i++, m<<=1) 1873e12c5d1SDavid du Colombier if((m|v) != v) 1883e12c5d1SDavid du Colombier break; 1893e12c5d1SDavid du Colombier 1903e12c5d1SDavid du Colombier /* 1913e12c5d1SDavid du Colombier * calculate block number 1923e12c5d1SDavid du Colombier */ 1933e12c5d1SDavid du Colombier i += (p - ba->bits)*BtoUL; 1943e12c5d1SDavid du Colombier if(i >= max) 1953e12c5d1SDavid du Colombier return Notabno; 1963e12c5d1SDavid du Colombier 1973e12c5d1SDavid du Colombier /* 1983e12c5d1SDavid du Colombier * set bit to 1 1993e12c5d1SDavid du Colombier */ 2003e12c5d1SDavid du Colombier *p = v | m; 2013e12c5d1SDavid du Colombier return i; 2023e12c5d1SDavid du Colombier } 2033e12c5d1SDavid du Colombier 2043e12c5d1SDavid du Colombier /* 2053e12c5d1SDavid du Colombier * allocate a block 2063e12c5d1SDavid du Colombier * 2073e12c5d1SDavid du Colombier * return Notabno if none left 2083e12c5d1SDavid du Colombier */ 2093e12c5d1SDavid du Colombier ulong 2103e12c5d1SDavid du Colombier dalloc(Disk *d, Dptr *p) 2113e12c5d1SDavid du Colombier { 2123e12c5d1SDavid du Colombier ulong bno; 2133e12c5d1SDavid du Colombier Bbuf *b; 2143e12c5d1SDavid du Colombier Dalloc *ba; 2153e12c5d1SDavid du Colombier ulong rv; 2163e12c5d1SDavid du Colombier ulong max; 2173e12c5d1SDavid du Colombier 2183e12c5d1SDavid du Colombier max = d->nb; 2193e12c5d1SDavid du Colombier for(bno = 0; bno < d->nab; bno++){ 2203e12c5d1SDavid du Colombier b = bcread(d, bno); 2213e12c5d1SDavid du Colombier ba = (Dalloc*)b->data; 2223e12c5d1SDavid du Colombier rv = _balloc(ba, max > d->b2b ? d->b2b : max); 2233e12c5d1SDavid du Colombier if(rv != Notabno){ 2243e12c5d1SDavid du Colombier rv = bno*d->b2b + rv; 2253e12c5d1SDavid du Colombier if(p){ 2263e12c5d1SDavid du Colombier p->start = p->end = 0; 2273e12c5d1SDavid du Colombier p->bno = rv; 2283e12c5d1SDavid du Colombier } 2293e12c5d1SDavid du Colombier bcmark(d, b); 2303e12c5d1SDavid du Colombier return rv; 2313e12c5d1SDavid du Colombier } 2323e12c5d1SDavid du Colombier max -= d->b2b; 2333e12c5d1SDavid du Colombier } 2343e12c5d1SDavid du Colombier if(p) 2353e12c5d1SDavid du Colombier p->bno = Notabno; 2363e12c5d1SDavid du Colombier return Notabno; 2373e12c5d1SDavid du Colombier } 2383e12c5d1SDavid du Colombier 2393e12c5d1SDavid du Colombier /* 2403e12c5d1SDavid du Colombier * allocate a block of pointers 2413e12c5d1SDavid du Colombier */ 2423e12c5d1SDavid du Colombier ulong 2433e12c5d1SDavid du Colombier dpalloc(Disk *d, Dptr *p) 2443e12c5d1SDavid du Colombier { 2453e12c5d1SDavid du Colombier Bbuf *b; 2463e12c5d1SDavid du Colombier Dptr *sp; 2473e12c5d1SDavid du Colombier Dptr *ep; 2483e12c5d1SDavid du Colombier 2493e12c5d1SDavid du Colombier if(dalloc(d, p) == Notabno) 2503e12c5d1SDavid du Colombier return Notabno; 2513e12c5d1SDavid du Colombier 2523e12c5d1SDavid du Colombier /* 2533e12c5d1SDavid du Colombier * allocate the page and invalidate all the 2543e12c5d1SDavid du Colombier * pointers 2553e12c5d1SDavid du Colombier */ 2563e12c5d1SDavid du Colombier b = bcalloc(d, p->bno); 2573e12c5d1SDavid du Colombier if(b == 0) 2583e12c5d1SDavid du Colombier return -1; 2593e12c5d1SDavid du Colombier sp = (Dptr*)b->data; 2603e12c5d1SDavid du Colombier for(ep = sp + d->p2b; sp < ep; sp++){ 2613e12c5d1SDavid du Colombier sp->bno = Notabno; 2623e12c5d1SDavid du Colombier sp->start = sp->end = 0; 2633e12c5d1SDavid du Colombier } 2643e12c5d1SDavid du Colombier p->bno |= Indbno; 2653e12c5d1SDavid du Colombier p->start = 0; 2663e12c5d1SDavid du Colombier p->end = d->bsize; 2673e12c5d1SDavid du Colombier 2683e12c5d1SDavid du Colombier /* 2693e12c5d1SDavid du Colombier * mark the page as dirty 2703e12c5d1SDavid du Colombier */ 2713e12c5d1SDavid du Colombier bcmark(d, b); 2723e12c5d1SDavid du Colombier return 0; 2733e12c5d1SDavid du Colombier } 2743e12c5d1SDavid du Colombier 2753e12c5d1SDavid du Colombier /* 2763e12c5d1SDavid du Colombier * free a block 2773e12c5d1SDavid du Colombier */ 2783e12c5d1SDavid du Colombier int 2793e12c5d1SDavid du Colombier _bfree(Disk *d, ulong i) 2803e12c5d1SDavid du Colombier { 2813e12c5d1SDavid du Colombier ulong *p; 2823e12c5d1SDavid du Colombier ulong m; 2833e12c5d1SDavid du Colombier Bbuf *b; 2843e12c5d1SDavid du Colombier Dalloc *ba; 2853e12c5d1SDavid du Colombier ulong bno; 2863e12c5d1SDavid du Colombier 2873e12c5d1SDavid du Colombier /* 2883e12c5d1SDavid du Colombier * get correct allocation block 2893e12c5d1SDavid du Colombier */ 2903e12c5d1SDavid du Colombier bno = i/d->b2b; 2913e12c5d1SDavid du Colombier if(bno >= d->nab) 2923e12c5d1SDavid du Colombier return -1; 2933e12c5d1SDavid du Colombier b = bcread(d, bno); 2943e12c5d1SDavid du Colombier if(b == 0) 2953e12c5d1SDavid du Colombier return -1; 2963e12c5d1SDavid du Colombier ba = (Dalloc*)b->data; 2973e12c5d1SDavid du Colombier 2983e12c5d1SDavid du Colombier /* 2993e12c5d1SDavid du Colombier * change bit 3003e12c5d1SDavid du Colombier */ 3013e12c5d1SDavid du Colombier i -= bno*d->b2b; 3023e12c5d1SDavid du Colombier p = ba->bits + (i/BtoUL); 3033e12c5d1SDavid du Colombier m = 1<<(i%BtoUL); 3043e12c5d1SDavid du Colombier *p &= ~m; 3053e12c5d1SDavid du Colombier bcmark(d, b); 3063e12c5d1SDavid du Colombier 3073e12c5d1SDavid du Colombier return 0; 3083e12c5d1SDavid du Colombier } 3093e12c5d1SDavid du Colombier 3103e12c5d1SDavid du Colombier /* 3113e12c5d1SDavid du Colombier * free a block (or blocks) 3123e12c5d1SDavid du Colombier */ 3133e12c5d1SDavid du Colombier int 3143e12c5d1SDavid du Colombier dfree(Disk *d, Dptr *dp) 3153e12c5d1SDavid du Colombier { 3163e12c5d1SDavid du Colombier Dptr *sp; 3173e12c5d1SDavid du Colombier Dptr *ep; 3183e12c5d1SDavid du Colombier Bbuf *b; 3193e12c5d1SDavid du Colombier ulong bno; 3203e12c5d1SDavid du Colombier 3213e12c5d1SDavid du Colombier bno = dp->bno; 3223e12c5d1SDavid du Colombier dp->bno = Notabno; 3233e12c5d1SDavid du Colombier 3243e12c5d1SDavid du Colombier /* 3253e12c5d1SDavid du Colombier * nothing to free 3263e12c5d1SDavid du Colombier */ 3273e12c5d1SDavid du Colombier if(bno == Notabno) 3283e12c5d1SDavid du Colombier return 0; 3293e12c5d1SDavid du Colombier 3303e12c5d1SDavid du Colombier /* 3313e12c5d1SDavid du Colombier * direct pointer 3323e12c5d1SDavid du Colombier */ 3333e12c5d1SDavid du Colombier if((bno & Indbno) == 0) 3343e12c5d1SDavid du Colombier return _bfree(d, bno); 3353e12c5d1SDavid du Colombier 3363e12c5d1SDavid du Colombier /* 3373e12c5d1SDavid du Colombier * first indirect page 3383e12c5d1SDavid du Colombier */ 3393e12c5d1SDavid du Colombier bno &= ~Indbno; 3403e12c5d1SDavid du Colombier _bfree(d, bno); 3413e12c5d1SDavid du Colombier 3423e12c5d1SDavid du Colombier /* 3433e12c5d1SDavid du Colombier * then all the pages it points to 3443e12c5d1SDavid du Colombier * 3453e12c5d1SDavid du Colombier * DANGER: this algorithm may fail is their are more 3463e12c5d1SDavid du Colombier * allocation blocks than block buffers 3473e12c5d1SDavid du Colombier */ 3483e12c5d1SDavid du Colombier b = bcread(d, bno); 3493e12c5d1SDavid du Colombier if(b == 0) 3503e12c5d1SDavid du Colombier return -1; 3513e12c5d1SDavid du Colombier sp = (Dptr*)b->data; 3523e12c5d1SDavid du Colombier for(ep = sp + d->p2b; sp < ep; sp++) 3533e12c5d1SDavid du Colombier if(dfree(d, sp) < 0) 3543e12c5d1SDavid du Colombier return -1; 3553e12c5d1SDavid du Colombier 3563e12c5d1SDavid du Colombier return 0; 3573e12c5d1SDavid du Colombier } 358