aboutsummaryrefslogtreecommitdiff
path: root/sys/ufs/ffs/ffs_snapshot.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/ufs/ffs/ffs_snapshot.c')
-rw-r--r--sys/ufs/ffs/ffs_snapshot.c50
1 files changed, 36 insertions, 14 deletions
diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c
index d27a9260c9b5..a4b2deaeec77 100644
--- a/sys/ufs/ffs/ffs_snapshot.c
+++ b/sys/ufs/ffs/ffs_snapshot.c
@@ -83,7 +83,7 @@ ffs_snapshot(mp, snapfile)
int error, cg, snaploc, indiroff, numblks;
int i, size, base, len, loc, inoblkcnt;
int blksperindir, flag = mp->mnt_flag;
- struct fs *fs = VFSTOUFS(mp)->um_fs;
+ struct fs *copy_fs, *fs = VFSTOUFS(mp)->um_fs;
struct proc *p = CURPROC;
struct inode *devip, *ip, *xp;
struct buf *bp, *nbp, *ibp;
@@ -223,9 +223,7 @@ restart:
/*
* Allocate copies for the superblock and its summary information.
*/
- error = VOP_BALLOC(vp, (off_t)(SBOFF), fs->fs_bsize, KERNCRED,
- 0, &nbp);
- if (error)
+ if ((error = VOP_BALLOC(vp, (off_t)(SBOFF), SBSIZE, KERNCRED, 0, &nbp)))
goto out;
bawrite(nbp);
blkno = fragstoblks(fs, fs->fs_csaddr);
@@ -292,8 +290,8 @@ restart:
nbp->b_flags |= B_VALIDSUSPWRT;
bawrite(nbp);
base = cg * fs->fs_fpg / fs->fs_frag;
- if (base + len > numblks)
- len = numblks - base;
+ if (base + len >= numblks)
+ len = numblks - base - 1;
loc = 0;
if (base < NDADDR) {
for ( ; loc < NDADDR; loc++) {
@@ -324,6 +322,8 @@ restart:
}
if (!ffs_isblock(fs, cg_blksfree(cgp), loc))
continue;
+ if (((ufs_daddr_t *)(ibp->b_data))[indiroff] != 0)
+ panic("ffs_snapshot: lost block");
((ufs_daddr_t *)(ibp->b_data))[indiroff] = BLK_NOCOPY;
}
bqrelse(bp);
@@ -333,15 +333,14 @@ restart:
/*
* Snapshot the superblock and its summary information.
*/
- error = VOP_BALLOC(vp, (off_t)(SBOFF), fs->fs_bsize, KERNCRED,
- 0, &nbp);
- if (error)
+ if ((error = VOP_BALLOC(vp, SBOFF, SBSIZE, KERNCRED, 0, &nbp)) != 0)
goto out1;
- bcopy(fs, nbp->b_data, fs->fs_sbsize);
- ((struct fs *)(nbp->b_data))->fs_clean = 1;
- if (fs->fs_sbsize < fs->fs_bsize)
- bzero(&nbp->b_data[fs->fs_sbsize],
- fs->fs_bsize - fs->fs_sbsize);
+ copy_fs = (struct fs *)(nbp->b_data + blkoff(fs, SBOFF));
+ bcopy(fs, copy_fs, fs->fs_sbsize);
+ copy_fs->fs_clean = 1;
+ if (fs->fs_sbsize < SBSIZE)
+ bzero(&nbp->b_data[blkoff(fs, SBOFF) + fs->fs_sbsize],
+ SBSIZE - fs->fs_sbsize);
nbp->b_flags |= B_VALIDSUSPWRT;
bawrite(nbp);
blkno = fragstoblks(fs, fs->fs_csaddr);
@@ -594,6 +593,29 @@ snapacct(vp, oldblkp, lastblkp)
}
/*
+ * Decrement extra reference on snapshot when last name is removed.
+ * It will not be freed until the last open reference goes away.
+ */
+void
+ffs_snapgone(ip)
+ struct inode *ip;
+{
+ struct inode *xp;
+
+ /*
+ * Find snapshot in incore list.
+ */
+ for (xp = VTOI(ip->i_devvp); xp; xp = xp->i_copyonwrite)
+ if (xp->i_copyonwrite == ip)
+ break;
+ if (xp == 0)
+ printf("ffs_snapgone: lost snapshot vnode %d\n",
+ ip->i_number);
+ else
+ vrele(ITOV(ip));
+}
+
+/*
* Prepare a snapshot file for being removed.
*/
void