xref: /plan9/sys/src/cmd/cfs/disk.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
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 {
17*9a747e4fSDavid du Colombier 	Dir	*dir;
183e12c5d1SDavid du Colombier 	char	buf[1024];
193e12c5d1SDavid du Colombier 	Dalloc	*ba;
20*9a747e4fSDavid du Colombier 	uvlong	length;
213e12c5d1SDavid du Colombier 	ulong	i;
223e12c5d1SDavid du Colombier 	Bbuf	*b;
233e12c5d1SDavid du Colombier 
243e12c5d1SDavid du Colombier 	/*
253e12c5d1SDavid du Colombier 	 *  get disk size
263e12c5d1SDavid du Colombier 	 */
27*9a747e4fSDavid du Colombier 	dir = dirfstat(f);
28*9a747e4fSDavid du Colombier 	if(dir == nil){
293e12c5d1SDavid du Colombier 		perror("dinit: stat");
303e12c5d1SDavid du Colombier 		return -1;
313e12c5d1SDavid du Colombier 	}
32*9a747e4fSDavid du Colombier 	length = dir->length;
33*9a747e4fSDavid du Colombier 	free(dir);
343e12c5d1SDavid du Colombier 
353e12c5d1SDavid du Colombier 	/*
363e12c5d1SDavid du Colombier 	 *  read first physical block to get logical block size, number of inodes,
373e12c5d1SDavid du Colombier 	 *  and number 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;
58*9a747e4fSDavid 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 	}
963e12c5d1SDavid du Colombier 
973e12c5d1SDavid du Colombier 	return 0;
983e12c5d1SDavid du Colombier }
993e12c5d1SDavid du Colombier 
1003e12c5d1SDavid du Colombier /*
1013e12c5d1SDavid du Colombier  *  format the disk as a cache
1023e12c5d1SDavid du Colombier  */
1033e12c5d1SDavid du Colombier int
1043e12c5d1SDavid du Colombier dformat(Disk *d, int f, char *name, ulong bsize, ulong psize)
1053e12c5d1SDavid du Colombier {
1063e12c5d1SDavid du Colombier 	int	i;
107*9a747e4fSDavid du Colombier 	Dir	*dir;
108*9a747e4fSDavid du Colombier 	uvlong	length;
1093e12c5d1SDavid du Colombier 	Bbuf	*b;
1103e12c5d1SDavid du Colombier 	Dalloc	*ba;
1113e12c5d1SDavid du Colombier 	Dptr	dptr;
1123e12c5d1SDavid du Colombier 
1133e12c5d1SDavid du Colombier 	fprint(2, "formatting disk\n");
1143e12c5d1SDavid du Colombier 
1153e12c5d1SDavid du Colombier 	/*
1163e12c5d1SDavid du Colombier 	 *  calculate basic numbers
1173e12c5d1SDavid du Colombier 	 */
118*9a747e4fSDavid du Colombier 	dir = dirfstat(f);
119*9a747e4fSDavid du Colombier 	if(dir == nil)
1203e12c5d1SDavid du Colombier 		return -1;
121*9a747e4fSDavid du Colombier 	length = dir->length;
1223e12c5d1SDavid du Colombier 	d->bsize = bsize;
1233e12c5d1SDavid du Colombier 	if((d->bsize % psize) != 0){
1243e12c5d1SDavid du Colombier 		fprint(2, "cfs: logical bsize not multiple of physical\n");
1253e12c5d1SDavid du Colombier 		return -1;
1263e12c5d1SDavid du Colombier 	}
127*9a747e4fSDavid du Colombier 	d->nb = length/d->bsize;
1283e12c5d1SDavid du Colombier 	d->b2b = (d->bsize - sizeof(Dahdr))*8;
1293e12c5d1SDavid du Colombier 	d->nab = (d->nb+d->b2b-1)/d->b2b;
1303e12c5d1SDavid du Colombier 	d->p2b = d->bsize/sizeof(Dptr);
1313e12c5d1SDavid du Colombier 
1323e12c5d1SDavid du Colombier 	/*
1333e12c5d1SDavid du Colombier 	 *  init allocation blocks
1343e12c5d1SDavid du Colombier 	 */
1353e12c5d1SDavid du Colombier 	if(bcinit(d, f, d->bsize) < 0)
1363e12c5d1SDavid du Colombier 		return -1;
1373e12c5d1SDavid du Colombier 	for(i = 0; i < d->nab; i++){
1383e12c5d1SDavid du Colombier 		b = bcalloc(d, i);
1393e12c5d1SDavid du Colombier 		if(b == 0){
1403e12c5d1SDavid du Colombier 			perror("cfs: bcalloc");
1413e12c5d1SDavid du Colombier 			return -1;
1423e12c5d1SDavid du Colombier 		}
1433e12c5d1SDavid du Colombier 		memset(b->data, 0, d->bsize);
1443e12c5d1SDavid du Colombier 		ba = (Dalloc*)b->data;
1453e12c5d1SDavid du Colombier 		ba->magic = Amagic;
1463e12c5d1SDavid du Colombier 		ba->bsize = d->bsize;
1473e12c5d1SDavid du Colombier 		ba->nab = d->nab;
1483e12c5d1SDavid du Colombier 		strncpy(ba->name, name, sizeof(ba->name));
1493e12c5d1SDavid du Colombier 		bcmark(d, b);
1503e12c5d1SDavid du Colombier 	}
1513e12c5d1SDavid du Colombier 
1523e12c5d1SDavid du Colombier 	/*
1533e12c5d1SDavid du Colombier 	 *  allocate allocation blocks
1543e12c5d1SDavid du Colombier 	 */
1553e12c5d1SDavid du Colombier 	for(i = 0; i < d->nab; i++)
1563e12c5d1SDavid du Colombier 		if(dalloc(d, &dptr) < 0){
1573e12c5d1SDavid du Colombier 			fprint(2, "can't allocate allocation blocks\n");
1583e12c5d1SDavid du Colombier 			return -1;
1593e12c5d1SDavid du Colombier 		}
1603e12c5d1SDavid du Colombier 
1613e12c5d1SDavid du Colombier 	return bcsync(d);
1623e12c5d1SDavid du Colombier }
1633e12c5d1SDavid du Colombier 
1643e12c5d1SDavid du Colombier /*
1653e12c5d1SDavid du Colombier  *  allocate a block from a bit vector page
1663e12c5d1SDavid du Colombier  *
1673e12c5d1SDavid du Colombier  *  a return value of Notabno means no blocks left
1683e12c5d1SDavid du Colombier  */
1693e12c5d1SDavid du Colombier static ulong
1703e12c5d1SDavid du Colombier _balloc(Dalloc *ba, ulong max)
1713e12c5d1SDavid du Colombier {
1723e12c5d1SDavid du Colombier 	ulong *p;
1733e12c5d1SDavid du Colombier 	ulong *e;
1743e12c5d1SDavid du Colombier 	ulong i;	/* bit position in long */
1753e12c5d1SDavid du Colombier 	ulong m;	/* 1<<i */
1763e12c5d1SDavid du Colombier 	ulong v;	/* old value of long */
1773e12c5d1SDavid du Colombier 	int len;	/* number of valid words */
1783e12c5d1SDavid du Colombier 
1793e12c5d1SDavid du Colombier 	/*
1803e12c5d1SDavid du Colombier 	 *  find a word with a 0 bit
1813e12c5d1SDavid du Colombier 	 */
1823e12c5d1SDavid du Colombier 	len = (max+BtoUL-1)/BtoUL;
1833e12c5d1SDavid du Colombier 	for(p = ba->bits, e = p + len; p < e; p++)
1843e12c5d1SDavid du Colombier 		if(*p != 0xFFFFFFFF)
1853e12c5d1SDavid du Colombier 			break;
1863e12c5d1SDavid du Colombier 	if(p == e)
1873e12c5d1SDavid du Colombier 		return Notabno;
1883e12c5d1SDavid du Colombier 
1893e12c5d1SDavid du Colombier 	/*
1903e12c5d1SDavid du Colombier 	 *  find the first 0 bit
1913e12c5d1SDavid du Colombier 	 */
1923e12c5d1SDavid du Colombier 	v = *p;
1933e12c5d1SDavid du Colombier 	for(m = 1, i = 0; i<BtoUL; i++, m<<=1)
1943e12c5d1SDavid du Colombier 		if((m|v) != v)
1953e12c5d1SDavid du Colombier 			break;
1963e12c5d1SDavid du Colombier 
1973e12c5d1SDavid du Colombier 	/*
1983e12c5d1SDavid du Colombier 	 *  calculate block number
1993e12c5d1SDavid du Colombier 	 */
2003e12c5d1SDavid du Colombier 	i += (p - ba->bits)*BtoUL;
2013e12c5d1SDavid du Colombier 	if(i >= max)
2023e12c5d1SDavid du Colombier 		return Notabno;
2033e12c5d1SDavid du Colombier 
2043e12c5d1SDavid du Colombier 	/*
2053e12c5d1SDavid du Colombier 	 *  set bit to 1
2063e12c5d1SDavid du Colombier 	 */
2073e12c5d1SDavid du Colombier 	*p = v | m;
2083e12c5d1SDavid du Colombier 	return i;
2093e12c5d1SDavid du Colombier }
2103e12c5d1SDavid du Colombier 
2113e12c5d1SDavid du Colombier /*
2123e12c5d1SDavid du Colombier  *  allocate a block
2133e12c5d1SDavid du Colombier  *
2143e12c5d1SDavid du Colombier  *  return Notabno if none left
2153e12c5d1SDavid du Colombier  */
2163e12c5d1SDavid du Colombier ulong
2173e12c5d1SDavid du Colombier dalloc(Disk *d, Dptr *p)
2183e12c5d1SDavid du Colombier {
2193e12c5d1SDavid du Colombier 	ulong	bno;
2203e12c5d1SDavid du Colombier 	Bbuf	*b;
2213e12c5d1SDavid du Colombier 	Dalloc	*ba;
2223e12c5d1SDavid du Colombier 	ulong	rv;
2233e12c5d1SDavid du Colombier 	ulong	max;
2243e12c5d1SDavid du Colombier 
2253e12c5d1SDavid du Colombier 	max = d->nb;
2263e12c5d1SDavid du Colombier 	for(bno = 0; bno < d->nab; bno++){
2273e12c5d1SDavid du Colombier 		b = bcread(d, bno);
2283e12c5d1SDavid du Colombier 		ba = (Dalloc*)b->data;
2293e12c5d1SDavid du Colombier 		rv = _balloc(ba, max > d->b2b ? d->b2b : max);
2303e12c5d1SDavid du Colombier 		if(rv != Notabno){
2313e12c5d1SDavid du Colombier 			rv = bno*d->b2b + rv;
2323e12c5d1SDavid du Colombier 			if(p){
2333e12c5d1SDavid du Colombier 				p->start = p->end = 0;
2343e12c5d1SDavid du Colombier 				p->bno = rv;
2353e12c5d1SDavid du Colombier 			}
2363e12c5d1SDavid du Colombier 			bcmark(d, b);
2373e12c5d1SDavid du Colombier 			return rv;
2383e12c5d1SDavid du Colombier 		}
2393e12c5d1SDavid du Colombier 		max -= d->b2b;
2403e12c5d1SDavid du Colombier 	}
2413e12c5d1SDavid du Colombier 	if(p)
2423e12c5d1SDavid du Colombier 		p->bno = Notabno;
2433e12c5d1SDavid du Colombier 	return Notabno;
2443e12c5d1SDavid du Colombier }
2453e12c5d1SDavid du Colombier 
2463e12c5d1SDavid du Colombier /*
2473e12c5d1SDavid du Colombier  *  allocate a block of pointers
2483e12c5d1SDavid du Colombier  */
2493e12c5d1SDavid du Colombier ulong
2503e12c5d1SDavid du Colombier dpalloc(Disk *d, Dptr *p)
2513e12c5d1SDavid du Colombier {
2523e12c5d1SDavid du Colombier 	Bbuf *b;
2533e12c5d1SDavid du Colombier 	Dptr *sp;
2543e12c5d1SDavid du Colombier 	Dptr *ep;
2553e12c5d1SDavid du Colombier 
2563e12c5d1SDavid du Colombier 	if(dalloc(d, p) == Notabno)
2573e12c5d1SDavid du Colombier 		return Notabno;
2583e12c5d1SDavid du Colombier 
2593e12c5d1SDavid du Colombier 	/*
2603e12c5d1SDavid du Colombier 	 *  allocate the page and invalidate all the
2613e12c5d1SDavid du Colombier 	 *  pointers
2623e12c5d1SDavid du Colombier 	 */
2633e12c5d1SDavid du Colombier 	b = bcalloc(d, p->bno);
2643e12c5d1SDavid du Colombier 	if(b == 0)
2653e12c5d1SDavid du Colombier 		return -1;
2663e12c5d1SDavid du Colombier 	sp = (Dptr*)b->data;
2673e12c5d1SDavid du Colombier 	for(ep = sp + d->p2b; sp < ep; sp++){
2683e12c5d1SDavid du Colombier 		sp->bno = Notabno;
2693e12c5d1SDavid du Colombier 		sp->start = sp->end = 0;
2703e12c5d1SDavid du Colombier 	}
2713e12c5d1SDavid du Colombier 	p->bno |= Indbno;
2723e12c5d1SDavid du Colombier 	p->start = 0;
2733e12c5d1SDavid du Colombier 	p->end = d->bsize;
2743e12c5d1SDavid du Colombier 
2753e12c5d1SDavid du Colombier 	/*
2763e12c5d1SDavid du Colombier 	 *  mark the page as dirty
2773e12c5d1SDavid du Colombier 	 */
2783e12c5d1SDavid du Colombier 	bcmark(d, b);
2793e12c5d1SDavid du Colombier 	return 0;
2803e12c5d1SDavid du Colombier }
2813e12c5d1SDavid du Colombier 
2823e12c5d1SDavid du Colombier /*
2833e12c5d1SDavid du Colombier  *  free a block
2843e12c5d1SDavid du Colombier  */
2853e12c5d1SDavid du Colombier int
2863e12c5d1SDavid du Colombier _bfree(Disk *d, ulong i)
2873e12c5d1SDavid du Colombier {
2883e12c5d1SDavid du Colombier 	ulong *p;
2893e12c5d1SDavid du Colombier 	ulong m;
2903e12c5d1SDavid du Colombier 	Bbuf *b;
2913e12c5d1SDavid du Colombier 	Dalloc *ba;
2923e12c5d1SDavid du Colombier 	ulong bno;
2933e12c5d1SDavid du Colombier 
2943e12c5d1SDavid du Colombier 	/*
2953e12c5d1SDavid du Colombier 	 *  get correct allocation block
2963e12c5d1SDavid du Colombier 	 */
2973e12c5d1SDavid du Colombier 	bno = i/d->b2b;
2983e12c5d1SDavid du Colombier 	if(bno >= d->nab)
2993e12c5d1SDavid du Colombier 		return -1;
3003e12c5d1SDavid du Colombier 	b = bcread(d, bno);
3013e12c5d1SDavid du Colombier 	if(b == 0)
3023e12c5d1SDavid du Colombier 		return -1;
3033e12c5d1SDavid du Colombier 	ba = (Dalloc*)b->data;
3043e12c5d1SDavid du Colombier 
3053e12c5d1SDavid du Colombier 	/*
3063e12c5d1SDavid du Colombier 	 *  change bit
3073e12c5d1SDavid du Colombier 	 */
3083e12c5d1SDavid du Colombier 	i -= bno*d->b2b;
3093e12c5d1SDavid du Colombier 	p = ba->bits + (i/BtoUL);
3103e12c5d1SDavid du Colombier 	m = 1<<(i%BtoUL);
3113e12c5d1SDavid du Colombier 	*p &= ~m;
3123e12c5d1SDavid du Colombier 	bcmark(d, b);
3133e12c5d1SDavid du Colombier 
3143e12c5d1SDavid du Colombier 	return 0;
3153e12c5d1SDavid du Colombier }
3163e12c5d1SDavid du Colombier 
3173e12c5d1SDavid du Colombier /*
3183e12c5d1SDavid du Colombier  *  free a block (or blocks)
3193e12c5d1SDavid du Colombier  */
3203e12c5d1SDavid du Colombier int
3213e12c5d1SDavid du Colombier dfree(Disk *d, Dptr *dp)
3223e12c5d1SDavid du Colombier {
3233e12c5d1SDavid du Colombier 	Dptr *sp;
3243e12c5d1SDavid du Colombier 	Dptr *ep;
3253e12c5d1SDavid du Colombier 	Bbuf *b;
3263e12c5d1SDavid du Colombier 	ulong bno;
3273e12c5d1SDavid du Colombier 
3283e12c5d1SDavid du Colombier 	bno = dp->bno;
3293e12c5d1SDavid du Colombier 	dp->bno = Notabno;
3303e12c5d1SDavid du Colombier 
3313e12c5d1SDavid du Colombier 	/*
3323e12c5d1SDavid du Colombier 	 *  nothing to free
3333e12c5d1SDavid du Colombier 	 */
3343e12c5d1SDavid du Colombier 	if(bno == Notabno)
3353e12c5d1SDavid du Colombier 		return 0;
3363e12c5d1SDavid du Colombier 
3373e12c5d1SDavid du Colombier 	/*
3383e12c5d1SDavid du Colombier 	 *  direct pointer
3393e12c5d1SDavid du Colombier 	 */
3403e12c5d1SDavid du Colombier 	if((bno & Indbno) == 0)
3413e12c5d1SDavid du Colombier 		return _bfree(d, bno);
3423e12c5d1SDavid du Colombier 
3433e12c5d1SDavid du Colombier 	/*
3443e12c5d1SDavid du Colombier 	 *  first indirect page
3453e12c5d1SDavid du Colombier 	 */
3463e12c5d1SDavid du Colombier 	bno &= ~Indbno;
3473e12c5d1SDavid du Colombier 	_bfree(d, bno);
3483e12c5d1SDavid du Colombier 
3493e12c5d1SDavid du Colombier 	/*
3503e12c5d1SDavid du Colombier 	 *  then all the pages it points to
3513e12c5d1SDavid du Colombier 	 *
3523e12c5d1SDavid du Colombier 	 *	DANGER: this algorithm may fail is their are more
3533e12c5d1SDavid du Colombier 	 *		allocation blocks than block buffers
3543e12c5d1SDavid du Colombier 	 */
3553e12c5d1SDavid du Colombier 	b = bcread(d, bno);
3563e12c5d1SDavid du Colombier 	if(b == 0)
3573e12c5d1SDavid du Colombier 		return -1;
3583e12c5d1SDavid du Colombier 	sp = (Dptr*)b->data;
3593e12c5d1SDavid du Colombier 	for(ep = sp + d->p2b; sp < ep; sp++)
3603e12c5d1SDavid du Colombier 		if(dfree(d, sp) < 0)
3613e12c5d1SDavid du Colombier 			return -1;
3623e12c5d1SDavid du Colombier 
3633e12c5d1SDavid du Colombier 	return 0;
3643e12c5d1SDavid du Colombier }
365