From bcad702d798cdd2d713e31f5f56c99261d297531 Mon Sep 17 00:00:00 2001 From: scottl Date: Sat, 9 Oct 2004 02:53:47 +0000 Subject: 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. --- sbin/growfs/growfs.c | 64 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 22 deletions(-) (limited to 'sbin/growfs') 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=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 */ } -- cgit v1.1