From 7045329caa73e7fb03bc735bd3e0a63e923ff7ca Mon Sep 17 00:00:00 2001 From: Tim Chase Date: Sun, 15 Mar 2015 19:30:19 -0500 Subject: [PATCH] Fix deadlocks resulting from the post-kmem rework merge Since many more allocations are allowed to sleep following the post-kmem rework merge, there are many more opportunities for deadlocks related to the pre-superblock z_hold_mtx array. This patch puts all threads locking z_hold_mtx under PF_STRANS to disallow re-entry into the zfs code. --- module/zfs/dbuf.c | 1 + module/zfs/dmu.c | 3 +++ module/zfs/dmu_zfetch.c | 3 +++ module/zfs/sa.c | 5 ++++- module/zfs/zfs_znode.c | 33 ++++++++++++++++++++++++--------- 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index f10a04d112a8..987b75c5275b 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -2089,6 +2089,7 @@ dbuf_hold(dnode_t *dn, uint64_t blkid, void *tag) { dmu_buf_impl_t *db; int err = dbuf_hold_impl(dn, 0, blkid, FALSE, tag, &db); + return (err ? NULL : db); } diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index 1501ae8046ad..71f35357b061 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -573,10 +573,13 @@ dmu_prefetch(objset_t *os, uint64_t object, uint64_t offset, uint64_t len) if (nblks != 0) { int i; + fstrans_cookie_t cookie; blkid = dbuf_whichblock(dn, offset); + cookie = spl_fstrans_mark(); for (i = 0; i < nblks; i++) dbuf_prefetch(dn, blkid + i, ZIO_PRIORITY_SYNC_READ); + spl_fstrans_unmark(cookie); } rw_exit(&dn->dn_struct_rwlock); diff --git a/module/zfs/dmu_zfetch.c b/module/zfs/dmu_zfetch.c index 8ff2f0509787..40773b59a05c 100644 --- a/module/zfs/dmu_zfetch.c +++ b/module/zfs/dmu_zfetch.c @@ -289,12 +289,15 @@ dmu_zfetch_fetch(dnode_t *dn, uint64_t blkid, uint64_t nblks) { uint64_t fetchsz; uint64_t i; + fstrans_cookie_t cookie; fetchsz = dmu_zfetch_fetchsz(dn, blkid, nblks); + cookie = spl_fstrans_mark(); for (i = 0; i < fetchsz; i++) { dbuf_prefetch(dn, blkid + i, ZIO_PRIORITY_ASYNC_READ); } + spl_fstrans_unmark(cookie); return (fetchsz); } diff --git a/module/zfs/sa.c b/module/zfs/sa.c index 9063d1dae449..ca719c563158 100644 --- a/module/zfs/sa.c +++ b/module/zfs/sa.c @@ -1436,7 +1436,10 @@ sa_handle_get(objset_t *objset, uint64_t objid, void *userp, int sa_buf_hold(objset_t *objset, uint64_t obj_num, void *tag, dmu_buf_t **db) { - return (dmu_bonus_hold(objset, obj_num, tag, db)); + int rval; + + rval = (dmu_bonus_hold(objset, obj_num, tag, db)); + return (rval); } void diff --git a/module/zfs/zfs_znode.c b/module/zfs/zfs_znode.c index 3a7c30db2cfa..398ff502af23 100644 --- a/module/zfs/zfs_znode.c +++ b/module/zfs/zfs_znode.c @@ -564,6 +564,7 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr, sa_bulk_attr_t *sa_attrs; int cnt = 0; zfs_acl_locator_cb_t locate = { 0 }; + fstrans_cookie_t cookie; if (zsb->z_replay) { obj = vap->va_nodeid; @@ -610,6 +611,7 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr, } } + cookie = spl_fstrans_mark(); ZFS_OBJ_HOLD_ENTER(zsb, obj); VERIFY(0 == sa_buf_hold(zsb->z_os, obj, NULL, &db)); @@ -785,6 +787,7 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr, } kmem_free(sa_attrs, sizeof (sa_bulk_attr_t) * ZPL_END); ZFS_OBJ_HOLD_EXIT(zsb, obj); + spl_fstrans_unmark(cookie); } /* @@ -890,6 +893,7 @@ zfs_zget(zfs_sb_t *zsb, uint64_t obj_num, znode_t **zpp) znode_t *zp; int err; sa_handle_t *hdl; + fstrans_cookie_t cookie = spl_fstrans_mark(); *zpp = NULL; @@ -899,6 +903,7 @@ zfs_zget(zfs_sb_t *zsb, uint64_t obj_num, znode_t **zpp) err = sa_buf_hold(zsb->z_os, obj_num, NULL, &db); if (err) { ZFS_OBJ_HOLD_EXIT(zsb, obj_num); + spl_fstrans_unmark(cookie); return (err); } @@ -909,6 +914,7 @@ zfs_zget(zfs_sb_t *zsb, uint64_t obj_num, znode_t **zpp) doi.doi_bonus_size < sizeof (znode_phys_t)))) { sa_buf_rele(db, NULL); ZFS_OBJ_HOLD_EXIT(zsb, obj_num); + spl_fstrans_unmark(cookie); return (SET_ERROR(EINVAL)); } @@ -956,6 +962,7 @@ zfs_zget(zfs_sb_t *zsb, uint64_t obj_num, znode_t **zpp) mutex_exit(&zp->z_lock); sa_buf_rele(db, NULL); ZFS_OBJ_HOLD_EXIT(zsb, obj_num); + spl_fstrans_unmark(cookie); return (err); } @@ -977,6 +984,7 @@ zfs_zget(zfs_sb_t *zsb, uint64_t obj_num, znode_t **zpp) *zpp = zp; } ZFS_OBJ_HOLD_EXIT(zsb, obj_num); + spl_fstrans_unmark(cookie); return (err); } @@ -992,7 +1000,9 @@ zfs_rezget(znode_t *zp) int err; int count = 0; uint64_t gen; + fstrans_cookie_t cookie; + cookie = spl_fstrans_mark(); ZFS_OBJ_HOLD_ENTER(zsb, obj_num); mutex_enter(&zp->z_acl_lock); @@ -1018,6 +1028,7 @@ zfs_rezget(znode_t *zp) err = sa_buf_hold(zsb->z_os, obj_num, NULL, &db); if (err) { ZFS_OBJ_HOLD_EXIT(zsb, obj_num); + spl_fstrans_unmark(cookie); return (err); } @@ -1028,6 +1039,7 @@ zfs_rezget(znode_t *zp) doi.doi_bonus_size < sizeof (znode_phys_t)))) { sa_buf_rele(db, NULL); ZFS_OBJ_HOLD_EXIT(zsb, obj_num); + spl_fstrans_unmark(cookie); return (SET_ERROR(EINVAL)); } @@ -1054,6 +1066,7 @@ zfs_rezget(znode_t *zp) if (sa_bulk_lookup(zp->z_sa_hdl, bulk, count)) { zfs_znode_dmu_fini(zp); ZFS_OBJ_HOLD_EXIT(zsb, obj_num); + spl_fstrans_unmark(cookie); return (SET_ERROR(EIO)); } @@ -1062,6 +1075,7 @@ zfs_rezget(znode_t *zp) if (gen != zp->z_gen) { zfs_znode_dmu_fini(zp); ZFS_OBJ_HOLD_EXIT(zsb, obj_num); + spl_fstrans_unmark(cookie); return (SET_ERROR(EIO)); } @@ -1070,6 +1084,7 @@ zfs_rezget(znode_t *zp) zfs_inode_update(zp); ZFS_OBJ_HOLD_EXIT(zsb, obj_num); + spl_fstrans_unmark(cookie); return (0); } @@ -1081,6 +1096,7 @@ zfs_znode_delete(znode_t *zp, dmu_tx_t *tx) objset_t *os = zsb->z_os; uint64_t obj = zp->z_id; uint64_t acl_obj = zfs_external_acl(zp); + fstrans_cookie_t cookie = spl_fstrans_mark(); ZFS_OBJ_HOLD_ENTER(zsb, obj); if (acl_obj) { @@ -1090,6 +1106,7 @@ zfs_znode_delete(znode_t *zp, dmu_tx_t *tx) VERIFY(0 == dmu_object_free(os, obj, tx)); zfs_znode_dmu_fini(zp); ZFS_OBJ_HOLD_EXIT(zsb, obj); + spl_fstrans_unmark(cookie); } void @@ -1097,7 +1114,7 @@ zfs_zinactive(znode_t *zp) { zfs_sb_t *zsb = ZTOZSB(zp); uint64_t z_id = zp->z_id; - boolean_t drop_mutex = 0; + fstrans_cookie_t cookie; ASSERT(zp->z_sa_hdl); @@ -1110,10 +1127,8 @@ zfs_zinactive(znode_t *zp) * zfs_zinactive() call path. To avoid this deadlock the process * must not reacquire the mutex when it is already holding it. */ - if (!ZFS_OBJ_HOLD_OWNED(zsb, z_id)) { - ZFS_OBJ_HOLD_ENTER(zsb, z_id); - drop_mutex = 1; - } + cookie = spl_fstrans_mark(); + ZFS_OBJ_HOLD_ENTER(zsb, z_id); mutex_enter(&zp->z_lock); @@ -1124,8 +1139,8 @@ zfs_zinactive(znode_t *zp) if (zp->z_unlinked) { mutex_exit(&zp->z_lock); - if (drop_mutex) - ZFS_OBJ_HOLD_EXIT(zsb, z_id); + ZFS_OBJ_HOLD_EXIT(zsb, z_id); + spl_fstrans_unmark(cookie); zfs_rmnode(zp); return; @@ -1134,8 +1149,8 @@ zfs_zinactive(znode_t *zp) mutex_exit(&zp->z_lock); zfs_znode_dmu_fini(zp); - if (drop_mutex) - ZFS_OBJ_HOLD_EXIT(zsb, z_id); + ZFS_OBJ_HOLD_EXIT(zsb, z_id); + spl_fstrans_unmark(cookie); } static inline int