diff options
author | Trond Myklebust <trondmy@gmail.com> | 2018-08-14 17:55:56 -0400 |
---|---|---|
committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2018-08-15 12:05:15 -0400 |
commit | 8618289c46556fd4dd259a1af02ccc448032f48d (patch) | |
tree | dae02612130410f169459c9a56e81dcbab2e7f6b /fs/nfs/callback_proc.c | |
parent | d0fbb1d8a194c0ec0180c1d073ad709e45503a43 (diff) |
NFSv4: Fix a sleep in atomic context in nfs4_callback_sequence()
We must drop the lock before we can sleep in referring_call_exists().
Reported-by: Jia-Ju Bai <baijiaju1990@gmail.com>
Fixes: 045d2a6d076a ("NFSv4.1: Delay callback processing...")
Cc: stable@vger.kernel.org # v4.9+
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Diffstat (limited to 'fs/nfs/callback_proc.c')
-rw-r--r-- | fs/nfs/callback_proc.c | 14 |
1 files changed, 10 insertions, 4 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index cd733649646b..fa515d5ea5ba 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -442,11 +442,14 @@ validate_seqid(const struct nfs4_slot_table *tbl, const struct nfs4_slot *slot, | |||
442 | * a match. If the slot is in use and the sequence numbers match, the | 442 | * a match. If the slot is in use and the sequence numbers match, the |
443 | * client is still waiting for a response to the original request. | 443 | * client is still waiting for a response to the original request. |
444 | */ | 444 | */ |
445 | static bool referring_call_exists(struct nfs_client *clp, | 445 | static int referring_call_exists(struct nfs_client *clp, |
446 | uint32_t nrclists, | 446 | uint32_t nrclists, |
447 | struct referring_call_list *rclists) | 447 | struct referring_call_list *rclists, |
448 | spinlock_t *lock) | ||
449 | __releases(lock) | ||
450 | __acquires(lock) | ||
448 | { | 451 | { |
449 | bool status = false; | 452 | int status = 0; |
450 | int i, j; | 453 | int i, j; |
451 | struct nfs4_session *session; | 454 | struct nfs4_session *session; |
452 | struct nfs4_slot_table *tbl; | 455 | struct nfs4_slot_table *tbl; |
@@ -469,8 +472,10 @@ static bool referring_call_exists(struct nfs_client *clp, | |||
469 | 472 | ||
470 | for (j = 0; j < rclist->rcl_nrefcalls; j++) { | 473 | for (j = 0; j < rclist->rcl_nrefcalls; j++) { |
471 | ref = &rclist->rcl_refcalls[j]; | 474 | ref = &rclist->rcl_refcalls[j]; |
475 | spin_unlock(lock); | ||
472 | status = nfs4_slot_wait_on_seqid(tbl, ref->rc_slotid, | 476 | status = nfs4_slot_wait_on_seqid(tbl, ref->rc_slotid, |
473 | ref->rc_sequenceid, HZ >> 1) < 0; | 477 | ref->rc_sequenceid, HZ >> 1) < 0; |
478 | spin_lock(lock); | ||
474 | if (status) | 479 | if (status) |
475 | goto out; | 480 | goto out; |
476 | } | 481 | } |
@@ -547,7 +552,8 @@ __be32 nfs4_callback_sequence(void *argp, void *resp, | |||
547 | * related callback was received before the response to the original | 552 | * related callback was received before the response to the original |
548 | * call. | 553 | * call. |
549 | */ | 554 | */ |
550 | if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists)) { | 555 | if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists, |
556 | &tbl->slot_tbl_lock) < 0) { | ||
551 | status = htonl(NFS4ERR_DELAY); | 557 | status = htonl(NFS4ERR_DELAY); |
552 | goto out_unlock; | 558 | goto out_unlock; |
553 | } | 559 | } |