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.
This commit is contained in:
Scott Long 2004-10-09 02:53:47 +00:00
parent 42c7735ce5
commit e7c4605481
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=136289

View File

@ -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 */
}