diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index 745050c7d6c..881fdca27b5 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -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. * diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index 3c9c8851dd2..8618123a9c2 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -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); diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index 6c6fe5eba00..3bfc1b99541 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -420,6 +420,10 @@ loop: 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. */