diff options
author | mckusick <mckusick@FreeBSD.org> | 2000-12-19 04:41:09 +0000 |
---|---|---|
committer | mckusick <mckusick@FreeBSD.org> | 2000-12-19 04:41:09 +0000 |
commit | d1a83511c997df4f465dfb9e1d1ab2e2c3666f2c (patch) | |
tree | abc5a685e18eb929d3697eca0a425c11dc6b6c9f /sys/ufs/ffs/ffs_snapshot.c | |
parent | 119826523104113decb150c935cd97d39d2b5890 (diff) | |
download | FreeBSD-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/ufs/ffs/ffs_snapshot.c')
-rw-r--r-- | sys/ufs/ffs/ffs_snapshot.c | 50 |
1 files changed, 36 insertions, 14 deletions
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 |