Skip to content

Commit

Permalink
Fix deadlocks resulting from the post-kmem rework merge
Browse files Browse the repository at this point in the history
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.

Also, lock down all the dmu_tx_hold family of functions since they can
also cause deadlocks during direct reclaim.
  • Loading branch information
dweeezil committed Mar 29, 2015
1 parent 4c7b7ee commit 6d617e7
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 26 deletions.
1 change: 1 addition & 0 deletions module/zfs/dbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
3 changes: 3 additions & 0 deletions module/zfs/dmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
70 changes: 54 additions & 16 deletions module/zfs/dmu_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,20 +150,22 @@ dmu_tx_hold_object_impl(dmu_tx_t *tx, objset_t *os, uint64_t object,
txh->txh_arg2 = arg2;
#endif
list_insert_tail(&tx->tx_holds, txh);

return (txh);
}

void
dmu_tx_add_new_object(dmu_tx_t *tx, objset_t *os, uint64_t object)
{
fstrans_cookie_t cookie;
/*
* If we're syncing, they can manipulate any object anyhow, and
* the hold on the dnode_t can cause problems.
*/
if (!dmu_tx_is_syncing(tx)) {
cookie = spl_fstrans_mark();
(void) dmu_tx_hold_object_impl(tx, os,
object, THT_NEWOBJECT, 0, 0);
spl_fstrans_unmark(cookie);
}
}

Expand Down Expand Up @@ -418,18 +420,21 @@ void
dmu_tx_hold_write(dmu_tx_t *tx, uint64_t object, uint64_t off, int len)
{
dmu_tx_hold_t *txh;
fstrans_cookie_t cookie;

ASSERT(tx->tx_txg == 0);
ASSERT(len < DMU_MAX_ACCESS);
ASSERT(len == 0 || UINT64_MAX - off >= len - 1);

cookie = spl_fstrans_mark();
txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
object, THT_WRITE, off, len);
if (txh == NULL)
return;

dmu_tx_count_write(txh, off, len);
dmu_tx_count_dnode(txh);
spl_fstrans_unmark(cookie);
}

static void
Expand Down Expand Up @@ -607,18 +612,20 @@ dmu_tx_hold_free(dmu_tx_t *tx, uint64_t object, uint64_t off, uint64_t len)
dnode_t *dn;
int err;
zio_t *zio;
fstrans_cookie_t cookie;

ASSERT(tx->tx_txg == 0);

cookie = spl_fstrans_mark();
txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
object, THT_FREE, off, len);
if (txh == NULL)
return;
goto out;
dn = txh->txh_dnode;
dmu_tx_count_dnode(txh);

if (off >= (dn->dn_maxblkid+1) * dn->dn_datablksz)
return;
goto out;
if (len == DMU_OBJECT_END)
len = (dn->dn_maxblkid+1) * dn->dn_datablksz - off;

Expand Down Expand Up @@ -675,23 +682,25 @@ dmu_tx_hold_free(dmu_tx_t *tx, uint64_t object, uint64_t off, uint64_t len)
break;
if (err) {
tx->tx_err = err;
return;
goto out;
}

err = dmu_tx_check_ioerr(zio, dn, 1, i);
if (err) {
tx->tx_err = err;
return;
goto out;
}
}
err = zio_wait(zio);
if (err) {
tx->tx_err = err;
return;
goto out;
}
}

dmu_tx_count_free(txh, off, len);
out:
spl_fstrans_unmark(cookie);
}

void
Expand All @@ -701,13 +710,15 @@ dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name)
dnode_t *dn;
uint64_t nblocks;
int epbs, err;
fstrans_cookie_t cookie;

ASSERT(tx->tx_txg == 0);

cookie = spl_fstrans_mark();
txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
object, THT_ZAP, add, (uintptr_t)name);
if (txh == NULL)
return;
goto out;
dn = txh->txh_dnode;

dmu_tx_count_dnode(txh);
Expand All @@ -719,7 +730,7 @@ dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name)
* including the header block.
*/
dmu_tx_count_write(txh, 0, 2 << fzap_default_block_shift);
return;
goto out;
}

ASSERT3U(DMU_OT_BYTESWAP(dn->dn_type), ==, DMU_BSWAP_ZAP);
Expand All @@ -734,7 +745,7 @@ dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name)
err = dmu_tx_check_ioerr(NULL, dn, 0, 0);
if (err) {
tx->tx_err = err;
return;
goto out;
}

/*
Expand All @@ -749,7 +760,7 @@ dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name)
txh->txh_space_towrite += SPA_MAXBLOCKSIZE;
if (!BP_IS_HOLE(bp))
txh->txh_space_tounref += SPA_MAXBLOCKSIZE;
return;
goto out;
}

if (dn->dn_maxblkid > 0 && name) {
Expand All @@ -761,7 +772,7 @@ dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name)
8, 0, NULL);
if (err == EIO) {
tx->tx_err = err;
return;
goto out;
}
}

Expand All @@ -778,32 +789,41 @@ dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name)
txh->txh_space_towrite += 3 << dn->dn_indblkshift;
else
txh->txh_space_tooverwrite += 3 << dn->dn_indblkshift;

out:
spl_fstrans_unmark(cookie);
}

void
dmu_tx_hold_bonus(dmu_tx_t *tx, uint64_t object)
{
dmu_tx_hold_t *txh;
fstrans_cookie_t cookie;

ASSERT(tx->tx_txg == 0);

cookie = spl_fstrans_mark();
txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
object, THT_BONUS, 0, 0);
if (txh)
dmu_tx_count_dnode(txh);
spl_fstrans_unmark(cookie);
}

void
dmu_tx_hold_space(dmu_tx_t *tx, uint64_t space)
{
dmu_tx_hold_t *txh;
fstrans_cookie_t cookie;

ASSERT(tx->tx_txg == 0);

cookie = spl_fstrans_mark();
txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
DMU_NEW_OBJECT, THT_SPACE, space, 0);
if (txh)
txh->txh_space_towrite += space;
spl_fstrans_unmark(cookie);
}

int
Expand Down Expand Up @@ -1509,10 +1529,12 @@ static void
dmu_tx_sa_registration_hold(sa_os_t *sa, dmu_tx_t *tx)
{
int i;
fstrans_cookie_t cookie;

if (!sa->sa_need_attr_registration)
return;

cookie = spl_fstrans_mark();
for (i = 0; i != sa->sa_num_attrs; i++) {
if (!sa->sa_attr_table[i].sa_registered) {
if (sa->sa_reg_attr_obj)
Expand All @@ -1523,6 +1545,7 @@ dmu_tx_sa_registration_hold(sa_os_t *sa, dmu_tx_t *tx)
B_TRUE, sa->sa_attr_table[i].sa_name);
}
}
spl_fstrans_unmark(cookie);
}


Expand All @@ -1531,16 +1554,18 @@ dmu_tx_hold_spill(dmu_tx_t *tx, uint64_t object)
{
dnode_t *dn;
dmu_tx_hold_t *txh;
fstrans_cookie_t cookie;

cookie = spl_fstrans_mark();
txh = dmu_tx_hold_object_impl(tx, tx->tx_objset, object,
THT_SPILL, 0, 0);
if (txh == NULL)
return;
goto out;

dn = txh->txh_dnode;

if (dn == NULL)
return;
goto out;

/* If blkptr doesn't exist then add space to towrite */
if (!(dn->dn_phys->dn_flags & DNODE_FLAG_SPILL_BLKPTR)) {
Expand All @@ -1557,17 +1582,22 @@ dmu_tx_hold_spill(dmu_tx_t *tx, uint64_t object)
if (!BP_IS_HOLE(bp))
txh->txh_space_tounref += SPA_MAXBLOCKSIZE;
}

out:
spl_fstrans_unmark(cookie);
}

void
dmu_tx_hold_sa_create(dmu_tx_t *tx, int attrsize)
{
sa_os_t *sa = tx->tx_objset->os_sa;
fstrans_cookie_t cookie;

cookie = spl_fstrans_mark();
dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);

if (tx->tx_objset->os_sa->sa_master_obj == 0)
return;
goto out;

if (tx->tx_objset->os_sa->sa_layout_attr_obj)
dmu_tx_hold_zap(tx, sa->sa_layout_attr_obj, B_TRUE, NULL);
Expand All @@ -1581,10 +1611,13 @@ dmu_tx_hold_sa_create(dmu_tx_t *tx, int attrsize)
dmu_tx_sa_registration_hold(sa, tx);

if (attrsize <= DN_MAX_BONUSLEN && !sa->sa_force_spill)
return;
goto out;

(void) dmu_tx_hold_object_impl(tx, tx->tx_objset, DMU_NEW_OBJECT,
THT_SPILL, 0, 0);

out:
spl_fstrans_unmark(cookie);
}

/*
Expand All @@ -1601,15 +1634,17 @@ dmu_tx_hold_sa(dmu_tx_t *tx, sa_handle_t *hdl, boolean_t may_grow)
{
uint64_t object;
sa_os_t *sa = tx->tx_objset->os_sa;
fstrans_cookie_t cookie;

ASSERT(hdl != NULL);

object = sa_handle_object(hdl);

cookie = spl_fstrans_mark();
dmu_tx_hold_bonus(tx, object);

if (tx->tx_objset->os_sa->sa_master_obj == 0)
return;
goto out;

if (tx->tx_objset->os_sa->sa_reg_attr_obj == 0 ||
tx->tx_objset->os_sa->sa_layout_attr_obj == 0) {
Expand Down Expand Up @@ -1639,6 +1674,9 @@ dmu_tx_hold_sa(dmu_tx_t *tx, sa_handle_t *hdl, boolean_t may_grow)
}
DB_DNODE_EXIT(db);
}

out:
spl_fstrans_unmark(cookie);
}

void
Expand Down
3 changes: 3 additions & 0 deletions module/zfs/dmu_zfetch.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
5 changes: 4 additions & 1 deletion module/zfs/sa.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 6d617e7

Please sign in to comment.