summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2000-12-19 04:41:09 +0000
committermckusick <mckusick@FreeBSD.org>2000-12-19 04:41:09 +0000
commitd1a83511c997df4f465dfb9e1d1ab2e2c3666f2c (patch)
treeabc5a685e18eb929d3697eca0a425c11dc6b6c9f /sys
parent119826523104113decb150c935cd97d39d2b5890 (diff)
downloadFreeBSD-src-d1a83511c997df4f465dfb9e1d1ab2e2c3666f2c.zip
FreeBSD-src-d1a83511c997df4f465dfb9e1d1ab2e2c3666f2c.tar.gz
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>).
Diffstat (limited to 'sys')
-rw-r--r--sys/ufs/ffs/ffs_extern.h1
-rw-r--r--sys/ufs/ffs/ffs_snapshot.c50
-rw-r--r--sys/ufs/ufs/ufs_extern.h2
-rw-r--r--sys/ufs/ufs/ufs_lookup.c4
4 files changed, 40 insertions, 17 deletions
diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h
index e5ef387..7801412 100644
--- a/sys/ufs/ffs/ffs_extern.h
+++ b/sys/ufs/ffs/ffs_extern.h
@@ -94,6 +94,7 @@ 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));
+void ffs_snapremove __P((struct vnode *vp));
int ffs_snapshot __P((struct mount *mp, char *snapfile));
void ffs_snapshot_mount __P((struct mount *mp));
void ffs_snapshot_unmount __P((struct mount *mp));
diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c
index d27a926..a4b2dea 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
diff --git a/sys/ufs/ufs/ufs_extern.h b/sys/ufs/ufs/ufs_extern.h
index fea9272..a5c7a47 100644
--- a/sys/ufs/ufs/ufs_extern.h
+++ b/sys/ufs/ufs/ufs_extern.h
@@ -87,7 +87,7 @@ int ufs_init __P((struct vfsconf *));
void ufs_itimes __P((struct vnode *vp));
int ufs_lookup __P((struct vop_cachedlookup_args *));
int ufs_reclaim __P((struct vop_reclaim_args *));
-void ffs_snapremove __P((struct vnode *vp));
+void ffs_snapgone __P((struct inode *));
int ufs_root __P((struct mount *, struct vnode **));
int ufs_start __P((struct mount *, int, struct proc *));
int ufs_vinit __P((struct mount *, vop_t **, vop_t **, struct vnode **));
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c
index 6901e33..1396484 100644
--- a/sys/ufs/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs/ufs_lookup.c
@@ -950,7 +950,7 @@ out:
* when last open reference goes away.
*/
if (ip != 0 && (ip->i_flags & SF_SNAPSHOT) != 0 && ip->i_effnlink == 0)
- vrele(ITOV(ip));
+ ffs_snapgone(ip);
return (error);
}
@@ -999,7 +999,7 @@ ufs_dirrewrite(dp, oip, newinum, newtype, isrmdir)
* when last open reference goes away.
*/
if ((oip->i_flags & SF_SNAPSHOT) != 0 && oip->i_effnlink == 0)
- vrele(ITOV(oip));
+ ffs_snapgone(oip);
return (error);
}
OpenPOWER on IntegriCloud