diff options
author | scottl <scottl@FreeBSD.org> | 2004-10-09 02:53:47 +0000 |
---|---|---|
committer | scottl <scottl@FreeBSD.org> | 2004-10-09 02:53:47 +0000 |
commit | bcad702d798cdd2d713e31f5f56c99261d297531 (patch) | |
tree | 39c06af27273e92145959cee51378ca8be3bb672 /sbin/growfs | |
parent | 7e9cf9f93431762f97cd654c8a0db849c20b6a5b (diff) | |
download | FreeBSD-src-bcad702d798cdd2d713e31f5f56c99261d297531.zip FreeBSD-src-bcad702d798cdd2d713e31f5f56c99261d297531.tar.gz |
3 important fixes for growfs:
1) ginode() is passed a cylinder group number and inode number. The inode
number is relative to the cg. Use this relative number rather than the
absolute inode number when searching the cg inode bitmap to see if the inode
is allocated. Using the absolute number quickly runs the check off the end
of the array and causes invalid inodes to be referenced.
2) ginode() checks the absolute indoe number to make sure that it is greater
than ROOTINO. However, the caller loops through all of the possible inode
numbers and directly passes in values that are < ROOTINO. Instead of halting
the program with an error, just return NULL.
3) When allocating new cylinder groups, growfs was initializing all of the
inodes in the group regardless of this only being required for UFS1. Not
doing this for UFS2 provides a significant performance increase.
These fixes allow growing a filesystem beyond a trivial amount and have
been tested to grow an 8GB filesystem to 1.9TB. Much more testing would
be appreciated.
Obtained from: Sandvine, Inc.
Diffstat (limited to 'sbin/growfs')
-rw-r--r-- | sbin/growfs/growfs.c | 64 |
1 files changed, 42 insertions, 22 deletions
diff --git a/sbin/growfs/growfs.c b/sbin/growfs/growfs.c index cf58071..8423743 100644 --- a/sbin/growfs/growfs.c +++ b/sbin/growfs/growfs.c @@ -447,22 +447,30 @@ initcg(int cylno, time_t utime, int fso, unsigned int Nflag) setbit(cg_inosused(&acg), i); acg.cg_cs.cs_nifree--; } - bzero(iobuf, sblock.fs_bsize); - for (i = 0; i < sblock.fs_ipg / INOPF(&sblock); i += sblock.fs_frag) { - dp1 = (struct ufs1_dinode *)iobuf; - dp2 = (struct ufs2_dinode *)iobuf; + /* + * XXX Newfs writes out two blocks of initialized inodes + * unconditionally. Should we check here to make sure that they + * were actually written? + */ + if (sblock.fs_magic == FS_UFS1_MAGIC) { + bzero(iobuf, sblock.fs_bsize); + for (i = 2 * sblock.fs_frag; i < sblock.fs_ipg / INOPF(&sblock); + i += sblock.fs_frag) { + dp1 = (struct ufs1_dinode *)iobuf; + dp2 = (struct ufs2_dinode *)iobuf; #ifdef FSIRAND - for (j = 0; j < INOPB(&sblock); j++) - if (sblock.fs_magic == FS_UFS1_MAGIC) { - dp1->di_gen = random(); - dp1++; - } else { - dp2->di_gen = random(); - dp2++; - } + for (j = 0; j < INOPB(&sblock); j++) + if (sblock.fs_magic == FS_UFS1_MAGIC) { + dp1->di_gen = random(); + dp1++; + } else { + dp2->di_gen = random(); + dp2++; + } #endif - wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i), - sblock.fs_bsize, iobuf, fso, Nflag); + wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i), + sblock.fs_bsize, iobuf, fso, Nflag); + } } if (cylno > 0) { /* @@ -1493,7 +1501,7 @@ updcsloc(time_t utime, int fsi, int fso, unsigned int Nflag) for(cylno=0; cylno<osblock.fs_ncg; cylno++) { DBG_PRINT1("scg doing cg (%d)\n", cylno); - for(inc=osblock.fs_ipg-1 ; inc>=0 ; inc--) { + for(inc=osblock.fs_ipg-1 ; inc>0 ; inc--) { updrefs(cylno, (ino_t)inc, bp, fsi, fso, Nflag); } } @@ -1549,6 +1557,9 @@ rdfs(ufs2_daddr_t bno, size_t size, void *bf, int fsi) DBG_ENTER; + if (bno < 0) { + err(32, "rdfs: attempting to read negative block number\n"); + } if (lseek(fsi, (off_t)bno * DEV_BSIZE, 0) < 0) { err(33, "rdfs: seek error: %jd", (intmax_t)bno); } @@ -1846,12 +1857,24 @@ ginode(ino_t inumber, int fsi, int cg) DBG_ENTER; - inumber += (cg * sblock.fs_ipg); + /* + * The inumber passed in is relative to the cg, so use it here to see + * if the inode has been allocated yet. + */ if (isclr(cg_inosused(&aocg), inumber)) { DBG_LEAVE; return NULL; } - if (inumber < ROOTINO || inumber > maxino) + /* + * Now make the inumber relative to the entire inode space so it can + * be sanity checked. + */ + inumber += (cg * sblock.fs_ipg); + if (inumber < ROOTINO) { + DBG_LEAVE; + return NULL; + } + if (inumber > maxino) errx(8, "bad inode number %d to ginode", inumber); if (startinum == 0 || inumber < startinum || inumber >= startinum + INOPB(&sblock)) { @@ -2385,10 +2408,6 @@ updrefs(int cg, ino_t in, struct gfs_bpp *bp, int fsi, int fso, unsigned int DBG_ENTER; - /* - * XXX We should skip unused inodes even from being read from disk - * here by using the bitmap. - */ ino = ginode(in, fsi, cg); if (ino == NULL) { DBG_LEAVE; @@ -2399,7 +2418,8 @@ updrefs(int cg, ino_t in, struct gfs_bpp *bp, int fsi, int fso, unsigned int DBG_LEAVE; return; /* only check DIR, FILE, LINK */ } - if (mode == IFLNK && DIP(ino, di_size) < (u_int64_t) sblock.fs_maxsymlinklen) { + if (mode == IFLNK && + DIP(ino, di_size) < (u_int64_t) sblock.fs_maxsymlinklen) { DBG_LEAVE; return; /* skip short symlinks */ } |