diff options
Diffstat (limited to 'fs/ceph/inode.c')
-rw-r--r-- | fs/ceph/inode.c | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 3acdd3cc6039..761451f36e2d 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
@@ -1476,7 +1476,8 @@ static int readdir_prepopulate_inodes_only(struct ceph_mds_request *req, | |||
1476 | pr_err("fill_inode badness on %p got %d\n", in, rc); | 1476 | pr_err("fill_inode badness on %p got %d\n", in, rc); |
1477 | err = rc; | 1477 | err = rc; |
1478 | } | 1478 | } |
1479 | iput(in); | 1479 | /* avoid calling iput_final() in mds dispatch threads */ |
1480 | ceph_async_iput(in); | ||
1480 | } | 1481 | } |
1481 | 1482 | ||
1482 | return err; | 1483 | return err; |
@@ -1674,8 +1675,11 @@ retry_lookup: | |||
1674 | &req->r_caps_reservation); | 1675 | &req->r_caps_reservation); |
1675 | if (ret < 0) { | 1676 | if (ret < 0) { |
1676 | pr_err("fill_inode badness on %p\n", in); | 1677 | pr_err("fill_inode badness on %p\n", in); |
1677 | if (d_really_is_negative(dn)) | 1678 | if (d_really_is_negative(dn)) { |
1678 | iput(in); | 1679 | /* avoid calling iput_final() in mds |
1680 | * dispatch threads */ | ||
1681 | ceph_async_iput(in); | ||
1682 | } | ||
1679 | d_drop(dn); | 1683 | d_drop(dn); |
1680 | err = ret; | 1684 | err = ret; |
1681 | goto next_item; | 1685 | goto next_item; |
@@ -1685,7 +1689,7 @@ retry_lookup: | |||
1685 | if (ceph_security_xattr_deadlock(in)) { | 1689 | if (ceph_security_xattr_deadlock(in)) { |
1686 | dout(" skip splicing dn %p to inode %p" | 1690 | dout(" skip splicing dn %p to inode %p" |
1687 | " (security xattr deadlock)\n", dn, in); | 1691 | " (security xattr deadlock)\n", dn, in); |
1688 | iput(in); | 1692 | ceph_async_iput(in); |
1689 | skipped++; | 1693 | skipped++; |
1690 | goto next_item; | 1694 | goto next_item; |
1691 | } | 1695 | } |
@@ -1737,6 +1741,25 @@ bool ceph_inode_set_size(struct inode *inode, loff_t size) | |||
1737 | } | 1741 | } |
1738 | 1742 | ||
1739 | /* | 1743 | /* |
1744 | * Put reference to inode, but avoid calling iput_final() in current thread. | ||
1745 | * iput_final() may wait for reahahead pages. The wait can cause deadlock in | ||
1746 | * some contexts. | ||
1747 | */ | ||
1748 | void ceph_async_iput(struct inode *inode) | ||
1749 | { | ||
1750 | if (!inode) | ||
1751 | return; | ||
1752 | for (;;) { | ||
1753 | if (atomic_add_unless(&inode->i_count, -1, 1)) | ||
1754 | break; | ||
1755 | if (queue_work(ceph_inode_to_client(inode)->inode_wq, | ||
1756 | &ceph_inode(inode)->i_work)) | ||
1757 | break; | ||
1758 | /* queue work failed, i_count must be at least 2 */ | ||
1759 | } | ||
1760 | } | ||
1761 | |||
1762 | /* | ||
1740 | * Write back inode data in a worker thread. (This can't be done | 1763 | * Write back inode data in a worker thread. (This can't be done |
1741 | * in the message handler context.) | 1764 | * in the message handler context.) |
1742 | */ | 1765 | */ |