aboutsummaryrefslogtreecommitdiff
path: root/sys/ufs/ffs/ffs_snapshot.c
diff options
context:
space:
mode:
authorKirk McKusick <mckusick@FreeBSD.org>2000-12-19 04:41:09 +0000
committerKirk McKusick <mckusick@FreeBSD.org>2000-12-19 04:41:09 +0000
commit48d617487d1aa23554265d029c9b5e6b798cd4fc (patch)
tree2c88335dde69698bb10fa75573a96f25c6fd27d6 /sys/ufs/ffs/ffs_snapshot.c
parent6da443cb22f9242d6037b4de526d24ececc21394 (diff)
downloadsrc-48d617487d1aa23554265d029c9b5e6b798cd4fc.tar.gz
src-48d617487d1aa23554265d029c9b5e6b798cd4fc.zip
Several small but important fixes for snapshots:
1) Be more tolerant of missing snapshot files by only trying to decrement their reference count if they are registered as active. 2) Fix for snapshots of filesystems with block sizes larger than 8K (from Ollivier Robert <roberto@eurocontrol.fr>). 3) Fix to avoid losing last block in snapshot file when calculating blocks that need to be copied (from Don Coleman <coleman@coleman.org>).
Notes
Notes: svn path=/head/; revision=70183
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