diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index aa6f31c773e2..79fcb91148ee 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -71,7 +71,7 @@ static ufs_daddr_t ffs_clusteralloc __P((struct inode *, int, ufs_daddr_t, int)); static ino_t ffs_dirpref __P((struct inode *)); static ufs_daddr_t ffs_fragextend __P((struct inode *, int, long, int, int)); -static void ffs_fserr __P((struct fs *, u_int, char *)); +static void ffs_fserr __P((struct fs *, ino_t, char *)); static u_long ffs_hashalloc __P((struct inode *, int, long, int, allocfcn_t *)); static ino_t ffs_nodealloccg __P((struct inode *, int, ufs_daddr_t, int)); @@ -162,7 +162,7 @@ ffs_alloc(ip, lbn, bpref, size, cred, bnp) softdep_request_cleanup(fs, ITOV(ip)); goto retry; } - ffs_fserr(fs, cred->cr_uid, "file system full"); + ffs_fserr(fs, ip->i_number, "file system full"); uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); return (ENOSPC); } @@ -309,10 +309,11 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp) if (bno > 0) { bp->b_blkno = fsbtodb(fs, bno); if (!DOINGSOFTDEP(vp)) - ffs_blkfree(ip, bprev, (long)osize); + ffs_blkfree(fs, ip->i_devvp, bprev, (long)osize, + ip->i_number); if (nsize < request) - ffs_blkfree(ip, bno + numfrags(fs, nsize), - (long)(request - nsize)); + ffs_blkfree(fs, ip->i_devvp, bno + numfrags(fs, nsize), + (long)(request - nsize), ip->i_number); ip->i_blocks += btodb(nsize - osize); ip->i_flag |= IN_CHANGE | IN_UPDATE; allocbuf(bp, nsize); @@ -337,7 +338,7 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp) softdep_request_cleanup(fs, vp); goto retry; } - ffs_fserr(fs, cred->cr_uid, "file system full"); + ffs_fserr(fs, ip->i_number, "file system full"); uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); return (ENOSPC); } @@ -542,9 +543,9 @@ ffs_reallocblks(ap) #endif for (blkno = newblk, i = 0; i < len; i++, blkno += fs->fs_frag) { if (!DOINGSOFTDEP(vp)) - ffs_blkfree(ip, + ffs_blkfree(fs, ip->i_devvp, dbtofsb(fs, buflist->bs_children[i]->b_blkno), - fs->fs_bsize); + fs->fs_bsize, ip->i_number); buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno); #ifdef DIAGNOSTIC if (!ffs_checkblk(ip, @@ -652,7 +653,7 @@ ffs_valloc(pvp, mode, cred, vpp) ip->i_gen = random() / 2 + 1; return (0); noinodes: - ffs_fserr(fs, cred->cr_uid, "out of inodes"); + ffs_fserr(fs, pip->i_number, "out of inodes"); uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt); return (ENOSPC); } @@ -1427,48 +1428,52 @@ ffs_nodealloccg(ip, cg, ipref, mode) * block reassembly is checked. */ void -ffs_blkfree(ip, bno, size) - register struct inode *ip; +ffs_blkfree(fs, devvp, bno, size, inum) + struct fs *fs; + struct vnode *devvp; ufs_daddr_t bno; long size; + ino_t inum; { - register struct fs *fs; - register struct cg *cgp; + struct cg *cgp; struct buf *bp; ufs_daddr_t fragno, cgbno; int i, error, cg, blk, frags, bbase; u_int8_t *blksfree; -#ifdef DIAGNOSTIC - struct vnode *vp; -#endif + dev_t dev; - fs = ip->i_fs; + cg = dtog(fs, bno); + if (devvp->v_type != VCHR) { + /* devvp is a snapshot */ + dev = VTOI(devvp)->i_devvp->v_rdev; + cgbno = fragstoblks(fs, cgtod(fs, cg)); + } else { + /* devvp is a normal disk device */ + dev = devvp->v_rdev; + cgbno = fsbtodb(fs, cgtod(fs, cg)); + if ((devvp->v_flag & VCOPYONWRITE) && + ffs_snapblkfree(fs, devvp, bno, size, inum)) + return; + VOP_FREEBLKS(devvp, fsbtodb(fs, bno), size); + } #ifdef DIAGNOSTIC - if ((vp = ITOV(ip)) != NULL && vp->v_mount != NULL && - (vp->v_mount->mnt_kern_flag & MNTK_SUSPENDED)) + if (dev->si_mountpoint && + (dev->si_mountpoint->mnt_kern_flag & MNTK_SUSPENDED)) panic("ffs_blkfree: deallocation on suspended filesystem"); if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0 || fragnum(fs, bno) + numfrags(fs, size) > fs->fs_frag) { printf("dev=%s, bno = %ld, bsize = %ld, size = %ld, fs = %s\n", - devtoname(ip->i_dev), (long)bno, (long)fs->fs_bsize, size, - fs->fs_fsmnt); + devtoname(dev), (long)bno, (long)fs->fs_bsize, + size, fs->fs_fsmnt); panic("ffs_blkfree: bad size"); } #endif - if ((ip->i_devvp->v_flag & VCOPYONWRITE) && - ffs_snapblkfree(ip, bno, size)) - return; - VOP_FREEBLKS(ip->i_devvp, fsbtodb(fs, bno), size); - cg = dtog(fs, bno); if ((u_int)bno >= fs->fs_size) { - printf("bad block %ld, ino %lu\n", - (long)bno, (u_long)ip->i_number); - ffs_fserr(fs, ip->i_uid, "bad block"); + printf("bad block %ld, ino %lu\n", (long)bno, (u_long)inum); + ffs_fserr(fs, inum, "bad block"); return; } - error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), - (int)fs->fs_cgsize, NOCRED, &bp); - if (error) { + if ((error = bread(devvp, cgbno, (int)fs->fs_cgsize, NOCRED, &bp))) { brelse(bp); return; } @@ -1484,8 +1489,13 @@ ffs_blkfree(ip, bno, size) if (size == fs->fs_bsize) { fragno = fragstoblks(fs, cgbno); if (!ffs_isfreeblock(fs, blksfree, fragno)) { + if (devvp->v_type != VCHR) { + /* devvp is a snapshot */ + brelse(bp); + return; + } printf("dev = %s, block = %ld, fs = %s\n", - devtoname(ip->i_dev), (long)bno, fs->fs_fsmnt); + devtoname(dev), (long)bno, fs->fs_fsmnt); panic("ffs_blkfree: freeing free block"); } ffs_setblock(fs, blksfree, fragno); @@ -1510,7 +1520,7 @@ ffs_blkfree(ip, bno, size) for (i = 0; i < frags; i++) { if (isset(blksfree, cgbno + i)) { printf("dev = %s, block = %ld, fs = %s\n", - devtoname(ip->i_dev), (long)(bno + i), + devtoname(dev), (long)(bno + i), fs->fs_fsmnt); panic("ffs_blkfree: freeing free frag"); } @@ -1610,7 +1620,7 @@ ffs_vfree(pvp, ino, mode) softdep_freefile(pvp, ino, mode); return (0); } - return (ffs_freefile(VTOI(pvp), ino, mode)); + return (ffs_freefile(VTOI(pvp)->i_fs, VTOI(pvp)->i_devvp, ino, mode)); } /* @@ -1618,25 +1628,32 @@ ffs_vfree(pvp, ino, mode) * The specified inode is placed back in the free map. */ int -ffs_freefile(pip, ino, mode) - struct inode *pip; +ffs_freefile(fs, devvp, ino, mode) + struct fs *fs; + struct vnode *devvp; ino_t ino; int mode; { - register struct fs *fs; - register struct cg *cgp; + struct cg *cgp; struct buf *bp; - int error, cg; + int error, cgbno, cg; u_int8_t *inosused; + dev_t dev; - fs = pip->i_fs; - if ((u_int)ino >= fs->fs_ipg * fs->fs_ncg) - panic("ffs_vfree: range: dev = (%d,%d), ino = %d, fs = %s", - major(pip->i_dev), minor(pip->i_dev), ino, fs->fs_fsmnt); cg = ino_to_cg(fs, ino); - error = bread(pip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), - (int)fs->fs_cgsize, NOCRED, &bp); - if (error) { + if (devvp->v_type != VCHR) { + /* devvp is a snapshot */ + dev = VTOI(devvp)->i_devvp->v_rdev; + cgbno = fragstoblks(fs, cgtod(fs, cg)); + } else { + /* devvp is a normal disk device */ + dev = devvp->v_rdev; + cgbno = fsbtodb(fs, cgtod(fs, cg)); + } + if ((u_int)ino >= fs->fs_ipg * fs->fs_ncg) + panic("ffs_vfree: range: dev = %s, ino = %d, fs = %s", + devtoname(dev), ino, fs->fs_fsmnt); + if ((error = bread(devvp, cgbno, (int)fs->fs_cgsize, NOCRED, &bp))) { brelse(bp); return (error); } @@ -1650,7 +1667,7 @@ ffs_freefile(pip, ino, mode) inosused = cg_inosused(cgp); ino %= fs->fs_ipg; if (isclr(inosused, ino)) { - printf("dev = %s, ino = %lu, fs = %s\n", devtoname(pip->i_dev), + printf("dev = %s, ino = %lu, fs = %s\n", devtoname(dev), (u_long)ino + cg * fs->fs_ipg, fs->fs_fsmnt); if (fs->fs_ronly == 0) panic("ffs_vfree: freeing free inode"); @@ -1837,15 +1854,16 @@ ffs_clusteracct(fs, cgp, blkno, cnt) * fs: error message */ static void -ffs_fserr(fs, uid, cp) +ffs_fserr(fs, inum, cp) struct fs *fs; - u_int uid; + ino_t inum; char *cp; { struct proc *p = curproc; /* XXX */ - log(LOG_ERR, "pid %d (%s), uid %d on %s: %s\n", p ? p->p_pid : -1, - p ? p->p_comm : "-", uid, fs->fs_fsmnt, cp); + log(LOG_ERR, "pid %d (%s), uid %d inumber %d on %s: %s\n", + p ? p->p_pid : -1, p ? p->p_comm : "-", + p ? p->p_ucred->cr_uid : 0, inum, fs->fs_fsmnt, cp); } /* @@ -1900,7 +1918,6 @@ static int sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) { struct fsck_cmd cmd; - struct inode tip; struct ufsmount *ump; struct vnode *vp; struct inode *ip; @@ -2003,11 +2020,9 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) (ino_t)(cmd.value + cmd.size - 1)); } #endif /* DEBUG */ - tip.i_devvp = ump->um_devvp; - tip.i_dev = ump->um_dev; - tip.i_fs = fs; while (cmd.size > 0) { - if ((error = ffs_freefile(&tip, cmd.value, filetype))) + if ((error = ffs_freefile(fs, ump->um_devvp, cmd.value, + filetype))) break; cmd.size -= 1; cmd.value += 1; @@ -2028,20 +2043,14 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) (ufs_daddr_t)cmd.value + cmd.size - 1); } #endif /* DEBUG */ - tip.i_number = ROOTINO; - tip.i_devvp = ump->um_devvp; - tip.i_dev = ump->um_dev; - tip.i_fs = fs; - tip.i_size = cmd.size * fs->fs_fsize; - tip.i_uid = 0; - tip.i_vnode = NULL; blkno = (ufs_daddr_t)cmd.value; blkcnt = cmd.size; blksize = fs->fs_frag - (blkno % fs->fs_frag); while (blkcnt > 0) { if (blksize > blkcnt) blksize = blkcnt; - ffs_blkfree(&tip, blkno, blksize * fs->fs_fsize); + ffs_blkfree(fs, ump->um_devvp, blkno, + blksize * fs->fs_fsize, ROOTINO); blkno += blksize; blkcnt -= blksize; blksize = fs->fs_frag; diff --git a/sys/ufs/ffs/ffs_balloc.c b/sys/ufs/ffs/ffs_balloc.c index 26747fc25777..dbfe075d582a 100644 --- a/sys/ufs/ffs/ffs_balloc.c +++ b/sys/ufs/ffs/ffs_balloc.c @@ -352,7 +352,7 @@ ffs_balloc(struct vnode *a_vp, off_t a_startoffset, int a_size, */ (void) VOP_FSYNC(vp, cred, MNT_WAIT, td); for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { - ffs_blkfree(ip, *blkp, fs->fs_bsize); + ffs_blkfree(fs, ip->i_devvp, *blkp, fs->fs_bsize, ip->i_number); deallocated += fs->fs_bsize; } if (allocib != NULL) { diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index b70f7f753948..cfcdcbd0d937 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -59,14 +59,15 @@ int ffs_alloc __P((struct inode *, int ffs_balloc __P((struct vnode *a_vp, off_t a_startoffset, int a_size, struct ucred *a_cred, int a_flags, struct buf **a_bpp)); int ffs_blkatoff __P((struct vnode *, off_t, char **, struct buf **)); -void ffs_blkfree __P((struct inode *, ufs_daddr_t, long)); +void ffs_blkfree __P((struct fs *, struct vnode *, ufs_daddr_t, long, + ino_t)); ufs_daddr_t ffs_blkpref __P((struct inode *, ufs_daddr_t, int, ufs_daddr_t *)); void ffs_clrblock __P((struct fs *, u_char *, ufs_daddr_t)); void ffs_clusteracct __P((struct fs *, struct cg *, ufs_daddr_t, int)); int ffs_fhtovp __P((struct mount *, struct fid *, struct vnode **)); int ffs_flushfiles __P((struct mount *, int, struct thread *)); void ffs_fragacct __P((struct fs *, int, int32_t [], int)); -int ffs_freefile __P((struct inode *, ino_t, int )); +int ffs_freefile __P((struct fs *, struct vnode *, ino_t, int )); int ffs_isblock __P((struct fs *, u_char *, ufs_daddr_t)); int ffs_isfreeblock __P((struct fs *, unsigned char *, ufs_daddr_t)); int ffs_mountfs __P((struct vnode *, struct mount *, struct thread *, @@ -78,7 +79,8 @@ int ffs_reallocblks __P((struct vop_reallocblks_args *)); int ffs_realloccg __P((struct inode *, ufs_daddr_t, ufs_daddr_t, int, int, struct ucred *, struct buf **)); void ffs_setblock __P((struct fs *, u_char *, ufs_daddr_t)); -int ffs_snapblkfree __P((struct inode *freeip, ufs_daddr_t bno, long size)); +int ffs_snapblkfree __P((struct fs *, struct vnode *, ufs_daddr_t, + long, ino_t)); void ffs_snapremove __P((struct vnode *vp)); int ffs_snapshot __P((struct mount *mp, char *snapfile)); void ffs_snapshot_mount __P((struct mount *mp)); diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c index 43dfec641d97..301cb495cba1 100644 --- a/sys/ufs/ffs/ffs_inode.c +++ b/sys/ufs/ffs/ffs_inode.c @@ -336,7 +336,8 @@ ffs_truncate(vp, length, flags, cred, td) blocksreleased += count; if (lastiblock[level] < 0) { oip->i_ib[level] = 0; - ffs_blkfree(oip, bn, fs->fs_bsize); + ffs_blkfree(fs, oip->i_devvp, bn, fs->fs_bsize, + oip->i_number); blocksreleased += nblocks; } } @@ -355,7 +356,7 @@ ffs_truncate(vp, length, flags, cred, td) continue; oip->i_db[i] = 0; bsize = blksize(fs, oip, i); - ffs_blkfree(oip, bn, bsize); + ffs_blkfree(fs, oip->i_devvp, bn, bsize, oip->i_number); blocksreleased += btodb(bsize); } if (lastblock < 0) @@ -385,7 +386,8 @@ ffs_truncate(vp, length, flags, cred, td) * required for the storage we're keeping. */ bn += numfrags(fs, newspace); - ffs_blkfree(oip, bn, oldspace - newspace); + ffs_blkfree(fs, oip->i_devvp, bn, oldspace - newspace, + oip->i_number); blocksreleased += btodb(oldspace - newspace); } } @@ -514,7 +516,7 @@ ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) allerror = error; blocksreleased += blkcount; } - ffs_blkfree(ip, nb, fs->fs_bsize); + ffs_blkfree(fs, ip->i_devvp, nb, fs->fs_bsize, ip->i_number); blocksreleased += nblocks; } diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index 1d0a372078fe..1140973c0b96 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -63,14 +63,16 @@ static int cgaccount __P((int, struct vnode *, struct buf *, int)); static int expunge __P((struct vnode *, struct inode *, struct fs *, int (*) __P((struct vnode *, ufs_daddr_t *, ufs_daddr_t *, struct fs *, - ufs_daddr_t)))); + ufs_daddr_t, int)), int)); static int indiracct __P((struct vnode *, struct vnode *, int, ufs_daddr_t, int, int, int, int, struct fs *, int (*) __P((struct vnode *, - ufs_daddr_t *, ufs_daddr_t *, struct fs *, ufs_daddr_t)))); + ufs_daddr_t *, ufs_daddr_t *, struct fs *, ufs_daddr_t, int)), int)); +static int fullacct __P((struct vnode *, ufs_daddr_t *, ufs_daddr_t *, + struct fs *, ufs_daddr_t, int)); static int snapacct __P((struct vnode *, ufs_daddr_t *, ufs_daddr_t *, - struct fs *, ufs_daddr_t)); + struct fs *, ufs_daddr_t, int)); static int mapacct __P((struct vnode *, ufs_daddr_t *, ufs_daddr_t *, - struct fs *, ufs_daddr_t)); + struct fs *, ufs_daddr_t, int)); static int ffs_copyonwrite __P((struct vnode *, struct buf *)); static int readblock __P((struct buf *, daddr_t)); @@ -101,9 +103,9 @@ ffs_snapshot(mp, snapfile) struct mount *mp; char *snapfile; { - ufs_daddr_t blkno, inoblks[FSMAXSNAP]; + ufs_daddr_t blkno; int error, cg, snaploc, numblks; - int i, size, len, loc, inoblkcnt; + int i, size, len, loc; int flag = mp->mnt_flag; struct timespec starttime = {0, 0}, endtime; char saved_nice = 0; @@ -118,7 +120,7 @@ ffs_snapshot(mp, snapfile) struct nameidata nd; struct mount *wrtmp; struct vattr vat; - struct vnode *vp; + struct vnode *vp, *xvp, *nvp; /* * Need to serialize access to snapshot code per filesystem. @@ -210,28 +212,6 @@ ffs_snapshot(mp, snapfile) goto out; bdwrite(ibp); } - /* - * Allocate shadow blocks to copy all of the other snapshot inodes - * so that we will be able to expunge them from this snapshot. Also - * include a copy of ourselves so that we do not deadlock trying - * to copyonwrite ourselves when VOP_FSYNC'ing below. - */ - fs->fs_snapinum[snaploc] = ip->i_number; - for (loc = snaploc, inoblkcnt = 0; loc >= 0; loc--) { - blkno = fragstoblks(fs, ino_to_fsba(fs, fs->fs_snapinum[loc])); - fs->fs_snapinum[snaploc] = 0; - for (i = 0; i < inoblkcnt; i++) - if (inoblks[i] == blkno) - break; - if (i == inoblkcnt) { - inoblks[inoblkcnt++] = blkno; - error = UFS_BALLOC(vp, lblktosize(fs, (off_t)blkno), - fs->fs_bsize, KERNCRED, 0, &nbp); - if (error) - goto out; - bawrite(nbp); - } - } /* * Allocate copies for the superblock and its summary information. */ @@ -272,8 +252,10 @@ ffs_snapshot(mp, snapfile) for (cg = 0; cg < fs->fs_ncg; cg++) { error = bread(vp, fragstoblks(fs, cgtod(fs, cg)), fs->fs_bsize, KERNCRED, &nbp); - if (error) + if (error) { + brelse(nbp); goto out; + } error = cgaccount(cg, vp, nbp, 1); bawrite(nbp); if (error) @@ -308,43 +290,36 @@ ffs_snapshot(mp, snapfile) break; vn_start_write(NULL, &wrtmp, V_WAIT); } + if (collectsnapstats) + nanotime(&starttime); /* * First, copy all the cylinder group maps that have changed. */ - if (collectsnapstats) - nanotime(&starttime); for (cg = 0; cg < fs->fs_ncg; cg++) { if ((ACTIVECGNUM(fs, cg) & ACTIVECGOFF(cg)) != 0) continue; redo++; error = bread(vp, fragstoblks(fs, cgtod(fs, cg)), fs->fs_bsize, KERNCRED, &nbp); - if (error) + if (error) { + brelse(nbp); goto out1; + } error = cgaccount(cg, vp, nbp, 2); bawrite(nbp); if (error) goto out1; } - /* - * Copy the shadow blocks for the snapshot inodes so that - * the copies can can be expunged. - */ - for (loc = 0; loc < inoblkcnt; loc++) { - error = bread(vp, inoblks[loc], fs->fs_bsize, KERNCRED, &nbp); - if (error) - goto out1; - readblock(nbp, inoblks[loc]); - nbp->b_flags |= B_VALIDSUSPWRT; - bdwrite(nbp); - } /* * Grab a copy of the superblock and its summary information. * We delay writing it until the suspension is released below. */ error = bread(vp, lblkno(fs, SBOFF), fs->fs_bsize, KERNCRED, &sbp); - if (error) + if (error) { + brelse(sbp); + sbp = NULL; goto out1; + } copy_fs = (struct fs *)(sbp->b_data + blkoff(fs, SBOFF)); bcopy(fs, copy_fs, fs->fs_sbsize); if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0) @@ -366,7 +341,10 @@ ffs_snapshot(mp, snapfile) if ((error = bread(ip->i_devvp, fsbtodb(fs, fs->fs_csaddr + loc), len, KERNCRED, &bp)) != 0) { + brelse(bp); free(copy_fs->fs_csp, M_UFSMNT); + bawrite(sbp); + sbp = NULL; goto out1; } bcopy(bp->b_data, space, (u_int)len); @@ -379,6 +357,69 @@ ffs_snapshot(mp, snapfile) for (i = 0; i < fs->fs_ncg; i++) *lp++ = fs->fs_contigsumsize; } + /* + * We must check for active files that have been unlinked + * (e.g., with a zero link count). We have to expunge all + * trace of these files from the snapshot so that they are + * not reclaimed prematurely by fsck or unnecessarily dumped. + * We turn off the MNTK_SUSPENDED flag to avoid a panic from + * spec_strategy about writing on a suspended filesystem. + */ + mp->mnt_kern_flag &= ~MNTK_SUSPENDED; + mtx_lock(&mntvnode_mtx); +loop: + for (xvp = TAILQ_FIRST(&mp->mnt_nvnodelist); xvp; xvp = nvp) { + /* + * Make sure this vnode wasn't reclaimed in getnewvnode(). + * Start over if it has (it won't be on the list anymore). + */ + if (xvp->v_mount != mp) + goto loop; + nvp = TAILQ_NEXT(xvp, v_nmntvnodes); + mtx_unlock(&mntvnode_mtx); + mtx_lock(&xvp->v_interlock); + if (xvp->v_usecount == 0 || xvp->v_type == VNON || + (VOP_GETATTR(xvp, &vat, td->td_proc->p_ucred, td) == 0 && + vat.va_nlink > 0)) { + mtx_unlock(&xvp->v_interlock); + mtx_lock(&mntvnode_mtx); + continue; + } + if (snapdebug) + vprint("ffs_snapshot: busy vnode", xvp); + if (vn_lock(xvp, LK_EXCLUSIVE | LK_INTERLOCK, td) != 0) + goto loop; + xp = VTOI(xvp); + /* + * If there is a fragment, clear it here. + */ + blkno = 0; + loc = howmany(xp->i_size, fs->fs_bsize) - 1; + if (loc < NDADDR) { + len = fragroundup(fs, blkoff(fs, xp->i_size)); + if (len < fs->fs_bsize) { + ffs_blkfree(copy_fs, vp, xp->i_db[loc], len, + xp->i_number); + blkno = xp->i_db[loc]; + xp->i_db[loc] = 0; + } + } + error = expunge(vp, xp, copy_fs, fullacct, BLK_NOCOPY); + if (blkno) + xp->i_db[loc] = blkno; + if (!error) + error = ffs_freefile(copy_fs, vp, xp->i_number, + xp->i_mode); + VOP_UNLOCK(xvp, 0, td); + if (error) { + free(copy_fs->fs_csp, M_UFSMNT); + bawrite(sbp); + sbp = NULL; + goto out1; + } + mtx_lock(&mntvnode_mtx); + } + mtx_unlock(&mntvnode_mtx); /* * Record snapshot inode. Since this is the newest snapshot, * it must be placed at the end of the list. @@ -406,53 +447,50 @@ ffs_snapshot(mp, snapfile) vp->v_mount->mnt_stat.f_mntonname, endtime.tv_sec, endtime.tv_nsec / 1000000, redo, fs->fs_ncg); } - if (sbp != NULL) { - /* - * Copy allocation information from all the snapshots in - * this snapshot and then expunge them from its view. - */ - snaphead = &ip->i_devvp->v_rdev->si_snapshots; - TAILQ_FOREACH(xp, snaphead, i_nextsnap) { - if (xp == VTOI(vp)) - break; - if ((error = expunge(vp, xp, fs, snapacct)) != 0) - goto out1; + if (sbp == NULL) + goto out; + /* + * Copy allocation information from all the snapshots in + * this snapshot and then expunge them from its view. + */ + snaphead = &ip->i_devvp->v_rdev->si_snapshots; + TAILQ_FOREACH(xp, snaphead, i_nextsnap) { + if (xp == ip) + break; + if ((error = expunge(vp, xp, fs, snapacct, BLK_SNAP)) != 0) { + fs->fs_snapinum[snaploc] = 0; + goto done; } - /* - * Expunge the blocks used by the snapshots from the set of - * blocks marked as used in the snapshot bitmaps. - */ - if ((error = expunge(vp, VTOI(vp), copy_fs, mapacct)) != 0) { - vref(vp); - ffs_snapgone(VTOI(vp)); - free(copy_fs->fs_csp, M_UFSMNT); - bawrite(sbp); - goto out; - } - /* - * Write the superblock and its summary information - * to the snapshot. - */ - blkno = fragstoblks(fs, fs->fs_csaddr); - len = howmany(fs->fs_cssize, fs->fs_bsize); - space = copy_fs->fs_csp; - for (loc = 0; loc < len; loc++) { - error = bread(vp, blkno + loc, fs->fs_bsize, - KERNCRED, &nbp); - if (error) { - vref(vp); - ffs_snapgone(VTOI(vp)); - free(copy_fs->fs_csp, M_UFSMNT); - bawrite(sbp); - goto out; - } - bcopy(space, nbp->b_data, fs->fs_bsize); - space = (char *)space + fs->fs_bsize; - bawrite(nbp); - } - free(copy_fs->fs_csp, M_UFSMNT); - bawrite(sbp); } + /* + * Expunge the blocks used by the snapshots from the set of + * blocks marked as used in the snapshot bitmaps. + */ + if ((error = expunge(vp, ip, copy_fs, mapacct, BLK_SNAP)) != 0) { + fs->fs_snapinum[snaploc] = 0; + goto done; + } + /* + * Write the superblock and its summary information + * to the snapshot. + */ + blkno = fragstoblks(fs, fs->fs_csaddr); + len = howmany(fs->fs_cssize, fs->fs_bsize); + space = copy_fs->fs_csp; + for (loc = 0; loc < len; loc++) { + error = bread(vp, blkno + loc, fs->fs_bsize, KERNCRED, &nbp); + if (error) { + brelse(nbp); + fs->fs_snapinum[snaploc] = 0; + goto done; + } + bcopy(space, nbp->b_data, fs->fs_bsize); + space = (char *)space + fs->fs_bsize; + bawrite(nbp); + } +done: + free(copy_fs->fs_csp, M_UFSMNT); + bawrite(sbp); out: if (fs->fs_active != 0) { FREE(fs->fs_active, M_DEVBUF); @@ -572,28 +610,31 @@ cgaccount(cg, vp, nbp, passno) * if the other snapshot holding them is freed. */ static int -expunge(vp, xp, fs, acctfunc) - struct vnode *vp; - struct inode *xp; +expunge(snapvp, cancelip, fs, acctfunc, expungetype) + struct vnode *snapvp; + struct inode *cancelip; struct fs *fs; int (*acctfunc) __P((struct vnode *, ufs_daddr_t *, ufs_daddr_t *, - struct fs *, ufs_daddr_t)); + struct fs *, ufs_daddr_t, int)); + int expungetype; { int i, len, error, numblks, blksperindir; - ufs_daddr_t lbn, rlbn, blkno; + ufs_daddr_t lbn, rlbn, blkno, indiroff; + struct thread *td = curthread; struct dinode *dip; struct buf *bp; - if ((error = (*acctfunc)(vp, &xp->i_db[0], &xp->i_ib[NIADDR], fs, 0))) + numblks = howmany(cancelip->i_size, fs->fs_bsize); + if ((error = (*acctfunc)(snapvp, &cancelip->i_db[0], + &cancelip->i_ib[NIADDR], fs, 0, expungetype))) return (error); - numblks = howmany(fs->fs_size, fs->fs_frag); blksperindir = 1; lbn = -NDADDR; len = numblks - NDADDR; rlbn = NDADDR; for (i = 0; len > 0 && i < NIADDR; i++) { - error = indiracct(vp, ITOV(xp), i, xp->i_ib[i], lbn, - rlbn, len, blksperindir, fs, acctfunc); + error = indiracct(snapvp, ITOV(cancelip), i, cancelip->i_ib[i], + lbn, rlbn, len, blksperindir, fs, acctfunc, expungetype); if (error) return (error); blksperindir *= NINDIR(fs); @@ -602,13 +643,37 @@ expunge(vp, xp, fs, acctfunc) rlbn += blksperindir; } /* - * Set copied snapshot inode to be a zero length file. + * Prepare to expunge the inode. If its inode block has not + * yet been copied, then allocate and fill the copy. */ - blkno = fragstoblks(fs, ino_to_fsba(fs, xp->i_number)); - if ((error = bread(vp, blkno, fs->fs_bsize, KERNCRED, &bp)) != 0) + lbn = fragstoblks(fs, ino_to_fsba(fs, cancelip->i_number)); + blkno = 0; + if (lbn < NDADDR) { + blkno = cancelip->i_db[lbn]; + } else { + td->td_proc->p_flag |= P_COWINPROGRESS; + error = UFS_BALLOC(snapvp, lblktosize(fs, (off_t)lbn), + fs->fs_bsize, KERNCRED, B_METAONLY, &bp); + td->td_proc->p_flag &= ~P_COWINPROGRESS; + if (error) + return (error); + indiroff = (lbn - NDADDR) % NINDIR(fs); + blkno = ((ufs_daddr_t *)(bp->b_data))[indiroff]; + bqrelse(bp); + } + error = UFS_BALLOC(snapvp, lblktosize(fs, (off_t)lbn), + fs->fs_bsize, KERNCRED, 0, &bp); + if (error) return (error); - dip = (struct dinode *)bp->b_data + - ino_to_fsbo(fs, xp->i_number); + if (blkno == 0 && (error = readblock(bp, lbn))) + return (error); + /* + * Set a snapshot inode to be a zero length file, regular files + * to be completely unallocated. + */ + dip = (struct dinode *)bp->b_data + ino_to_fsbo(fs, cancelip->i_number); + if (expungetype == BLK_NOCOPY) + dip->di_mode = 0; dip->di_size = 0; dip->di_blocks = 0; dip->di_flags &= ~SF_SNAPSHOT; @@ -623,7 +688,7 @@ expunge(vp, xp, fs, acctfunc) */ static int indiracct(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks, blksperindir, fs, - acctfunc) + acctfunc, expungetype) struct vnode *snapvp; struct vnode *cancelvp; int level; @@ -634,7 +699,8 @@ indiracct(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks, blksperindir, fs, int blksperindir; struct fs *fs; int (*acctfunc) __P((struct vnode *, ufs_daddr_t *, ufs_daddr_t *, - struct fs *, ufs_daddr_t)); + struct fs *, ufs_daddr_t, int)); + int expungetype; { int subblksperindir, error, last, num, i; struct indir indirs[NIADDR + 2]; @@ -665,7 +731,7 @@ indiracct(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks, blksperindir, fs, MALLOC(bap, ufs_daddr_t *, fs->fs_bsize, M_DEVBUF, M_WAITOK); bcopy(bp->b_data, (caddr_t)bap, fs->fs_bsize); bqrelse(bp); - error = (*acctfunc)(snapvp, &bap[0], &bap[last], fs, rlbn); + error = (*acctfunc)(snapvp, &bap[0], &bap[last], fs, rlbn, expungetype); if (error || level == 0) goto out; /* @@ -675,7 +741,7 @@ indiracct(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks, blksperindir, fs, subblksperindir = blksperindir / NINDIR(fs); for (lbn++, level--, i = 0; i < last; i++) { error = indiracct(snapvp, cancelvp, level, bap[i], lbn, - rlbn, remblks, subblksperindir, fs, acctfunc); + rlbn, remblks, subblksperindir, fs, acctfunc, expungetype); if (error) goto out; rlbn += blksperindir; @@ -688,14 +754,33 @@ indiracct(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks, blksperindir, fs, } /* - * Identify a set of blocks allocated in a snapshot inode. + * Do both snap accounting and map accounting. */ static int -snapacct(vp, oldblkp, lastblkp, fs, lblkno) +fullacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype) struct vnode *vp; ufs_daddr_t *oldblkp, *lastblkp; struct fs *fs; ufs_daddr_t lblkno; + int expungetype; /* BLK_SNAP or BLK_NOCOPY */ +{ + int error; + + if ((error = snapacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype))) + return (error); + return (mapacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype)); +} + +/* + * Identify a set of blocks allocated in a snapshot inode. + */ +static int +snapacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype) + struct vnode *vp; + ufs_daddr_t *oldblkp, *lastblkp; + struct fs *fs; + ufs_daddr_t lblkno; + int expungetype; /* BLK_SNAP or BLK_NOCOPY */ { struct inode *ip = VTOI(vp); ufs_daddr_t lbn, blkno, *blkp; @@ -719,17 +804,18 @@ snapacct(vp, oldblkp, lastblkp, fs, lblkno) [(lbn - NDADDR) % NINDIR(fs)]; } /* - * If we find a block marked BLK_NOCOPY, then it is + * If we are expunging a snapshot vnode and we + * find a block marked BLK_NOCOPY, then it is * one that has been allocated to this snapshot after * we took our current snapshot and can be ignored. */ - if (*blkp == BLK_NOCOPY) { + if (expungetype == BLK_SNAP && *blkp == BLK_NOCOPY) { if (lbn >= NDADDR) brelse(ibp); } else { if (*blkp != 0) panic("snapacct: bad block"); - *blkp = BLK_SNAP; + *blkp = expungetype; if (lbn >= NDADDR) bdwrite(ibp); } @@ -741,59 +827,24 @@ snapacct(vp, oldblkp, lastblkp, fs, lblkno) * Account for a set of blocks allocated in a snapshot inode. */ static int -mapacct(vp, oldblkp, lastblkp, fs, lblkno) +mapacct(vp, oldblkp, lastblkp, fs, lblkno, expungetype) struct vnode *vp; ufs_daddr_t *oldblkp, *lastblkp; struct fs *fs; ufs_daddr_t lblkno; + int expungetype; { - struct inode *ip = VTOI(vp); - ufs_daddr_t blkno, cgblkno, fragno; - struct buf *bp; - struct cg *cgp; - char *blksfree; - int i, cg, error; + ufs_daddr_t blkno; + ino_t inum; + inum = VTOI(vp)->i_number; for ( ; oldblkp < lastblkp; oldblkp++, lblkno++) { blkno = *oldblkp; if (blkno == 0 || blkno == BLK_NOCOPY) continue; if (blkno == BLK_SNAP) blkno = blkstofrags(fs, lblkno); - cg = dtog(fs, blkno); - cgblkno = fragstoblks(fs, cgtod(fs, cg)); - if ((error = bread(vp, cgblkno, fs->fs_bsize, KERNCRED, &bp))) - return (error); - cgp = (struct cg *)bp->b_data; - if (!cg_chkmagic(cgp) || cgp->cg_cgx != cg) { - if (!cg_chkmagic(cgp)) - printf("mapacct: bad magic 0x%x\n", - cgp->cg_magic); - else - printf("%s: mismatched cg %d != cg_cgx %d\n", - "mapacct", cg, cgp->cg_cgx); - brelse(bp); - return (EIO); - } - cgp->cg_time = time_second; - cgblkno = dtogd(fs, blkno); - blksfree = cg_blksfree(cgp); - fragno = fragstoblks(fs, cgblkno); - if (!ffs_isfreeblock(fs, blksfree, fragno)) { - printf("dev = %s, block = %ld, fs = %s\n", - devtoname(ip->i_dev), (long)blkno, fs->fs_fsmnt); - panic("mapacct: freeing free block"); - } - ffs_setblock(fs, blksfree, fragno); - ffs_clusteracct(fs, cgp, fragno, 1); - cgp->cg_cs.cs_nbfree++; - fs->fs_cstotal.cs_nbfree++; - fs->fs_cs(fs, cg).cs_nbfree++; - i = cbtocylno(fs, cgblkno); - cg_blks(fs, cgp, i)[cbtorpos(fs, cgblkno)]++; - cg_blktot(cgp)[i]++; - fs->fs_fmod = 1; - bdwrite(bp); + ffs_blkfree(fs, vp, blkno, fs->fs_bsize, inum); } return (0); } @@ -879,7 +930,8 @@ ffs_snapremove(vp) if (dblk == BLK_NOCOPY || dblk == BLK_SNAP) ip->i_db[blkno] = 0; else if ((dblk == blkstofrags(fs, blkno) && - ffs_snapblkfree(ip, dblk, fs->fs_bsize))) { + ffs_snapblkfree(fs, ip->i_devvp, dblk, fs->fs_bsize, + ip->i_number))) { ip->i_blocks -= btodb(fs->fs_bsize); ip->i_db[blkno] = 0; } @@ -897,7 +949,8 @@ ffs_snapremove(vp) if (dblk == BLK_NOCOPY || dblk == BLK_SNAP) ((ufs_daddr_t *)(ibp->b_data))[loc] = 0; else if ((dblk == blkstofrags(fs, blkno) && - ffs_snapblkfree(ip, dblk, fs->fs_bsize))) { + ffs_snapblkfree(fs, ip->i_devvp, dblk, + fs->fs_bsize, ip->i_number))) { ip->i_blocks -= btodb(fs->fs_bsize); ((ufs_daddr_t *)(ibp->b_data))[loc] = 0; } @@ -930,13 +983,14 @@ ffs_snapremove(vp) * must always have been allocated from a BLK_NOCOPY location. */ int -ffs_snapblkfree(freeip, bno, size) - struct inode *freeip; +ffs_snapblkfree(fs, devvp, bno, size, inum) + struct fs *fs; + struct vnode *devvp; ufs_daddr_t bno; long size; + ino_t inum; { struct buf *ibp, *cbp, *savedcbp = 0; - struct fs *fs = freeip->i_fs; struct thread *td = curthread; struct inode *ip; struct vnode *vp; @@ -945,7 +999,7 @@ ffs_snapblkfree(freeip, bno, size) struct snaphead *snaphead; lbn = fragstoblks(fs, bno); - snaphead = &freeip->i_devvp->v_rdev->si_snapshots; + snaphead = &devvp->v_rdev->si_snapshots; TAILQ_FOREACH(ip, snaphead, i_nextsnap) { vp = ITOV(ip); /* @@ -1016,7 +1070,7 @@ ffs_snapblkfree(freeip, bno, size) if (snapdebug) printf("%s %d lbn %d from inum %d\n", "Grabonremove: snapino", ip->i_number, lbn, - freeip->i_number); + inum); #endif vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); if (lbn < NDADDR) { @@ -1050,7 +1104,7 @@ ffs_snapblkfree(freeip, bno, size) if (snapdebug) printf("%s%d lbn %d for inum %d size %ld to blkno %d\n", "Copyonremove: snapino ", ip->i_number, lbn, - freeip->i_number, size, cbp->b_blkno); + inum, size, cbp->b_blkno); #endif /* * If we have already read the old block contents, then diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 913d5a134c70..a7c12d4c500e 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -169,7 +169,7 @@ static struct dirrem *newdirrem __P((struct buf *, struct inode *, static void free_diradd __P((struct diradd *)); static void free_allocindir __P((struct allocindir *, struct inodedep *)); static void free_newdirblk __P((struct newdirblk *)); -static int indir_trunc __P((struct inode *, ufs_daddr_t, int, ufs_lbn_t, +static int indir_trunc __P((struct freeblks *, ufs_daddr_t, int, ufs_lbn_t, long *)); static void deallocate_dependencies __P((struct buf *, struct inodedep *)); static void free_allocdirect __P((struct allocdirectlst *, @@ -1506,7 +1506,7 @@ newfreefrag(ip, blkno, size) MALLOC(freefrag, struct freefrag *, sizeof(struct freefrag), M_FREEFRAG, M_SOFTDEP_FLAGS); freefrag->ff_list.wk_type = D_FREEFRAG; - freefrag->ff_state = ip->i_uid & ~ONWORKLIST; /* XXX - used below */ + freefrag->ff_state = 0; freefrag->ff_inum = ip->i_number; freefrag->ff_mnt = ITOV(ip)->v_mount; freefrag->ff_devvp = ip->i_devvp; @@ -1523,15 +1523,9 @@ static void handle_workitem_freefrag(freefrag) struct freefrag *freefrag; { - struct inode tip; - tip.i_vnode = NULL; - tip.i_fs = VFSTOUFS(freefrag->ff_mnt)->um_fs; - tip.i_devvp = freefrag->ff_devvp; - tip.i_dev = freefrag->ff_devvp->v_rdev; - tip.i_number = freefrag->ff_inum; - tip.i_uid = freefrag->ff_state & ~ONWORKLIST; /* XXX - set above */ - ffs_blkfree(&tip, freefrag->ff_blkno, freefrag->ff_fragsize); + ffs_blkfree(VFSTOUFS(freefrag->ff_mnt)->um_fs, freefrag->ff_devvp, + freefrag->ff_blkno, freefrag->ff_fragsize, freefrag->ff_inum); FREE(freefrag, M_FREEFRAG); } @@ -1819,8 +1813,10 @@ softdep_setup_freeblocks(ip, length) */ if ((error = bread(ip->i_devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), - (int)fs->fs_bsize, NOCRED, &bp)) != 0) + (int)fs->fs_bsize, NOCRED, &bp)) != 0) { + brelse(bp); softdep_error("softdep_setup_freeblocks", error); + } *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ip->i_number)) = ip->i_din; /* @@ -2224,7 +2220,7 @@ handle_workitem_freeblocks(freeblks, flags) struct freeblks *freeblks; int flags; { - struct inode tip, *ip; + struct inode *ip; struct vnode *vp; ufs_daddr_t bn; struct fs *fs; @@ -2233,13 +2229,7 @@ handle_workitem_freeblocks(freeblks, flags) int error, allerror = 0; ufs_lbn_t baselbns[NIADDR], tmpval; - tip.i_fs = fs = VFSTOUFS(freeblks->fb_mnt)->um_fs; - tip.i_number = freeblks->fb_previousinum; - tip.i_devvp = freeblks->fb_devvp; - tip.i_dev = freeblks->fb_devvp->v_rdev; - tip.i_size = freeblks->fb_oldsize; - tip.i_uid = freeblks->fb_uid; - tip.i_vnode = NULL; + fs = VFSTOUFS(freeblks->fb_mnt)->um_fs; tmpval = 1; baselbns[0] = NDADDR; for (i = 1; i < NIADDR; i++) { @@ -2254,10 +2244,11 @@ handle_workitem_freeblocks(freeblks, flags) for (level = (NIADDR - 1); level >= 0; level--) { if ((bn = freeblks->fb_iblks[level]) == 0) continue; - if ((error = indir_trunc(&tip, fsbtodb(fs, bn), level, + if ((error = indir_trunc(freeblks, fsbtodb(fs, bn), level, baselbns[level], &blocksreleased)) == 0) allerror = error; - ffs_blkfree(&tip, bn, fs->fs_bsize); + ffs_blkfree(fs, freeblks->fb_devvp, bn, fs->fs_bsize, + freeblks->fb_previousinum); fs->fs_pendingblocks -= nblocks; blocksreleased += nblocks; } @@ -2267,8 +2258,9 @@ handle_workitem_freeblocks(freeblks, flags) for (i = (NDADDR - 1); i >= 0; i--) { if ((bn = freeblks->fb_dblks[i]) == 0) continue; - bsize = blksize(fs, &tip, i); - ffs_blkfree(&tip, bn, bsize); + bsize = sblksize(fs, freeblks->fb_oldsize, i); + ffs_blkfree(fs, freeblks->fb_devvp, bn, bsize, + freeblks->fb_previousinum); fs->fs_pendingblocks -= btodb(bsize); blocksreleased += btodb(bsize); } @@ -2303,8 +2295,8 @@ handle_workitem_freeblocks(freeblks, flags) * blocks. */ static int -indir_trunc(ip, dbn, level, lbn, countp) - struct inode *ip; +indir_trunc(freeblks, dbn, level, lbn, countp) + struct freeblks *freeblks; ufs_daddr_t dbn; int level; ufs_lbn_t lbn; @@ -2319,7 +2311,7 @@ indir_trunc(ip, dbn, level, lbn, countp) int i, lbnadd, nblocks; int error, allerror = 0; - fs = ip->i_fs; + fs = VFSTOUFS(freeblks->fb_mnt)->um_fs; lbnadd = 1; for (i = level; i > 0; i--) lbnadd *= NINDIR(fs); @@ -2336,7 +2328,7 @@ indir_trunc(ip, dbn, level, lbn, countp) * Otherwise we have to read the blocks in from the disk. */ ACQUIRE_LOCK(&lk); - if ((bp = incore(ip->i_devvp, dbn)) != NULL && + if ((bp = incore(freeblks->fb_devvp, dbn)) != NULL && (wk = LIST_FIRST(&bp->b_dep)) != NULL) { if (wk->wk_type != D_INDIRDEP || (indirdep = WK_INDIRDEP(wk))->ir_savebp != bp || @@ -2353,9 +2345,12 @@ indir_trunc(ip, dbn, level, lbn, countp) FREE_LOCK(&lk); } else { FREE_LOCK(&lk); - error = bread(ip->i_devvp, dbn, (int)fs->fs_bsize, NOCRED, &bp); - if (error) + error = bread(freeblks->fb_devvp, dbn, (int)fs->fs_bsize, + NOCRED, &bp); + if (error) { + brelse(bp); return (error); + } } /* * Recursively free indirect blocks. @@ -2366,11 +2361,12 @@ indir_trunc(ip, dbn, level, lbn, countp) if ((nb = bap[i]) == 0) continue; if (level != 0) { - if ((error = indir_trunc(ip, fsbtodb(fs, nb), + if ((error = indir_trunc(freeblks, fsbtodb(fs, nb), level - 1, lbn + (i * lbnadd), countp)) != 0) allerror = error; } - ffs_blkfree(ip, nb, fs->fs_bsize); + ffs_blkfree(fs, freeblks->fb_devvp, nb, fs->fs_bsize, + freeblks->fb_previousinum); fs->fs_pendingblocks -= nblocks; *countp += nblocks; } @@ -3132,7 +3128,6 @@ handle_workitem_freefile(freefile) struct freefile *freefile; { struct fs *fs; - struct inode tip; struct inodedep *idp; int error; @@ -3144,11 +3139,9 @@ handle_workitem_freefile(freefile) if (error) panic("handle_workitem_freefile: inodedep survived"); #endif - tip.i_devvp = freefile->fx_devvp; - tip.i_dev = freefile->fx_devvp->v_rdev; - tip.i_fs = fs; fs->fs_pendinginodes -= 1; - if ((error = ffs_freefile(&tip, freefile->fx_oldinum, freefile->fx_mode)) != 0) + if ((error = ffs_freefile(fs, freefile->fx_devvp, freefile->fx_oldinum, + freefile->fx_mode)) != 0) softdep_error("handle_workitem_freefile", error); WORKITEM_FREE(freefile, D_FREEFILE); } @@ -4261,6 +4254,8 @@ softdep_fsync(vp) &bp); if (error == 0) error = BUF_WRITE(bp); + else + brelse(bp); vput(pvp); if (error != 0) return (error); @@ -4785,8 +4780,10 @@ flush_pagedep_deps(pvp, mp, diraddhdp) FREE_LOCK(&lk); if ((error = bread(ump->um_devvp, fsbtodb(ump->um_fs, ino_to_fsba(ump->um_fs, inum)), - (int)ump->um_fs->fs_bsize, NOCRED, &bp)) != 0) + (int)ump->um_fs->fs_bsize, NOCRED, &bp)) != 0) { + brelse(bp); break; + } if ((error = BUF_WRITE(bp)) != 0) break; ACQUIRE_LOCK(&lk);