kern/141387: [zfs] [patch] zfs snapshot -r failed because filesystem was busy

Martin Matuska mm at FreeBSD.org
Fri Dec 11 22:40:02 UTC 2009


>Number:         141387
>Category:       kern
>Synopsis:       [zfs] [patch] zfs snapshot -r failed because filesystem was busy
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Dec 11 22:40:01 UTC 2009
>Closed-Date:
>Last-Modified:
>Originator:     Martin Matuska
>Release:        FreeBSD 8-STABLE amd64
>Organization:
>Environment:
System: FreeBSD 8-STABLE FreeBSD 8-STABLE #2
>Description:
There is a bug in ZFS recursive snapshot that was already fixed in OpenSolaris snv_111
I was able to reproduce this bug in FreeBSD.

References:
Opensolaris Bug ID: 6462803
http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=6462803

This bug was fixed in OpenSolaris snv_111:
http://dlc.sun.com/osol/on/downloads/b111/on-changelog-b111.html

Issues Resolved:
BUG/RFE:6462803 zfs snapshot -r failed because filesystem was busy
Files Changed:
update:usr/src/cmd/zdb/zdb_il.c
update:usr/src/grub/grub-0.97/stage2/zfs-include/zil.h
update:usr/src/uts/common/fs/zfs/sys/zil.h
update:usr/src/uts/common/fs/zfs/zil.c

Revision: 8989:cfce31f4eebf

hg clone ssh://anon@hg.opensolaris.org/hg/onnv/onnv-gate
hg diff -c 8989 onnv-gate
>How-To-Repeat:
This may happen during ZFS recursive snapshot (managed to reproduce it):
root at www:~ > zfs snapshot -r pool at test
cannot create snapshot 'pool at test': dataset is busy
no snapshots were created
>Fix:
Index: cddl/contrib/opensolaris/cmd/zdb/zdb_il.c
===================================================================
--- cddl/contrib/opensolaris/cmd/zdb/zdb_il.c	(revision 200415)
+++ cddl/contrib/opensolaris/cmd/zdb/zdb_il.c	(working copy)
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Print intent log header and statistics.
  */
@@ -345,8 +343,10 @@
 	if (zh->zh_log.blk_birth == 0 || verbose < 2)
 		return;
 
-	(void) printf("\n    ZIL header: claim_txg %llu, seq %llu\n",
-	    (u_longlong_t)zh->zh_claim_txg, (u_longlong_t)zh->zh_replay_seq);
+	(void) printf("\n    ZIL header: claim_txg %llu, claim_seq %llu",
+	    (u_longlong_t)zh->zh_claim_txg, (u_longlong_t)zh->zh_claim_seq);
+	(void) printf(" replay_seq %llu, flags 0x%llx\n",
+	    (u_longlong_t)zh->zh_replay_seq, (u_longlong_t)zh->zh_flags);
 
 	if (verbose >= 4)
 		print_log_bp(&zh->zh_log, "\n\tfirst block: ");
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c	(revision 200415)
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c	(working copy)
@@ -502,6 +502,25 @@
 	    tx, zh->zh_claim_txg);
 }
 
+/*
+ * return true if the initial log block is not valid
+ */
+static boolean_t
+zil_empty(zilog_t *zilog)
+{
+	const zil_header_t *zh = zilog->zl_header;
+	arc_buf_t *abuf = NULL;
+
+	if (BP_IS_HOLE(&zh->zh_log))
+		return (B_TRUE);
+
+	if (zil_read_log_block(zilog, &zh->zh_log, &abuf) != 0)
+		return (B_TRUE);
+
+	VERIFY(arc_buf_remove_ref(abuf, &abuf) == 1);
+	return (B_FALSE);
+}
+
 int
 zil_claim(char *osname, void *txarg)
 {
@@ -522,6 +541,21 @@
 	zh = zil_header_in_syncing_context(zilog);
 
 	/*
+	 * Record here whether the zil has any records to replay.
+	 * If the header block pointer is null or the block points
+	 * to the stubby then we know there are no valid log records.
+	 * We use the header to store this state as the the zilog gets
+	 * freed later in dmu_objset_close().
+	 * The flags (and the rest of the header fields) are cleared in
+	 * zil_sync() as a result of a zil_destroy(), after replaying the log.
+	 *
+	 * Note, the intent log can be empty but still need the
+	 * stubby to be claimed.
+	 */
+	if (!zil_empty(zilog))
+		zh->zh_flags |= ZIL_REPLAY_NEEDED;
+
+	/*
 	 * Claim all log blocks if we haven't already done so, and remember
 	 * the highest claimed sequence number.  This ensures that if we can
 	 * read only part of the log now (e.g. due to a missing device),
@@ -1345,25 +1379,6 @@
 }
 
 /*
- * return true if the initial log block is not valid
- */
-static boolean_t
-zil_empty(zilog_t *zilog)
-{
-	const zil_header_t *zh = zilog->zl_header;
-	arc_buf_t *abuf = NULL;
-
-	if (BP_IS_HOLE(&zh->zh_log))
-		return (B_TRUE);
-
-	if (zil_read_log_block(zilog, &zh->zh_log, &abuf) != 0)
-		return (B_TRUE);
-
-	VERIFY(arc_buf_remove_ref(abuf, &abuf) == 1);
-	return (B_FALSE);
-}
-
-/*
  * Open an intent log.
  */
 zilog_t *
@@ -1418,7 +1433,7 @@
 	const zil_header_t *zh = zilog->zl_header;
 
 	mutex_enter(&zilog->zl_lock);
-	if (zh->zh_claim_txg != 0) {		/* unplayed log */
+	if (zh->zh_flags & ZIL_REPLAY_NEEDED) {		/* unplayed log */
 		mutex_exit(&zilog->zl_lock);
 		return (EBUSY);
 	}
@@ -1645,7 +1660,7 @@
 	const zil_header_t *zh = zilog->zl_header;
 	zil_replay_arg_t zr;
 
-	if (zil_empty(zilog)) {
+	if ((zh->zh_flags & ZIL_REPLAY_NEEDED) == 0) {
 		zil_destroy(zilog, B_TRUE);
 		return;
 	}
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zil.h
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zil.h	(revision 200415)
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zil.h	(working copy)
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -56,10 +56,16 @@
 	uint64_t zh_replay_seq;	/* highest replayed sequence number */
 	blkptr_t zh_log;	/* log chain */
 	uint64_t zh_claim_seq;	/* highest claimed sequence number */
-	uint64_t zh_pad[5];
+	uint64_t zh_flags;	/* header flags */
+	uint64_t zh_pad[4];
 } zil_header_t;
 
 /*
+ * zh_flags bit settings
+ */
+#define	ZIL_REPLAY_NEEDED 0x1	/* replay needed - internal only */
+
+/*
  * Log block trailer - structure at the end of the header and each log block
  *
  * The zit_bt contains a zbt_cksum which for the intent log is
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list