summaryrefslogtreecommitdiffstats
path: root/sys/ufs/ffs/ffs_snapshot.c
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2011-06-15 23:19:09 +0000
committermckusick <mckusick@FreeBSD.org>2011-06-15 23:19:09 +0000
commitef6ee3faed283f9910e11c5d56af10d587a6803a (patch)
tree1b8b16a7cb08122f5940fce8ca5c6380ec168b35 /sys/ufs/ffs/ffs_snapshot.c
parent5725aadb3786d9aadc53ad14bf1fef07fa822d5c (diff)
downloadFreeBSD-src-ef6ee3faed283f9910e11c5d56af10d587a6803a.zip
FreeBSD-src-ef6ee3faed283f9910e11c5d56af10d587a6803a.tar.gz
Ensure that filesystem metadata contained within persistent snapshots
is always kept consistent. Suggested by: Jeff Roberson
Diffstat (limited to 'sys/ufs/ffs/ffs_snapshot.c')
-rw-r--r--sys/ufs/ffs/ffs_snapshot.c64
1 files changed, 44 insertions, 20 deletions
diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c
index 89fc596..8d236bd 100644
--- a/sys/ufs/ffs/ffs_snapshot.c
+++ b/sys/ufs/ffs/ffs_snapshot.c
@@ -81,12 +81,13 @@ ffs_snapshot(mp, snapfile)
}
int
-ffs_snapblkfree(fs, devvp, bno, size, inum, wkhd)
+ffs_snapblkfree(fs, devvp, bno, size, inum, vtype, wkhd)
struct fs *fs;
struct vnode *devvp;
ufs2_daddr_t bno;
long size;
ino_t inum;
+ enum vtype vtype;
struct workhead *wkhd;
{
return (EINVAL);
@@ -174,8 +175,10 @@ static int ffs_bp_snapblk(struct vnode *, struct buf *);
* To ensure the consistency of snapshots across crashes, we must
* synchronously write out copied blocks before allowing the
* originals to be modified. Because of the rather severe speed
- * penalty that this imposes, the following flag allows this
- * crash persistence to be disabled.
+ * penalty that this imposes, the code normally only ensures
+ * persistence for the filesystem metadata contained within a
+ * snapshot. Setting the following flag allows this crash
+ * persistence to be enabled for file contents.
*/
int dopersistence = 0;
@@ -582,7 +585,7 @@ loop:
if (len != 0 && len < fs->fs_bsize) {
ffs_blkfree(ump, copy_fs, vp,
DIP(xp, i_db[loc]), len, xp->i_number,
- NULL);
+ xvp->v_type, NULL);
blkno = DIP(xp, i_db[loc]);
DIP_SET(xp, i_db[loc], 0);
}
@@ -1245,7 +1248,8 @@ mapacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, expungetype)
*ip->i_snapblklist++ = lblkno;
if (blkno == BLK_SNAP)
blkno = blkstofrags(fs, lblkno);
- ffs_blkfree(ip->i_ump, fs, vp, blkno, fs->fs_bsize, inum, NULL);
+ ffs_blkfree(ip->i_ump, fs, vp, blkno, fs->fs_bsize, inum,
+ vp->v_type, NULL);
}
return (0);
}
@@ -1528,7 +1532,8 @@ mapacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, expungetype)
*ip->i_snapblklist++ = lblkno;
if (blkno == BLK_SNAP)
blkno = blkstofrags(fs, lblkno);
- ffs_blkfree(ip->i_ump, fs, vp, blkno, fs->fs_bsize, inum, NULL);
+ ffs_blkfree(ip->i_ump, fs, vp, blkno, fs->fs_bsize, inum,
+ vp->v_type, NULL);
}
return (0);
}
@@ -1633,7 +1638,7 @@ ffs_snapremove(vp)
DIP_SET(ip, i_db[blkno], 0);
else if ((dblk == blkstofrags(fs, blkno) &&
ffs_snapblkfree(fs, ip->i_devvp, dblk, fs->fs_bsize,
- ip->i_number, NULL))) {
+ ip->i_number, vp->v_type, NULL))) {
DIP_SET(ip, i_blocks, DIP(ip, i_blocks) -
btodb(fs->fs_bsize));
DIP_SET(ip, i_db[blkno], 0);
@@ -1658,7 +1663,8 @@ ffs_snapremove(vp)
((ufs1_daddr_t *)(ibp->b_data))[loc]= 0;
else if ((dblk == blkstofrags(fs, blkno) &&
ffs_snapblkfree(fs, ip->i_devvp, dblk,
- fs->fs_bsize, ip->i_number, NULL))) {
+ fs->fs_bsize, ip->i_number, vp->v_type,
+ NULL))) {
ip->i_din1->di_blocks -=
btodb(fs->fs_bsize);
((ufs1_daddr_t *)(ibp->b_data))[loc]= 0;
@@ -1672,7 +1678,7 @@ ffs_snapremove(vp)
((ufs2_daddr_t *)(ibp->b_data))[loc] = 0;
else if ((dblk == blkstofrags(fs, blkno) &&
ffs_snapblkfree(fs, ip->i_devvp, dblk,
- fs->fs_bsize, ip->i_number, NULL))) {
+ fs->fs_bsize, ip->i_number, vp->v_type, NULL))) {
ip->i_din2->di_blocks -= btodb(fs->fs_bsize);
((ufs2_daddr_t *)(ibp->b_data))[loc] = 0;
}
@@ -1720,12 +1726,13 @@ ffs_snapremove(vp)
* must always have been allocated from a BLK_NOCOPY location.
*/
int
-ffs_snapblkfree(fs, devvp, bno, size, inum, wkhd)
+ffs_snapblkfree(fs, devvp, bno, size, inum, vtype, wkhd)
struct fs *fs;
struct vnode *devvp;
ufs2_daddr_t bno;
long size;
ino_t inum;
+ enum vtype vtype;
struct workhead *wkhd;
{
struct buf *ibp, *cbp, *savedcbp = 0;
@@ -1874,12 +1881,16 @@ retry:
* simply copy them to the new block. Note that we need
* to synchronously write snapshots that have not been
* unlinked, and hence will be visible after a crash,
- * to ensure their integrity.
+ * to ensure their integrity. At a minimum we ensure the
+ * integrity of the filesystem metadata, but use the
+ * dopersistence sysctl-setable flag to decide on the
+ * persistence needed for file content data.
*/
if (savedcbp != 0) {
bcopy(savedcbp->b_data, cbp->b_data, fs->fs_bsize);
bawrite(cbp);
- if (dopersistence && ip->i_effnlink > 0)
+ if ((vtype == VDIR || dopersistence) &&
+ ip->i_effnlink > 0)
(void) ffs_syncvnode(vp, MNT_WAIT);
continue;
}
@@ -1889,7 +1900,8 @@ retry:
if ((error = readblock(vp, cbp, lbn)) != 0) {
bzero(cbp->b_data, fs->fs_bsize);
bawrite(cbp);
- if (dopersistence && ip->i_effnlink > 0)
+ if ((vtype == VDIR || dopersistence) &&
+ ip->i_effnlink > 0)
(void) ffs_syncvnode(vp, MNT_WAIT);
break;
}
@@ -1898,12 +1910,15 @@ retry:
/*
* Note that we need to synchronously write snapshots that
* have not been unlinked, and hence will be visible after
- * a crash, to ensure their integrity.
+ * a crash, to ensure their integrity. At a minimum we
+ * ensure the integrity of the filesystem metadata, but
+ * use the dopersistence sysctl-setable flag to decide on
+ * the persistence needed for file content data.
*/
if (savedcbp) {
vp = savedcbp->b_vp;
bawrite(savedcbp);
- if (dopersistence && VTOI(vp)->i_effnlink > 0)
+ if ((vtype == VDIR || dopersistence) && ip->i_effnlink > 0)
(void) ffs_syncvnode(vp, MNT_WAIT);
}
/*
@@ -2358,12 +2373,16 @@ ffs_copyonwrite(devvp, bp)
* simply copy them to the new block. Note that we need
* to synchronously write snapshots that have not been
* unlinked, and hence will be visible after a crash,
- * to ensure their integrity.
+ * to ensure their integrity. At a minimum we ensure the
+ * integrity of the filesystem metadata, but use the
+ * dopersistence sysctl-setable flag to decide on the
+ * persistence needed for file content data.
*/
if (savedcbp != 0) {
bcopy(savedcbp->b_data, cbp->b_data, fs->fs_bsize);
bawrite(cbp);
- if (dopersistence && ip->i_effnlink > 0)
+ if ((devvp == bp->b_vp || bp->b_vp->v_type == VDIR ||
+ dopersistence) && ip->i_effnlink > 0)
(void) ffs_syncvnode(vp, MNT_WAIT);
else
launched_async_io = 1;
@@ -2375,7 +2394,8 @@ ffs_copyonwrite(devvp, bp)
if ((error = readblock(vp, cbp, lbn)) != 0) {
bzero(cbp->b_data, fs->fs_bsize);
bawrite(cbp);
- if (dopersistence && ip->i_effnlink > 0)
+ if ((devvp == bp->b_vp || bp->b_vp->v_type == VDIR ||
+ dopersistence) && ip->i_effnlink > 0)
(void) ffs_syncvnode(vp, MNT_WAIT);
else
launched_async_io = 1;
@@ -2386,12 +2406,16 @@ ffs_copyonwrite(devvp, bp)
/*
* Note that we need to synchronously write snapshots that
* have not been unlinked, and hence will be visible after
- * a crash, to ensure their integrity.
+ * a crash, to ensure their integrity. At a minimum we
+ * ensure the integrity of the filesystem metadata, but
+ * use the dopersistence sysctl-setable flag to decide on
+ * the persistence needed for file content data.
*/
if (savedcbp) {
vp = savedcbp->b_vp;
bawrite(savedcbp);
- if (dopersistence && VTOI(vp)->i_effnlink > 0)
+ if ((devvp == bp->b_vp || bp->b_vp->v_type == VDIR ||
+ dopersistence) && VTOI(vp)->i_effnlink > 0)
(void) ffs_syncvnode(vp, MNT_WAIT);
else
launched_async_io = 1;
OpenPOWER on IntegriCloud