xref: /plan9/sys/src/cmd/cfs/disk.c (revision 41fb754a868aff65c81b63b0b07ae1fab2010fd9)
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 	ulong	i;
18*41fb754aSDavid du Colombier 	uvlong	length;
19*41fb754aSDavid du Colombier 	char	buf[1024];
203e12c5d1SDavid du Colombier 	Bbuf	*b;
21*41fb754aSDavid du Colombier 	Dalloc	*ba;
22*41fb754aSDavid du Colombier 	Dir	*dir;
233e12c5d1SDavid du Colombier 
243e12c5d1SDavid du Colombier 	/*
253e12c5d1SDavid du Colombier 	 *  get disk size
263e12c5d1SDavid du Colombier 	 */
279a747e4fSDavid du Colombier 	dir = dirfstat(f);
289a747e4fSDavid du Colombier 	if(dir == nil){
293e12c5d1SDavid du Colombier 		perror("dinit: stat");
303e12c5d1SDavid du Colombier 		return -1;
313e12c5d1SDavid du Colombier 	}
329a747e4fSDavid du Colombier 	length = dir->length;
339a747e4fSDavid du Colombier 	free(dir);
343e12c5d1SDavid du Colombier 
353e12c5d1SDavid du Colombier 	/*
36*41fb754aSDavid du Colombier 	 *  read first physical block to get logical block size, # of inodes,
37*41fb754aSDavid du Colombier 	 *  and # of allocation blocks
383e12c5d1SDavid du Colombier 	 */
393e12c5d1SDavid du Colombier 	if(seek(f, 0, 0) < 0){
403e12c5d1SDavid du Colombier 		perror("dinit: seek");
413e12c5d1SDavid du Colombier 		return -1;
423e12c5d1SDavid du Colombier 	}
433e12c5d1SDavid du Colombier 	if(read(f, buf, sizeof(buf)) != sizeof(buf)){
443e12c5d1SDavid du Colombier 		perror("dinit: read");
453e12c5d1SDavid du Colombier 		return -1;
463e12c5d1SDavid du Colombier 	}
473e12c5d1SDavid du Colombier 	ba = (Dalloc*)buf;
483e12c5d1SDavid du Colombier 	if(ba->bsize <= 0){
493e12c5d1SDavid du Colombier 		fprint(2, "dinit: bsize 0x%lux<= 0\n", ba->bsize);
503e12c5d1SDavid du Colombier 		return -1;
513e12c5d1SDavid du Colombier 	}
523e12c5d1SDavid du Colombier 	if((ba->bsize % psize) != 0){
537dd7cddfSDavid du Colombier 		fprint(2, "dinit: logical bsize (%lud) not multiple of physical (%ud)\n",
543e12c5d1SDavid du Colombier 			ba->bsize, psize);
553e12c5d1SDavid du Colombier 		return -1;
563e12c5d1SDavid du Colombier 	}
573e12c5d1SDavid du Colombier 	d->bsize = ba->bsize;
589a747e4fSDavid du Colombier 	d->nb = length/d->bsize;
593e12c5d1SDavid du Colombier 	d->b2b = (d->bsize - sizeof(Dahdr))*8;
603e12c5d1SDavid du Colombier 	d->nab = (d->nb+d->b2b-1)/d->b2b;
613e12c5d1SDavid du Colombier 	d->p2b = d->bsize/sizeof(Dptr);
623e12c5d1SDavid du Colombier 	strncpy(d->name, ba->name, sizeof(d->name));
633e12c5d1SDavid du Colombier 
643e12c5d1SDavid du Colombier 	/*
653e12c5d1SDavid du Colombier 	 *  check allocation blocks for consistency
663e12c5d1SDavid du Colombier 	 */
673e12c5d1SDavid du Colombier 	if(bcinit(d, f, d->bsize) < 0){
683e12c5d1SDavid du Colombier 		fprint(2, "dinit: couldn't init block cache\n");
693e12c5d1SDavid du Colombier 		return -1;
703e12c5d1SDavid du Colombier 	}
713e12c5d1SDavid du Colombier 	for(i = 0; i < d->nab; i++){
723e12c5d1SDavid du Colombier 		b = bcread(d, i);
733e12c5d1SDavid du Colombier 		if(b == 0){
743e12c5d1SDavid du Colombier 			perror("dinit: read");
753e12c5d1SDavid du Colombier 			return -1;
763e12c5d1SDavid du Colombier 		}
773e12c5d1SDavid du Colombier 		ba = (Dalloc*)b->data;
783e12c5d1SDavid du Colombier 		if(ba->magic != Amagic){
797dd7cddfSDavid du Colombier 			fprint(2, "dinit: bad magic in alloc block %uld\n", i);
803e12c5d1SDavid du Colombier 			return -1;
813e12c5d1SDavid du Colombier 		}
823e12c5d1SDavid du Colombier 		if(d->bsize != ba->bsize){
837dd7cddfSDavid du Colombier 			fprint(2, "dinit: bad bsize in alloc block %uld\n", i);
843e12c5d1SDavid du Colombier 			return -1;
853e12c5d1SDavid du Colombier 		}
863e12c5d1SDavid du Colombier 		if(d->nab != ba->nab){
877dd7cddfSDavid du Colombier 			fprint(2, "dinit: bad nab in alloc block %uld\n", i);
883e12c5d1SDavid du Colombier 			return -1;
893e12c5d1SDavid du Colombier 		}
903e12c5d1SDavid du Colombier 		if(strncmp(d->name, ba->name, sizeof(d->name))){
917dd7cddfSDavid du Colombier 			fprint(2, "dinit: bad name in alloc block %uld\n", i);
923e12c5d1SDavid du Colombier 			return -1;
933e12c5d1SDavid du Colombier 		}
943e12c5d1SDavid du Colombier 	}
953e12c5d1SDavid du Colombier 	return 0;
963e12c5d1SDavid du Colombier }
973e12c5d1SDavid du Colombier 
983e12c5d1SDavid du Colombier /*
993e12c5d1SDavid du Colombier  *  format the disk as a cache
1003e12c5d1SDavid du Colombier  */
1013e12c5d1SDavid du Colombier int
1023e12c5d1SDavid du Colombier dformat(Disk *d, int f, char *name, ulong bsize, ulong psize)
1033e12c5d1SDavid du Colombier {
1043e12c5d1SDavid du Colombier 	int	i;
1059a747e4fSDavid du Colombier 	uvlong	length;
1063e12c5d1SDavid du Colombier 	Bbuf	*b;
1073e12c5d1SDavid du Colombier 	Dalloc	*ba;
108*41fb754aSDavid du Colombier 	Dir	*dir;
1093e12c5d1SDavid du Colombier 	Dptr	dptr;
1103e12c5d1SDavid du Colombier 
1113e12c5d1SDavid du Colombier 	fprint(2, "formatting disk\n");
1123e12c5d1SDavid du Colombier 
1133e12c5d1SDavid du Colombier 	/*
1143e12c5d1SDavid du Colombier 	 *  calculate basic numbers
1153e12c5d1SDavid du Colombier 	 */
1169a747e4fSDavid du Colombier 	dir = dirfstat(f);
1179a747e4fSDavid du Colombier 	if(dir == nil)
1183e12c5d1SDavid du Colombier 		return -1;
1199a747e4fSDavid du Colombier 	length = dir->length;
1203e12c5d1SDavid du Colombier 	d->bsize = bsize;
1213e12c5d1SDavid du Colombier 	if((d->bsize % psize) != 0){
1223e12c5d1SDavid du Colombier 		fprint(2, "cfs: logical bsize not multiple of physical\n");
1233e12c5d1SDavid du Colombier 		return -1;
1243e12c5d1SDavid du Colombier 	}
1259a747e4fSDavid du Colombier 	d->nb = length/d->bsize;
1263e12c5d1SDavid du Colombier 	d->b2b = (d->bsize - sizeof(Dahdr))*8;
1273e12c5d1SDavid du Colombier 	d->nab = (d->nb+d->b2b-1)/d->b2b;
1283e12c5d1SDavid du Colombier 	d->p2b = d->bsize/sizeof(Dptr);
1293e12c5d1SDavid du Colombier 
1303e12c5d1SDavid du Colombier 	/*
1313e12c5d1SDavid du Colombier 	 *  init allocation blocks
1323e12c5d1SDavid du Colombier 	 */
1333e12c5d1SDavid du Colombier 	if(bcinit(d, f, d->bsize) < 0)
1343e12c5d1SDavid du Colombier 		return -1;
1353e12c5d1SDavid du Colombier 	for(i = 0; i < d->nab; i++){
1363e12c5d1SDavid du Colombier 		b = bcalloc(d, i);
1373e12c5d1SDavid du Colombier 		if(b == 0){
1383e12c5d1SDavid du Colombier 			perror("cfs: bcalloc");
1393e12c5d1SDavid du Colombier 			return -1;
1403e12c5d1SDavid du Colombier 		}
1413e12c5d1SDavid du Colombier 		memset(b->data, 0, d->bsize);
1423e12c5d1SDavid du Colombier 		ba = (Dalloc*)b->data;
1433e12c5d1SDavid du Colombier 		ba->magic = Amagic;
1443e12c5d1SDavid du Colombier 		ba->bsize = d->bsize;
1453e12c5d1SDavid du Colombier 		ba->nab = d->nab;
1463e12c5d1SDavid du Colombier 		strncpy(ba->name, name, sizeof(ba->name));
1473e12c5d1SDavid du Colombier 		bcmark(d, b);
1483e12c5d1SDavid du Colombier 	}
1493e12c5d1SDavid du Colombier 
1503e12c5d1SDavid du Colombier 	/*
1513e12c5d1SDavid du Colombier 	 *  allocate allocation blocks
1523e12c5d1SDavid du Colombier 	 */
1533e12c5d1SDavid du Colombier 	for(i = 0; i < d->nab; i++)
15422a127bbSDavid du Colombier 		if(dalloc(d, &dptr) == Notabno){
1553e12c5d1SDavid du Colombier 			fprint(2, "can't allocate allocation blocks\n");
1563e12c5d1SDavid du Colombier 			return -1;
1573e12c5d1SDavid du Colombier 		}
1583e12c5d1SDavid du Colombier 
1593e12c5d1SDavid du Colombier 	return bcsync(d);
1603e12c5d1SDavid du Colombier }
1613e12c5d1SDavid du Colombier 
1623e12c5d1SDavid du Colombier /*
1633e12c5d1SDavid du Colombier  *  allocate a block from a bit vector page
1643e12c5d1SDavid du Colombier  *
1653e12c5d1SDavid du Colombier  *  a return value of Notabno means no blocks left
1663e12c5d1SDavid du Colombier  */
1673e12c5d1SDavid du Colombier static ulong
1683e12c5d1SDavid du Colombier _balloc(Dalloc *ba, ulong max)
1693e12c5d1SDavid du Colombier {
170*41fb754aSDavid du Colombier 	int len;	/* number of valid words */
1713e12c5d1SDavid du Colombier 	ulong i;	/* bit position in long */
1723e12c5d1SDavid du Colombier 	ulong m;	/* 1<<i */
1733e12c5d1SDavid du Colombier 	ulong v;	/* old value of long */
174*41fb754aSDavid du Colombier 	ulong *p, *e;
1753e12c5d1SDavid du Colombier 
1763e12c5d1SDavid du Colombier 	/*
1773e12c5d1SDavid du Colombier 	 *  find a word with a 0 bit
1783e12c5d1SDavid du Colombier 	 */
1793e12c5d1SDavid du Colombier 	len = (max+BtoUL-1)/BtoUL;
1803e12c5d1SDavid du Colombier 	for(p = ba->bits, e = p + len; p < e; p++)
1813e12c5d1SDavid du Colombier 		if(*p != 0xFFFFFFFF)
1823e12c5d1SDavid du Colombier 			break;
1833e12c5d1SDavid du Colombier 	if(p == e)
1843e12c5d1SDavid du Colombier 		return Notabno;
1853e12c5d1SDavid du Colombier 
1863e12c5d1SDavid du Colombier 	/*
1873e12c5d1SDavid du Colombier 	 *  find the first 0 bit
1883e12c5d1SDavid du Colombier 	 */
1893e12c5d1SDavid du Colombier 	v = *p;
1903e12c5d1SDavid du Colombier 	for(m = 1, i = 0; i < BtoUL; i++, m <<= 1)
1913e12c5d1SDavid du Colombier 		if((m|v) != v)
1923e12c5d1SDavid du Colombier 			break;
1933e12c5d1SDavid du Colombier 
1943e12c5d1SDavid du Colombier 	/*
1953e12c5d1SDavid du Colombier 	 *  calculate block number
1963e12c5d1SDavid du Colombier 	 */
1973e12c5d1SDavid du Colombier 	i += (p - ba->bits)*BtoUL;
1983e12c5d1SDavid du Colombier 	if(i >= max)
1993e12c5d1SDavid du Colombier 		return Notabno;
2003e12c5d1SDavid du Colombier 
2013e12c5d1SDavid du Colombier 	/*
2023e12c5d1SDavid du Colombier 	 *  set bit to 1
2033e12c5d1SDavid du Colombier 	 */
2043e12c5d1SDavid du Colombier 	*p = v | m;
2053e12c5d1SDavid du Colombier 	return i;
2063e12c5d1SDavid du Colombier }
2073e12c5d1SDavid du Colombier 
2083e12c5d1SDavid du Colombier /*
2093e12c5d1SDavid du Colombier  *  allocate a block
2103e12c5d1SDavid du Colombier  *
2113e12c5d1SDavid du Colombier  *  return Notabno if none left
2123e12c5d1SDavid du Colombier  */
2133e12c5d1SDavid du Colombier ulong
2143e12c5d1SDavid du Colombier dalloc(Disk *d, Dptr *p)
2153e12c5d1SDavid du Colombier {
216*41fb754aSDavid du Colombier 	ulong	bno, max, rv;
2173e12c5d1SDavid du Colombier 	Bbuf	*b;
2183e12c5d1SDavid du Colombier 	Dalloc	*ba;
2193e12c5d1SDavid du Colombier 
2203e12c5d1SDavid du Colombier 	max = d->nb;
2213e12c5d1SDavid du Colombier 	for(bno = 0; bno < d->nab; bno++){
2223e12c5d1SDavid du Colombier 		b = bcread(d, bno);
2233e12c5d1SDavid du Colombier 		ba = (Dalloc*)b->data;
2243e12c5d1SDavid du Colombier 		rv = _balloc(ba, max > d->b2b ? d->b2b : max);
2253e12c5d1SDavid du Colombier 		if(rv != Notabno){
2263e12c5d1SDavid du Colombier 			rv = bno*d->b2b + rv;
2273e12c5d1SDavid du Colombier 			if(p){
2283e12c5d1SDavid du Colombier 				p->start = p->end = 0;
2293e12c5d1SDavid du Colombier 				p->bno = rv;
2303e12c5d1SDavid du Colombier 			}
2313e12c5d1SDavid du Colombier 			bcmark(d, b);
2323e12c5d1SDavid du Colombier 			return rv;
2333e12c5d1SDavid du Colombier 		}
2343e12c5d1SDavid du Colombier 		max -= d->b2b;
2353e12c5d1SDavid du Colombier 	}
2363e12c5d1SDavid du Colombier 	if(p)
2373e12c5d1SDavid du Colombier 		p->bno = Notabno;
2383e12c5d1SDavid du Colombier 	return Notabno;
2393e12c5d1SDavid du Colombier }
2403e12c5d1SDavid du Colombier 
2413e12c5d1SDavid du Colombier /*
2423e12c5d1SDavid du Colombier  *  allocate a block of pointers
2433e12c5d1SDavid du Colombier  */
2443e12c5d1SDavid du Colombier ulong
2453e12c5d1SDavid du Colombier dpalloc(Disk *d, Dptr *p)
2463e12c5d1SDavid du Colombier {
2473e12c5d1SDavid du Colombier 	Bbuf *b;
248*41fb754aSDavid du Colombier 	Dptr *sp, *ep;
2493e12c5d1SDavid du Colombier 
2503e12c5d1SDavid du Colombier 	if(dalloc(d, p) == Notabno)
2513e12c5d1SDavid du Colombier 		return Notabno;
2523e12c5d1SDavid du Colombier 
2533e12c5d1SDavid du Colombier 	/*
2543e12c5d1SDavid du Colombier 	 *  allocate the page and invalidate all the
2553e12c5d1SDavid du Colombier 	 *  pointers
2563e12c5d1SDavid du Colombier 	 */
2573e12c5d1SDavid du Colombier 	b = bcalloc(d, p->bno);
2583e12c5d1SDavid du Colombier 	if(b == 0)
2593e12c5d1SDavid du Colombier 		return -1;
2603e12c5d1SDavid du Colombier 	sp = (Dptr*)b->data;
2613e12c5d1SDavid du Colombier 	for(ep = sp + d->p2b; sp < ep; sp++){
2623e12c5d1SDavid du Colombier 		sp->bno = Notabno;
2633e12c5d1SDavid du Colombier 		sp->start = sp->end = 0;
2643e12c5d1SDavid du Colombier 	}
2653e12c5d1SDavid du Colombier 	p->bno |= Indbno;
2663e12c5d1SDavid du Colombier 	p->start = 0;
2673e12c5d1SDavid du Colombier 	p->end = d->bsize;
2683e12c5d1SDavid du Colombier 
2693e12c5d1SDavid du Colombier 	/*
2703e12c5d1SDavid du Colombier 	 *  mark the page as dirty
2713e12c5d1SDavid du Colombier 	 */
2723e12c5d1SDavid du Colombier 	bcmark(d, b);
2733e12c5d1SDavid du Colombier 	return 0;
2743e12c5d1SDavid du Colombier }
2753e12c5d1SDavid du Colombier 
2763e12c5d1SDavid du Colombier /*
2773e12c5d1SDavid du Colombier  *  free a block
2783e12c5d1SDavid du Colombier  */
2793e12c5d1SDavid du Colombier int
2803e12c5d1SDavid du Colombier _bfree(Disk *d, ulong i)
2813e12c5d1SDavid du Colombier {
282*41fb754aSDavid du Colombier 	ulong bno, m;
2833e12c5d1SDavid du Colombier 	ulong *p;
2843e12c5d1SDavid du Colombier 	Bbuf *b;
2853e12c5d1SDavid du Colombier 	Dalloc *ba;
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 	ulong bno;
317*41fb754aSDavid du Colombier 	Dptr *sp, *ep;
318*41fb754aSDavid du Colombier 	Bbuf *b;
3193e12c5d1SDavid du Colombier 
3203e12c5d1SDavid du Colombier 	bno = dp->bno;
3213e12c5d1SDavid du Colombier 	dp->bno = Notabno;
3223e12c5d1SDavid du Colombier 
3233e12c5d1SDavid du Colombier 	/*
3243e12c5d1SDavid du Colombier 	 *  nothing to free
3253e12c5d1SDavid du Colombier 	 */
3263e12c5d1SDavid du Colombier 	if(bno == Notabno)
3273e12c5d1SDavid du Colombier 		return 0;
3283e12c5d1SDavid du Colombier 
3293e12c5d1SDavid du Colombier 	/*
3303e12c5d1SDavid du Colombier 	 *  direct pointer
3313e12c5d1SDavid du Colombier 	 */
3323e12c5d1SDavid du Colombier 	if((bno & Indbno) == 0)
3333e12c5d1SDavid du Colombier 		return _bfree(d, bno);
3343e12c5d1SDavid du Colombier 
3353e12c5d1SDavid du Colombier 	/*
3363e12c5d1SDavid du Colombier 	 *  first indirect page
3373e12c5d1SDavid du Colombier 	 */
3383e12c5d1SDavid du Colombier 	bno &= ~Indbno;
3393e12c5d1SDavid du Colombier 	_bfree(d, bno);
3403e12c5d1SDavid du Colombier 
3413e12c5d1SDavid du Colombier 	/*
3423e12c5d1SDavid du Colombier 	 *  then all the pages it points to
3433e12c5d1SDavid du Colombier 	 *
344*41fb754aSDavid du Colombier 	 *	DANGER: this algorithm may fail if there are more
3453e12c5d1SDavid du Colombier 	 *		allocation blocks than block buffers
3463e12c5d1SDavid du Colombier 	 */
3473e12c5d1SDavid du Colombier 	b = bcread(d, bno);
3483e12c5d1SDavid du Colombier 	if(b == 0)
3493e12c5d1SDavid du Colombier 		return -1;
3503e12c5d1SDavid du Colombier 	sp = (Dptr*)b->data;
3513e12c5d1SDavid du Colombier 	for(ep = sp + d->p2b; sp < ep; sp++)
3523e12c5d1SDavid du Colombier 		if(dfree(d, sp) < 0)
3533e12c5d1SDavid du Colombier 			return -1;
3543e12c5d1SDavid du Colombier 	return 0;
3553e12c5d1SDavid du Colombier }
356