diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-01-17 22:57:37 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-01-31 19:28:08 -0500 |
commit | 961a828df64979d2a9faeeeee043391670a193b9 (patch) | |
tree | 4b7ddaf1a19c589e3c8ec96b6c732faa507f2899 /fs | |
parent | 2aeb98f498ce37742b743080fdc6c8cf64053599 (diff) |
SUNRPC: Fix potential races in xprt_lock_write_next()
We have to ensure that the wake up from the waitqueue and the assignment
of xprt->snd_task are atomic. We can do this by assigning the snd_task
while under the waitqueue spinlock.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/nfs4_fs.h | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 13 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 17 |
3 files changed, 17 insertions, 14 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index df3d02c3e8cb..c45c21a5470f 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -222,6 +222,7 @@ static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *ser | |||
222 | return server->nfs_client->cl_session; | 222 | return server->nfs_client->cl_session; |
223 | } | 223 | } |
224 | 224 | ||
225 | extern bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy); | ||
225 | extern int nfs4_setup_sequence(const struct nfs_server *server, | 226 | extern int nfs4_setup_sequence(const struct nfs_server *server, |
226 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | 227 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, |
227 | struct rpc_task *task); | 228 | struct rpc_task *task); |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 360240cc1e9b..828a76590af9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -385,17 +385,20 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) | |||
385 | free_slotid, tbl->highest_used_slotid); | 385 | free_slotid, tbl->highest_used_slotid); |
386 | } | 386 | } |
387 | 387 | ||
388 | bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy) | ||
389 | { | ||
390 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
391 | return true; | ||
392 | } | ||
393 | |||
388 | /* | 394 | /* |
389 | * Signal state manager thread if session fore channel is drained | 395 | * Signal state manager thread if session fore channel is drained |
390 | */ | 396 | */ |
391 | static void nfs4_check_drain_fc_complete(struct nfs4_session *ses) | 397 | static void nfs4_check_drain_fc_complete(struct nfs4_session *ses) |
392 | { | 398 | { |
393 | struct rpc_task *task; | ||
394 | |||
395 | if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { | 399 | if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { |
396 | task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq); | 400 | rpc_wake_up_first(&ses->fc_slot_table.slot_tbl_waitq, |
397 | if (task) | 401 | nfs4_set_task_privileged, NULL); |
398 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
399 | return; | 402 | return; |
400 | } | 403 | } |
401 | 404 | ||
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index a42e60d3ee50..f0e9881c2aa2 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -190,23 +190,22 @@ static int nfs41_setup_state_renewal(struct nfs_client *clp) | |||
190 | static void nfs4_end_drain_session(struct nfs_client *clp) | 190 | static void nfs4_end_drain_session(struct nfs_client *clp) |
191 | { | 191 | { |
192 | struct nfs4_session *ses = clp->cl_session; | 192 | struct nfs4_session *ses = clp->cl_session; |
193 | struct nfs4_slot_table *tbl; | ||
193 | int max_slots; | 194 | int max_slots; |
194 | 195 | ||
195 | if (ses == NULL) | 196 | if (ses == NULL) |
196 | return; | 197 | return; |
198 | tbl = &ses->fc_slot_table; | ||
197 | if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { | 199 | if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { |
198 | spin_lock(&ses->fc_slot_table.slot_tbl_lock); | 200 | spin_lock(&tbl->slot_tbl_lock); |
199 | max_slots = ses->fc_slot_table.max_slots; | 201 | max_slots = tbl->max_slots; |
200 | while (max_slots--) { | 202 | while (max_slots--) { |
201 | struct rpc_task *task; | 203 | if (rpc_wake_up_first(&tbl->slot_tbl_waitq, |
202 | 204 | nfs4_set_task_privileged, | |
203 | task = rpc_wake_up_next(&ses->fc_slot_table. | 205 | NULL) == NULL) |
204 | slot_tbl_waitq); | ||
205 | if (!task) | ||
206 | break; | 206 | break; |
207 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
208 | } | 207 | } |
209 | spin_unlock(&ses->fc_slot_table.slot_tbl_lock); | 208 | spin_unlock(&tbl->slot_tbl_lock); |
210 | } | 209 | } |
211 | } | 210 | } |
212 | 211 | ||