xref: /plan9/sys/src/cmd/cfs/disk.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
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