This patch fixes a bug on an active filesystem on which a snapshot

is being taken from panicing with either "freeing free block" or
"freeing free inode". The problem arises when the snapshot code
is scanning the filesystem looking for inodes with a reference
count of zero (e.g., unlinked but still open) so that it can
expunge them from its view. If it encounters a reclaimed vnode
and has to restart its scan, then it will panic if it encounters
and tries to free an inode that it has already processed. The fix
is to check each candidate inode to see if it has already been
processed before trying to delete it from the snapshot image.

Sponsored by:   DARPA & NAI Labs.
This commit is contained in:
Kirk McKusick 2003-02-22 00:29:51 +00:00
parent d60682c239
commit 37e2ebfdba
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=111239
3 changed files with 47 additions and 1 deletions

View File

@ -1933,6 +1933,47 @@ ffs_freefile(fs, devvp, ino, mode)
return (0);
}
/*
* Check to see if a file is free.
*/
int
ffs_checkfreefile(fs, devvp, ino)
struct fs *fs;
struct vnode *devvp;
ino_t ino;
{
struct cg *cgp;
struct buf *bp;
ufs2_daddr_t cgbno;
int error, ret, cg;
u_int8_t *inosused;
cg = ino_to_cg(fs, ino);
if (devvp->v_type != VCHR) {
/* devvp is a snapshot */
cgbno = fragstoblks(fs, cgtod(fs, cg));
} else {
/* devvp is a normal disk device */
cgbno = fsbtodb(fs, cgtod(fs, cg));
}
if ((u_int)ino >= fs->fs_ipg * fs->fs_ncg)
return (1);
if ((error = bread(devvp, cgbno, (int)fs->fs_cgsize, NOCRED, &bp))) {
brelse(bp);
return (1);
}
cgp = (struct cg *)bp->b_data;
if (!cg_chkmagic(cgp)) {
brelse(bp);
return (1);
}
inosused = cg_inosused(cgp);
ino %= fs->fs_ipg;
ret = isclr(inosused, ino);
brelse(bp);
return (ret);
}
/*
* Find a block of the specified size in the specified cylinder group.
*

View File

@ -63,12 +63,13 @@ int ffs_blkatoff(struct vnode *, off_t, char **, struct buf **);
void ffs_blkfree(struct fs *, struct vnode *, ufs2_daddr_t, long, ino_t);
ufs2_daddr_t ffs_blkpref_ufs1(struct inode *, ufs_lbn_t, int, ufs1_daddr_t *);
ufs2_daddr_t ffs_blkpref_ufs2(struct inode *, ufs_lbn_t, int, ufs2_daddr_t *);
int ffs_checkfreefile(struct fs *, struct vnode *, ino_t);
void ffs_clrblock(struct fs *, u_char *, ufs1_daddr_t);
void ffs_clusteracct (struct fs *, struct cg *, ufs1_daddr_t, int);
vfs_fhtovp_t ffs_fhtovp;
int ffs_flushfiles(struct mount *, int, struct thread *);
void ffs_fragacct(struct fs *, int, int32_t [], int);
int ffs_freefile(struct fs *, struct vnode *, ino_t, int );
int ffs_freefile(struct fs *, struct vnode *, ino_t, int);
int ffs_isblock(struct fs *, u_char *, ufs1_daddr_t);
void ffs_load_inode(struct buf *, struct inode *, struct fs *, ino_t);
int ffs_mountroot(void);

View File

@ -420,6 +420,10 @@ ffs_snapshot(mp, snapfile)
if (vn_lock(xvp, LK_EXCLUSIVE, td) != 0)
goto loop;
xp = VTOI(xvp);
if (ffs_checkfreefile(copy_fs, vp, xp->i_number)) {
VOP_UNLOCK(xvp, 0, td);
continue;
}
/*
* If there is a fragment, clear it here.
*/