Module Name:    src
Committed By:   hannken
Date:           Wed Feb 16 19:43:50 UTC 2011

Modified Files:
        src/sys/ufs/ffs: ffs_snapshot.c

Log Message:
Refine the scope of WAPBL transactions so we should no longer get
a "wapbl_flush: current transaction too big to flush" panic when
creating or removing snapshots on larger logging disks.

Adresses PR #44568 (WAPBL doens't play nice with snapshots).


To generate a diff of this commit:
cvs rdiff -u -r1.102 -r1.103 src/sys/ufs/ffs/ffs_snapshot.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/ufs/ffs/ffs_snapshot.c
diff -u src/sys/ufs/ffs/ffs_snapshot.c:1.102 src/sys/ufs/ffs/ffs_snapshot.c:1.103
--- src/sys/ufs/ffs/ffs_snapshot.c:1.102	Mon Dec 20 00:25:47 2010
+++ src/sys/ufs/ffs/ffs_snapshot.c	Wed Feb 16 19:43:50 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: ffs_snapshot.c,v 1.102 2010/12/20 00:25:47 matt Exp $	*/
+/*	$NetBSD: ffs_snapshot.c,v 1.103 2011/02/16 19:43:50 hannken Exp $	*/
 
 /*
  * Copyright 2000 Marshall Kirk McKusick. All Rights Reserved.
@@ -38,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.102 2010/12/20 00:25:47 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.103 2011/02/16 19:43:50 hannken Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ffs.h"
@@ -114,6 +114,7 @@
 static int rwfsblk(struct vnode *, int, void *, daddr_t);
 static int syncsnap(struct vnode *);
 static int wrsnapblk(struct vnode *, void *, daddr_t);
+static int blocks_in_journal(struct fs *);
 
 static inline bool is_active_snapshot(struct snap_info *, struct inode *);
 static inline daddr_t db_get(struct inode *, int);
@@ -403,11 +404,12 @@
 static int
 snapshot_setup(struct mount *mp, struct vnode *vp)
 {
-	int error, i, len, loc;
+	int error, n, len, loc;
 	daddr_t blkno, numblks;
 	struct buf *ibp, *nbp;
 	struct fs *fs = VFSTOUFS(mp)->um_fs;
 	struct lwp *l = curlwp;
+	const int wbreak = blocks_in_journal(fs)/8;
 
 	/*
 	 * Check mount, exclusive reference and owner.
@@ -452,13 +454,13 @@
 	error = UFS_WAPBL_BEGIN(mp);
 	if (error)
 		return error;
-	for (blkno = NDADDR, i = 0; blkno < numblks; blkno += NINDIR(fs)) {
+	for (blkno = NDADDR, n = 0; blkno < numblks; blkno += NINDIR(fs)) {
 		error = ffs_balloc(vp, lblktosize(fs, (off_t)blkno),
 		    fs->fs_bsize, l->l_cred, B_METAONLY, &ibp);
 		if (error)
 			goto out;
 		brelse(ibp, 0);
-		if ((++i % 16) == 0) {
+		if (wbreak > 0 && (++n % wbreak) == 0) {
 			UFS_WAPBL_END(mp);
 			error = UFS_WAPBL_BEGIN(mp);
 			if (error)
@@ -561,7 +563,6 @@
 snapshot_expunge(struct mount *mp, struct vnode *vp, struct fs *copy_fs,
     daddr_t *snaplistsize, daddr_t **snaplist)
 {
-	bool has_wapbl = false;
 	int cg, error, len, loc;
 	daddr_t blkno, *blkp;
 	struct fs *fs = VFSTOUFS(mp)->um_fs;
@@ -593,10 +594,6 @@
 	 */
 	*snaplistsize = fs->fs_ncg + howmany(fs->fs_cssize, fs->fs_bsize) +
 	    FSMAXSNAP + 1 /* superblock */ + 1 /* last block */ + 1 /* size */;
-	error = UFS_WAPBL_BEGIN(mp);
-	if (error)
-		goto out;
-	has_wapbl = true;
 	mutex_enter(&mntvnode_lock);
 	/*
 	 * NOTE: not using the TAILQ_FOREACH here since in this loop vgone()
@@ -648,19 +645,30 @@
 		if (loc < NDADDR) {
 			len = fragroundup(fs, blkoff(fs, xp->i_size));
 			if (len > 0 && len < fs->fs_bsize) {
+				error = UFS_WAPBL_BEGIN(mp);
+				if (error) {
+					(void)vunmark(mvp);
+					goto out;
+				}
 				ffs_blkfree_snap(copy_fs, vp, db_get(xp, loc),
 				    len, xp->i_number);
 				blkno = db_get(xp, loc);
 				db_assign(xp, loc, 0);
+				UFS_WAPBL_END(mp);
 			}
 		}
 		*snaplistsize += 1;
 		error = expunge(vp, xp, copy_fs, fullacct, BLK_NOCOPY);
 		if (blkno)
 			db_assign(xp, loc, blkno);
-		if (!error)
-			error = ffs_freefile_snap(copy_fs, vp, xp->i_number,
-			    xp->i_mode);
+		if (!error) {
+			error = UFS_WAPBL_BEGIN(mp);
+			if (!error) {
+				error = ffs_freefile_snap(copy_fs, vp,
+				    xp->i_number, xp->i_mode);
+				UFS_WAPBL_END(mp);
+			}
+		}
 		if (error) {
 			(void)vunmark(mvp);
 			goto out;
@@ -688,8 +696,6 @@
 	(*snaplist)[0] = blkp - &(*snaplist)[0];
 
 out:
-	if (has_wapbl)
-		UFS_WAPBL_END(mp);
 	if (mvp != NULL)
 		vnfree(mvp);
 	if (logvp != NULL)
@@ -711,16 +717,13 @@
 snapshot_expunge_snap(struct mount *mp, struct vnode *vp,
     struct fs *copy_fs, daddr_t snaplistsize)
 {
-	int error, i;
+	int error = 0, i;
 	daddr_t numblks, *snaplist = NULL;
 	struct fs *fs = VFSTOUFS(mp)->um_fs;
 	struct inode *ip = VTOI(vp), *xp;
 	struct lwp *l = curlwp;
 	struct snap_info *si = VFSTOUFS(mp)->um_snapinfo;
 
-	error = UFS_WAPBL_BEGIN(mp);
-	if (error)
-		return error;
 	TAILQ_FOREACH(xp, &si->si_snapshots, i_nextsnap) {
 		if (xp == ip)
 			break;
@@ -729,7 +732,11 @@
 			break;
 		if (xp->i_nlink != 0)
 			continue;
+		error = UFS_WAPBL_BEGIN(mp);
+		if (error)
+			break;
 		error = ffs_freefile_snap(copy_fs, vp, xp->i_number, xp->i_mode);
+		UFS_WAPBL_END(mp);
 		if (error)
 			break;
 	}
@@ -761,12 +768,10 @@
 		snaplist[i] = ufs_rw64(snaplist[i], UFS_FSNEEDSWAP(fs));
 	error = vn_rdwr(UIO_WRITE, vp, (void *)snaplist,
 	    snaplistsize * sizeof(daddr_t), lblktosize(fs, (off_t)numblks),
-	    UIO_SYSSPACE, IO_NODELOCKED | IO_JOURNALLOCKED | IO_UNIT,
-	    l->l_cred, NULL, NULL);
+	    UIO_SYSSPACE, IO_NODELOCKED | IO_UNIT, l->l_cred, NULL, NULL);
 	for (i = 0; i < snaplistsize; i++)
 		snaplist[i] = ufs_rw64(snaplist[i], UFS_FSNEEDSWAP(fs));
 out:
-	UFS_WAPBL_END(mp);
 	if (error && snaplist != NULL) {
 		free(snaplist, M_UFSMNT);
 		ip->i_snapblklist = NULL;
@@ -859,13 +864,10 @@
 static int
 cgaccount(struct vnode *vp, int passno, int *redo)
 {
-	int cg, error;
+	int cg, error = 0;
 	struct buf *nbp;
 	struct fs *fs = VTOI(vp)->i_fs;
 
-	error = UFS_WAPBL_BEGIN(vp->v_mount);
-	if (error)
-		return error;
 	if (redo != NULL)
 		*redo = 0;
 	if (passno == 1)
@@ -874,18 +876,24 @@
 	for (cg = 0; cg < fs->fs_ncg; cg++) {
 		if (passno == 2 && ACTIVECG_ISSET(fs, cg))
 			continue;
+
 		if (redo != NULL)
 			*redo += 1;
+		error = UFS_WAPBL_BEGIN(vp->v_mount);
+		if (error)
+			return error;
 		error = ffs_balloc(vp, lfragtosize(fs, cgtod(fs, cg)),
 		    fs->fs_bsize, curlwp->l_cred, 0, &nbp);
-		if (error)
+		if (error) {
+			UFS_WAPBL_END(vp->v_mount);
 			break;
+		}
 		error = cgaccount1(cg, vp, nbp->b_data, passno);
 		bawrite(nbp);
+		UFS_WAPBL_END(vp->v_mount);
 		if (error)
 			break;
 	}
-	UFS_WAPBL_END(vp->v_mount);
 	return error;
 }
 
@@ -992,8 +1000,14 @@
 	struct lwp *l = curlwp;
 	void *bap;
 	struct buf *bp;
+	struct mount *mp;
 
 	ns = UFS_FSNEEDSWAP(fs);
+	mp = snapvp->v_mount;
+
+	error = UFS_WAPBL_BEGIN(mp);
+	if (error)
+		return error;
 	/*
 	 * Prepare to expunge the inode. If its inode block has not
 	 * yet been copied, then allocate and fill the copy.
@@ -1011,8 +1025,10 @@
 		if (! error)
 			error = rwfsblk(snapvp, B_READ, bp->b_data, lbn);
 	}
-	if (error)
+	if (error) {
+		UFS_WAPBL_END(mp);
 		return error;
+	}
 	/*
 	 * Set a snapshot inode to be a zero length file, regular files
 	 * or unlinked snapshots to be completely unallocated.
@@ -1039,6 +1055,7 @@
 		memset(&dip2->di_db[0], 0, (NDADDR + NIADDR) * sizeof(int64_t));
 	}
 	bdwrite(bp);
+	UFS_WAPBL_END(mp);
 	/*
 	 * Now go through and expunge all the blocks in the file
 	 * using the function requested.
@@ -1048,13 +1065,15 @@
 		bap = &cancelip->i_ffs1_db[0];
 	else
 		bap = &cancelip->i_ffs2_db[0];
-	if ((error = (*acctfunc)(snapvp, bap, 0, NDADDR, fs, 0, expungetype)))
+	error = (*acctfunc)(snapvp, bap, 0, NDADDR, fs, 0, expungetype);
+	if (error)
 		return (error);
 	if (fs->fs_magic == FS_UFS1_MAGIC)
 		bap = &cancelip->i_ffs1_ib[0];
 	else
 		bap = &cancelip->i_ffs2_ib[0];
-	if ((error = (*acctfunc)(snapvp, bap, 0, NIADDR, fs, -1, expungetype)))
+	error = (*acctfunc)(snapvp, bap, 0, NIADDR, fs, -1, expungetype);
+	if (error)
 		return (error);
 	blksperindir = 1;
 	lbn = -NDADDR;
@@ -1170,12 +1189,17 @@
 {
 	struct inode *ip = VTOI(vp);
 	struct lwp *l = curlwp;
+	struct mount *mp = vp->v_mount;
 	daddr_t blkno;
 	daddr_t lbn;
 	struct buf *ibp;
-	int error;
+	int error, n;
+	const int wbreak = blocks_in_journal(VFSTOUFS(mp)->um_fs)/8;
 
-	for ( ; oldblkp < lastblkp; oldblkp++) {
+	error = UFS_WAPBL_BEGIN(mp);
+	if (error)
+		return error;
+	for ( n = 0; oldblkp < lastblkp; oldblkp++) {
 		blkno = idb_get(ip, bap, oldblkp);
 		if (blkno == 0 || blkno == BLK_NOCOPY || blkno == BLK_SNAP)
 			continue;
@@ -1187,7 +1211,7 @@
 			error = ffs_balloc(vp, lblktosize(fs, (off_t)lbn),
 			    fs->fs_bsize, l->l_cred, B_METAONLY, &ibp);
 			if (error)
-				return (error);
+				break;
 			blkno = idb_get(ip, ibp->b_data,
 			    (lbn - NDADDR) % NINDIR(fs));
 		}
@@ -1211,8 +1235,15 @@
 				bdwrite(ibp);
 			}
 		}
+		if (wbreak > 0 && (++n % wbreak) == 0) {
+			UFS_WAPBL_END(mp);
+			error = UFS_WAPBL_BEGIN(mp);
+			if (error)
+				return error;
+		}
 	}
-	return (0);
+	UFS_WAPBL_END(mp);
+	return error;
 }
 
 /*
@@ -1224,16 +1255,21 @@
 {
 	daddr_t blkno;
 	struct inode *ip;
+	struct mount *mp = vp->v_mount;
 	ino_t inum;
-	int acctit;
+	int acctit, error, n;
+	const int wbreak = blocks_in_journal(VFSTOUFS(mp)->um_fs)/8;
 
+	error = UFS_WAPBL_BEGIN(mp);
+	if (error)
+		return error;
 	ip = VTOI(vp);
 	inum = ip->i_number;
 	if (lblkno == -1)
 		acctit = 0;
 	else
 		acctit = 1;
-	for ( ; oldblkp < lastblkp; oldblkp++, lblkno++) {
+	for ( n = 0; oldblkp < lastblkp; oldblkp++, lblkno++) {
 		blkno = idb_get(ip, bap, oldblkp);
 		if (blkno == 0 || blkno == BLK_NOCOPY)
 			continue;
@@ -1242,7 +1278,14 @@
 		if (blkno == BLK_SNAP)
 			blkno = blkstofrags(fs, lblkno);
 		ffs_blkfree_snap(fs, vp, blkno, fs->fs_bsize, inum);
+		if (wbreak > 0 && (++n % wbreak) == 0) {
+			UFS_WAPBL_END(mp);
+			error = UFS_WAPBL_BEGIN(mp);
+			if (error)
+				return error;
+		}
 	}
+	UFS_WAPBL_END(mp);
 	return (0);
 }
 #endif /* defined(FFS_NO_SNAPSHOT) */
@@ -1309,7 +1352,8 @@
 	struct snap_info *si;
 	struct lwp *l = curlwp;
 	daddr_t numblks, blkno, dblk;
-	int error, loc, last;
+	int error, loc, last, n;
+	const int wbreak = blocks_in_journal(fs)/8;
 
 	si = VFSTOUFS(mp)->um_snapinfo;
 	/*
@@ -1357,7 +1401,7 @@
 		}
 	}
 	numblks = howmany(ip->i_size, fs->fs_bsize);
-	for (blkno = NDADDR; blkno < numblks; blkno += NINDIR(fs)) {
+	for (blkno = NDADDR, n = 0; blkno < numblks; blkno += NINDIR(fs)) {
 		error = ffs_balloc(vp, lblktosize(fs, (off_t)blkno),
 		    fs->fs_bsize, l->l_cred, B_METAONLY, &ibp);
 		if (error)
@@ -1367,6 +1411,12 @@
 		else
 			last = fs->fs_size - blkno;
 		for (loc = 0; loc < last; loc++) {
+			if (wbreak > 0 && (++n % wbreak) == 0) {
+				UFS_WAPBL_END(mp);
+				error = UFS_WAPBL_BEGIN(mp);
+				if (error)
+					panic("UFS_WAPBL_BEGIN failed");
+			}
 			dblk = idb_get(ip, ibp->b_data, loc);
 			if (dblk == BLK_NOCOPY || dblk == BLK_SNAP)
 				idb_assign(ip, ibp->b_data, loc, 0);
@@ -2141,6 +2191,33 @@
 }
 
 /*
+ * Number of blocks that fit into the journal or zero if not logging.
+ */
+static int
+blocks_in_journal(struct fs *fs)
+{
+	off_t bpj;
+
+	if ((fs->fs_flags & FS_DOWAPBL) == 0)
+		return 0;
+	bpj = 1;
+	if (fs->fs_journal_version == UFS_WAPBL_VERSION) {
+		switch (fs->fs_journal_location) {
+		case UFS_WAPBL_JOURNALLOC_END_PARTITION:
+			bpj = (off_t)fs->fs_journallocs[UFS_WAPBL_EPART_BLKSZ]*
+			    fs->fs_journallocs[UFS_WAPBL_EPART_COUNT];
+			break;
+		case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM:
+			bpj = (off_t)fs->fs_journallocs[UFS_WAPBL_INFS_BLKSZ]*
+			    fs->fs_journallocs[UFS_WAPBL_INFS_COUNT];
+			break;
+		}
+	}
+	bpj /= fs->fs_bsize;
+	return (bpj > 0 ? bpj : 1);
+}
+
+/*
  * Get/Put direct block from inode or buffer containing disk addresses. Take
  * care for fs type (UFS1/UFS2) and byte swapping. These functions should go
  * into a global include.

Reply via email to