HomeFreeBSD

Fix deadlock in zfs_zget()

Description

Fix deadlock in zfs_zget()

zfsonlinux/zfs#180 occurred because of a race between inode eviction and
zfs_zget(). zfsonlinux/zfs@36df284 tried to address it by making a call
to the VFS to learn whether an inode is being evicted. If it was being
evicted the operation was retried after dropping and reacquiring the
relevant resources. Unfortunately, this introduced another deadlock.

INFO: task kworker/u24:6:891 blocked for more than 120 seconds.
      Tainted: P           O 3.13.6 #1
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
kworker/u24:6   D ffff88107fcd2e80     0   891      2 0x00000000
Workqueue: writeback bdi_writeback_workfn (flush-zfs-5)
 ffff8810370ff950 0000000000000002 ffff88103853d940 0000000000012e80
 ffff8810370fffd8 0000000000012e80 ffff88103853d940 ffff880f5c8be098
 ffff88107ffb6950 ffff8810370ff980 ffff88103a9a5b78 0000000000000000
Call Trace:
 [<ffffffff813dd1d4>] schedule+0x24/0x70
 [<ffffffff8115fc09>] __wait_on_freeing_inode+0x99/0xc0
 [<ffffffff8115fdd8>] find_inode_fast+0x78/0xb0
 [<ffffffff811608c5>] ilookup+0x65/0xd0
 [<ffffffffa035c5ab>] zfs_zget+0xdb/0x260 [zfs]
 [<ffffffffa03589d6>] zfs_get_data+0x46/0x340 [zfs]
 [<ffffffffa035fee1>] zil_add_block+0xa31/0xc00 [zfs]
 [<ffffffffa0360642>] zil_commit+0x12/0x20 [zfs]
 [<ffffffffa036a6e4>] zpl_putpage+0x174/0x840 [zfs]
 [<ffffffff811071ec>] do_writepages+0x1c/0x40
 [<ffffffff8116df2b>] __writeback_single_inode+0x3b/0x2b0
 [<ffffffff8116ecf7>] writeback_sb_inodes+0x247/0x420
 [<ffffffff8116f5f3>] wb_writeback+0xe3/0x320
 [<ffffffff81170b8e>] bdi_writeback_workfn+0xfe/0x490
 [<ffffffff8106072c>] process_one_work+0x16c/0x490
 [<ffffffff810613f3>] worker_thread+0x113/0x390
 [<ffffffff81066edf>] kthread+0xdf/0x100

This patch implements the original fix in a slightly different manner in
order to avoid both deadlocks. Instead of relying on a call to ilookup()
which can block in __wait_on_freeing_inode() the return value from igrab()
is used. This gives us the information that ilookup() provided without
the risk of a deadlock.

Alternately, this race could be closed by registering an sops->drop_inode()
callback. The callback would need to detect the active SA hold thereby
informing the VFS that this inode should not be evicted.

Signed-off-by: Richard Yao <ryao@gentoo.org>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Issue #180

Details

Provenance
Richard Yao <ryao@gentoo.org>Authored on Mar 25 2014, 7:41 PM
Brian Behlendorf <behlendorf1@llnl.gov>Committed on Apr 4 2014, 4:11 PM
Parents
rG8ac67298b175: Revert "Fixed a use-after-free bug in zfs_zget()."
Branches
Unknown
Tags
Unknown