Date: Mon, 14 Mar 2011 11:07:12 +0000 (UTC) From: Pawel Jakub Dawidek <pjd@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r219636 - head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs Message-ID: <201103141107.p2EB7C2W091679@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: pjd Date: Mon Mar 14 11:07:12 2011 New Revision: 219636 URL: http://svn.freebsd.org/changeset/base/219636 Log: Fix potential panic in dbuf_sync_list() relate to spill blocks handling. Obtained from: IllumOS MFC after: 1 month Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c ============================================================================== --- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c Mon Mar 14 10:51:24 2011 (r219635) +++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c Mon Mar 14 11:07:12 2011 (r219636) @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. */ #include <sys/zfs_context.h> @@ -1300,13 +1301,17 @@ dbuf_undirty(dmu_buf_impl_t *db, dmu_tx_ * it, since one of the current holders may be in the * middle of an update. Note that users of dbuf_undirty() * should not place a hold on the dbuf before the call. + * Also note: we can get here with a spill block, so + * test for that similar to how dbuf_dirty does. */ if (refcount_count(&db->db_holds) > db->db_dirtycnt) { mutex_exit(&db->db_mtx); /* Make sure we don't toss this buffer at sync phase */ - mutex_enter(&dn->dn_mtx); - dnode_clear_range(dn, db->db_blkid, 1, tx); - mutex_exit(&dn->dn_mtx); + if (db->db_blkid != DMU_SPILL_BLKID) { + mutex_enter(&dn->dn_mtx); + dnode_clear_range(dn, db->db_blkid, 1, tx); + mutex_exit(&dn->dn_mtx); + } DB_DNODE_EXIT(db); return (0); } @@ -1319,11 +1324,18 @@ dbuf_undirty(dmu_buf_impl_t *db, dmu_tx_ *drp = dr->dr_next; + /* + * Note that there are three places in dbuf_dirty() + * where this dirty record may be put on a list. + * Make sure to do a list_remove corresponding to + * every one of those list_insert calls. + */ if (dr->dr_parent) { mutex_enter(&dr->dr_parent->dt.di.dr_mtx); list_remove(&dr->dr_parent->dt.di.dr_children, dr); mutex_exit(&dr->dr_parent->dt.di.dr_mtx); - } else if (db->db_level+1 == dn->dn_nlevels) { + } else if (db->db_blkid == DMU_SPILL_BLKID || + db->db_level+1 == dn->dn_nlevels) { ASSERT(db->db_blkptr == NULL || db->db_parent == dn->dn_dbuf); mutex_enter(&dn->dn_mtx); list_remove(&dn->dn_dirty_records[txg & TXG_MASK], dr);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201103141107.p2EB7C2W091679>