]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - queue-4.19/nfsv4.1-again-fix-a-race-where-cb_notify_lock-fails-to-wake-a-waiter.patch
4.14-stable patches
[thirdparty/kernel/stable-queue.git] / queue-4.19 / nfsv4.1-again-fix-a-race-where-cb_notify_lock-fails-to-wake-a-waiter.patch
CommitLineData
5c6958b0
GKH
1From 52b042ab9948cc367b61f9ca9c18603aa7813c3a Mon Sep 17 00:00:00 2001
2From: Yihao Wu <wuyihao@linux.alibaba.com>
3Date: Wed, 22 May 2019 01:57:10 +0800
4Subject: NFSv4.1: Again fix a race where CB_NOTIFY_LOCK fails to wake a waiter
5
6From: Yihao Wu <wuyihao@linux.alibaba.com>
7
8commit 52b042ab9948cc367b61f9ca9c18603aa7813c3a upstream.
9
10Commit b7dbcc0e433f "NFSv4.1: Fix a race where CB_NOTIFY_LOCK fails to wake a waiter"
11found this bug. However it didn't fix it.
12
13This commit replaces schedule_timeout() with wait_woken() and
14default_wake_function() with woken_wake_function() in function
15nfs4_retry_setlk() and nfs4_wake_lock_waiter(). wait_woken() uses
16memory barriers in its implementation to avoid potential race condition
17when putting a process into sleeping state and then waking it up.
18
19Fixes: a1d617d8f134 ("nfs: allow blocking locks to be awoken by lock callbacks")
20Cc: stable@vger.kernel.org #4.9+
21Signed-off-by: Yihao Wu <wuyihao@linux.alibaba.com>
22Reviewed-by: Jeff Layton <jlayton@kernel.org>
23Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
24Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
25
26---
27 fs/nfs/nfs4proc.c | 24 +++++++-----------------
28 1 file changed, 7 insertions(+), 17 deletions(-)
29
30--- a/fs/nfs/nfs4proc.c
31+++ b/fs/nfs/nfs4proc.c
32@@ -6850,7 +6850,6 @@ struct nfs4_lock_waiter {
33 struct task_struct *task;
34 struct inode *inode;
35 struct nfs_lowner *owner;
36- bool notified;
37 };
38
39 static int
40@@ -6872,13 +6871,13 @@ nfs4_wake_lock_waiter(wait_queue_entry_t
41 /* Make sure it's for the right inode */
42 if (nfs_compare_fh(NFS_FH(waiter->inode), &cbnl->cbnl_fh))
43 return 0;
44-
45- waiter->notified = true;
46 }
47
48 /* override "private" so we can use default_wake_function */
49 wait->private = waiter->task;
50- ret = autoremove_wake_function(wait, mode, flags, key);
51+ ret = woken_wake_function(wait, mode, flags, key);
52+ if (ret)
53+ list_del_init(&wait->entry);
54 wait->private = waiter;
55 return ret;
56 }
57@@ -6887,7 +6886,6 @@ static int
58 nfs4_retry_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
59 {
60 int status = -ERESTARTSYS;
61- unsigned long flags;
62 struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner;
63 struct nfs_server *server = NFS_SERVER(state->inode);
64 struct nfs_client *clp = server->nfs_client;
65@@ -6897,8 +6895,7 @@ nfs4_retry_setlk(struct nfs4_state *stat
66 .s_dev = server->s_dev };
67 struct nfs4_lock_waiter waiter = { .task = current,
68 .inode = state->inode,
69- .owner = &owner,
70- .notified = false };
71+ .owner = &owner};
72 wait_queue_entry_t wait;
73
74 /* Don't bother with waitqueue if we don't expect a callback */
75@@ -6911,21 +6908,14 @@ nfs4_retry_setlk(struct nfs4_state *stat
76 add_wait_queue(q, &wait);
77
78 while(!signalled()) {
79- waiter.notified = false;
80 status = nfs4_proc_setlk(state, cmd, request);
81 if ((status != -EAGAIN) || IS_SETLK(cmd))
82 break;
83
84 status = -ERESTARTSYS;
85- spin_lock_irqsave(&q->lock, flags);
86- if (waiter.notified) {
87- spin_unlock_irqrestore(&q->lock, flags);
88- continue;
89- }
90- set_current_state(TASK_INTERRUPTIBLE);
91- spin_unlock_irqrestore(&q->lock, flags);
92-
93- freezable_schedule_timeout(NFS4_LOCK_MAXTIMEOUT);
94+ freezer_do_not_count();
95+ wait_woken(&wait, TASK_INTERRUPTIBLE, NFS4_LOCK_MAXTIMEOUT);
96+ freezer_count();
97 }
98
99 finish_wait(q, &wait);