Skip to content

Commit

Permalink
Avoid reacquiring a mutex in zfs_zinactive
Browse files Browse the repository at this point in the history
Commit @40d06e3 removed a scheme to avoid reacquiring a mutex in
zfs_zinactive. It turns out this the scheme is necessary. Reinstate it.

Signed-off-by: Chris Dunlop <chris@onthe.net.au>
Issue openzfs#3225
Closes openzfs#3304
  • Loading branch information
chrisrd committed Apr 16, 2015
1 parent b467db4 commit 21ba38f
Showing 1 changed file with 15 additions and 3 deletions.
18 changes: 15 additions & 3 deletions module/zfs/zfs_znode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1099,13 +1099,23 @@ zfs_zinactive(znode_t *zp)
{
zfs_sb_t *zsb = ZTOZSB(zp);
uint64_t z_id = zp->z_id;
boolean_t drop_mutex = 0;

ASSERT(zp->z_sa_hdl);

/*
* Don't allow a zfs_zget() while were trying to release this znode.
*
* Linux allows direct memory reclaim which means that any KM_SLEEP
* allocation may trigger inode eviction. This can lead to a deadlock
* through the ->shrink_icache_memory()->evict()->zfs_inactive()->
* zfs_zinactive() call path. To avoid this deadlock the process
* must not reacquire the mutex when it is already holding it.
*/
ZFS_OBJ_HOLD_ENTER(zsb, z_id);
if (!ZFS_OBJ_HOLD_OWNED(zsb, z_id)) {
ZFS_OBJ_HOLD_ENTER(zsb, z_id);
drop_mutex = 1;
}

mutex_enter(&zp->z_lock);

Expand All @@ -1116,7 +1126,8 @@ zfs_zinactive(znode_t *zp)
if (zp->z_unlinked) {
mutex_exit(&zp->z_lock);

ZFS_OBJ_HOLD_EXIT(zsb, z_id);
if (drop_mutex)
ZFS_OBJ_HOLD_EXIT(zsb, z_id);

zfs_rmnode(zp);
return;
Expand All @@ -1125,7 +1136,8 @@ zfs_zinactive(znode_t *zp)
mutex_exit(&zp->z_lock);
zfs_znode_dmu_fini(zp);

ZFS_OBJ_HOLD_EXIT(zsb, z_id);
if (drop_mutex)
ZFS_OBJ_HOLD_EXIT(zsb, z_id);
}

static inline int
Expand Down

0 comments on commit 21ba38f

Please sign in to comment.