Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/ufs/ffs/ffs_snapshot.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/ufs/ffs/ffs_snapshot.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.137 retrieving revision 1.137.2.3 diff -u -p -r1.137 -r1.137.2.3 --- src/sys/ufs/ffs/ffs_snapshot.c 2014/09/05 06:10:07 1.137 +++ src/sys/ufs/ffs/ffs_snapshot.c 2016/12/05 10:55:30 1.137.2.3 @@ -1,4 +1,4 @@ -/* $NetBSD: ffs_snapshot.c,v 1.137 2014/09/05 06:10:07 matt Exp $ */ +/* $NetBSD: ffs_snapshot.c,v 1.137.2.3 2016/12/05 10:55:30 skrll Exp $ */ /* * Copyright 2000 Marshall Kirk McKusick. All Rights Reserved. @@ -38,7 +38,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.137 2014/09/05 06:10:07 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.137.2.3 2016/12/05 10:55:30 skrll Exp $"); #if defined(_KERNEL_OPT) #include "opt_ffs.h" @@ -82,7 +82,7 @@ TAILQ_HEAD(inodelst, inode); /* List o struct snap_info { kmutex_t si_lock; /* Lock this snapinfo */ kmutex_t si_snaplock; /* Snapshot vnode common lock */ - lwp_t *si_owner; /* Sanplock owner */ + lwp_t *si_owner; /* Snaplock owner */ struct inodelst si_snapshots; /* List of active snapshots */ daddr_t *si_snapblklist; /* Snapshot block hints list */ uint32_t si_gen; /* Incremented on change */ @@ -198,12 +198,12 @@ ffs_snapshot(struct mount *mp, struct vn /* * If the vnode already is a snapshot, return. */ - if ((VTOI(vp)->i_flags & SF_SNAPSHOT)) { - if ((VTOI(vp)->i_flags & SF_SNAPINVAL)) + if ((ip->i_flags & SF_SNAPSHOT)) { + if ((ip->i_flags & SF_SNAPINVAL)) return EINVAL; if (ctime) { - ctime->tv_sec = DIP(VTOI(vp), mtime); - ctime->tv_nsec = DIP(VTOI(vp), mtimensec); + ctime->tv_sec = DIP(ip, mtime); + ctime->tv_nsec = DIP(ip, mtimensec); } return 0; } @@ -269,9 +269,9 @@ ffs_snapshot(struct mount *mp, struct vn * Create a copy of the superblock and its summary information. */ error = snapshot_copyfs(mp, vp, &sbbuf); - copy_fs = (struct fs *)((char *)sbbuf + ffs_blkoff(fs, fs->fs_sblockloc)); if (error) goto out; + copy_fs = (struct fs *)((char *)sbbuf + ffs_blkoff(fs, fs->fs_sblockloc)); /* * Expunge unlinked files from our view. */ @@ -402,6 +402,12 @@ out: } if (error) { if (UFS_WAPBL_BEGIN(mp) == 0) { + /* + * We depend on ffs_truncate() to call ffs_snapremove() + * before it may return an error. On failed + * ffs_truncate() we have normal file with leaked + * (meta-) data, but no snapshot to use. + */ (void) ffs_truncate(vp, (off_t)0, 0, NOCRED); UFS_WAPBL_END(mp); } @@ -437,7 +443,12 @@ snapshot_setup(struct mount *mp, struct return EACCES; if (vp->v_size != 0) { - error = ffs_truncate(vp, 0, 0, NOCRED); + /* + * Must completely truncate the file here. Allocated + * blocks on a snapshot mean that block has been copied + * on write, see ffs_copyonwrite() testing "blkno != 0" + */ + error = ufs_truncate_retry(vp, 0, NOCRED); if (error) return error; } @@ -553,7 +564,6 @@ snapshot_copyfs(struct mount *mp, struct int32_t *lp; struct buf *bp; struct fs *copyfs, *fs = VFSTOUFS(mp)->um_fs; - struct lwp *l = curlwp; struct vnode *devvp = VTOI(vp)->i_devvp; /* @@ -568,7 +578,7 @@ snapshot_copyfs(struct mount *mp, struct memcpy(copyfs, fs, fs->fs_sbsize); size = fs->fs_bsize < SBLOCKSIZE ? fs->fs_bsize : SBLOCKSIZE; if (fs->fs_sbsize < size) - memset((char *)(*sbbuf) + loc + fs->fs_sbsize, 0, + memset((char *)(*sbbuf) + loc + fs->fs_sbsize, 0, size - fs->fs_sbsize); size = ffs_blkroundup(fs, fs->fs_cssize); if (fs->fs_contigsumsize > 0) @@ -582,7 +592,7 @@ snapshot_copyfs(struct mount *mp, struct len = (i == fs->fs_frag) ? 0 : i * fs->fs_fsize; if (len > 0) { if ((error = bread(devvp, FFS_FSBTODB(fs, fs->fs_csaddr + loc), - len, l->l_cred, 0, &bp)) != 0) { + len, 0, &bp)) != 0) { free(copyfs->fs_csp, M_UFSMNT); free(*sbbuf, M_UFSMNT); *sbbuf = NULL; @@ -860,7 +870,7 @@ snapshot_writefs(struct mount *mp, struc if (error) return error; for (loc = 0; loc < len; loc++) { - error = bread(vp, blkno + loc, fs->fs_bsize, l->l_cred, + error = bread(vp, blkno + loc, fs->fs_bsize, B_MODIFY, &bp); if (error) { break; @@ -872,7 +882,7 @@ snapshot_writefs(struct mount *mp, struc if (error) goto out; error = bread(vp, ffs_lblkno(fs, fs->fs_sblockloc), - fs->fs_bsize, l->l_cred, B_MODIFY, &bp); + fs->fs_bsize, B_MODIFY, &bp); if (error) { goto out; } else { @@ -966,7 +976,7 @@ cgaccount1(int cg, struct vnode *vp, voi fs = ip->i_fs; ns = UFS_FSNEEDSWAP(fs); error = bread(ip->i_devvp, FFS_FSBTODB(fs, cgtod(fs, cg)), - (int)fs->fs_cgsize, l->l_cred, 0, &bp); + (int)fs->fs_cgsize, 0, &bp); if (error) { return (error); } @@ -1062,7 +1072,7 @@ expunge(struct vnode *snapvp, struct ino if (error) return error; if (blkno != 0) { - error = bread(snapvp, lbn, fs->fs_bsize, l->l_cred, + error = bread(snapvp, lbn, fs->fs_bsize, B_MODIFY, &bp); } else { error = ffs_balloc(snapvp, ffs_lblktosize(fs, (off_t)lbn), @@ -1559,7 +1569,7 @@ ffs_snapblkfree(struct fs *fs, struct vn mutex_enter(&si->si_snaplock); mutex_enter(&si->si_lock); si->si_owner = curlwp; - + retry: gen = si->si_gen; TAILQ_FOREACH(ip, &si->si_snapshots, i_nextsnap) { @@ -2094,11 +2104,11 @@ ffs_snapshot_read(struct vnode *vp, stru if (ffs_lblktosize(fs, lbn) + size > fsbytes) size = ffs_fragroundup(fs, fsbytes - ffs_lblktosize(fs, lbn)); - error = bread(vp, lbn, size, NOCRED, 0, &bp); + error = bread(vp, lbn, size, 0, &bp); } else { int nextsize = fs->fs_bsize; error = breadn(vp, lbn, - size, &nextlbn, &nextsize, 1, NOCRED, 0, &bp); + size, &nextlbn, &nextsize, 1, 0, &bp); } if (error) break; @@ -2162,7 +2172,7 @@ snapblkaddr(struct vnode *vp, daddr_t lb mutex_exit(&bufcache_lock); return error; } - error = bread(vp, indirs[num-1].in_lbn, fs->fs_bsize, NOCRED, 0, &bp); + error = bread(vp, indirs[num-1].in_lbn, fs->fs_bsize, 0, &bp); if (error == 0) { *res = idb_get(ip, bp->b_data, indirs[num-1].in_off); brelse(bp, 0);