提交 5d5053d5 编写于 作者: T Trond Myklebust 提交者: Zheng Zengkai

pNFS: Avoid a live lock condition in pnfs_update_layout()

stable inclusion
from stable-v5.10.124
commit 8acc3e228e1c90bd410f73597a4549e0409f22d6
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I5L6E7

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=8acc3e228e1c90bd410f73597a4549e0409f22d6

--------------------------------

[ Upstream commit 880265c7 ]

If we're about to send the first layoutget for an empty layout, we want
to make sure that we drain out the existing pending layoutget calls
first. The reason is that these layouts may have been already implicitly
returned to the server by a recall to which the client gave a
NFS4ERR_NOMATCHING_LAYOUT response.

The problem is that wait_var_event_killable() could in principle see the
plh_outstanding count go back to '1' when the first process to wake up
starts sending a new layoutget. If it fails to get a layout, then this
loop can continue ad infinitum...

Fixes: 0b77f97a ("NFSv4/pnfs: Fix layoutget behaviour after invalidation")
Signed-off-by: NTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: NAnna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: NSasha Levin <sashal@kernel.org>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
Reviewed-by: NWei Li <liwei391@huawei.com>
上级 cd4f26ed
...@@ -283,6 +283,7 @@ static u32 initiate_file_draining(struct nfs_client *clp, ...@@ -283,6 +283,7 @@ static u32 initiate_file_draining(struct nfs_client *clp,
rv = NFS4_OK; rv = NFS4_OK;
break; break;
case -ENOENT: case -ENOENT:
set_bit(NFS_LAYOUT_DRAIN, &lo->plh_flags);
/* Embrace your forgetfulness! */ /* Embrace your forgetfulness! */
rv = NFS4ERR_NOMATCHING_LAYOUT; rv = NFS4ERR_NOMATCHING_LAYOUT;
......
...@@ -469,6 +469,7 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo, ...@@ -469,6 +469,7 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo,
pnfs_clear_lseg_state(lseg, lseg_list); pnfs_clear_lseg_state(lseg, lseg_list);
pnfs_clear_layoutreturn_info(lo); pnfs_clear_layoutreturn_info(lo);
pnfs_free_returned_lsegs(lo, lseg_list, &range, 0); pnfs_free_returned_lsegs(lo, lseg_list, &range, 0);
set_bit(NFS_LAYOUT_DRAIN, &lo->plh_flags);
if (test_bit(NFS_LAYOUT_RETURN, &lo->plh_flags) && if (test_bit(NFS_LAYOUT_RETURN, &lo->plh_flags) &&
!test_and_set_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags)) !test_and_set_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags))
pnfs_clear_layoutreturn_waitbit(lo); pnfs_clear_layoutreturn_waitbit(lo);
...@@ -1923,8 +1924,9 @@ static void nfs_layoutget_begin(struct pnfs_layout_hdr *lo) ...@@ -1923,8 +1924,9 @@ static void nfs_layoutget_begin(struct pnfs_layout_hdr *lo)
static void nfs_layoutget_end(struct pnfs_layout_hdr *lo) static void nfs_layoutget_end(struct pnfs_layout_hdr *lo)
{ {
if (atomic_dec_and_test(&lo->plh_outstanding)) if (atomic_dec_and_test(&lo->plh_outstanding) &&
wake_up_var(&lo->plh_outstanding); test_and_clear_bit(NFS_LAYOUT_DRAIN, &lo->plh_flags))
wake_up_bit(&lo->plh_flags, NFS_LAYOUT_DRAIN);
} }
static bool pnfs_is_first_layoutget(struct pnfs_layout_hdr *lo) static bool pnfs_is_first_layoutget(struct pnfs_layout_hdr *lo)
...@@ -2031,11 +2033,11 @@ pnfs_update_layout(struct inode *ino, ...@@ -2031,11 +2033,11 @@ pnfs_update_layout(struct inode *ino,
* If the layout segment list is empty, but there are outstanding * If the layout segment list is empty, but there are outstanding
* layoutget calls, then they might be subject to a layoutrecall. * layoutget calls, then they might be subject to a layoutrecall.
*/ */
if ((list_empty(&lo->plh_segs) || !pnfs_layout_is_valid(lo)) && if (test_bit(NFS_LAYOUT_DRAIN, &lo->plh_flags) &&
atomic_read(&lo->plh_outstanding) != 0) { atomic_read(&lo->plh_outstanding) != 0) {
spin_unlock(&ino->i_lock); spin_unlock(&ino->i_lock);
lseg = ERR_PTR(wait_var_event_killable(&lo->plh_outstanding, lseg = ERR_PTR(wait_on_bit(&lo->plh_flags, NFS_LAYOUT_DRAIN,
!atomic_read(&lo->plh_outstanding))); TASK_KILLABLE));
if (IS_ERR(lseg)) if (IS_ERR(lseg))
goto out_put_layout_hdr; goto out_put_layout_hdr;
pnfs_put_layout_hdr(lo); pnfs_put_layout_hdr(lo);
...@@ -2414,7 +2416,8 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) ...@@ -2414,7 +2416,8 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
goto out_forget; goto out_forget;
} }
if (!pnfs_layout_is_valid(lo) && !pnfs_is_first_layoutget(lo)) if (test_bit(NFS_LAYOUT_DRAIN, &lo->plh_flags) &&
!pnfs_is_first_layoutget(lo))
goto out_forget; goto out_forget;
if (nfs4_stateid_match_other(&lo->plh_stateid, &res->stateid)) { if (nfs4_stateid_match_other(&lo->plh_stateid, &res->stateid)) {
......
...@@ -107,6 +107,7 @@ enum { ...@@ -107,6 +107,7 @@ enum {
NFS_LAYOUT_FIRST_LAYOUTGET, /* Serialize first layoutget */ NFS_LAYOUT_FIRST_LAYOUTGET, /* Serialize first layoutget */
NFS_LAYOUT_INODE_FREEING, /* The inode is being freed */ NFS_LAYOUT_INODE_FREEING, /* The inode is being freed */
NFS_LAYOUT_HASHED, /* The layout visible */ NFS_LAYOUT_HASHED, /* The layout visible */
NFS_LAYOUT_DRAIN,
}; };
enum layoutdriver_policy_flags { enum layoutdriver_policy_flags {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册