diff options
-rw-r--r-- | fs/nfs/callback_proc.c | 2 | ||||
-rw-r--r-- | fs/nfs/callback_xdr.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4client.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4session.c | 4 | ||||
-rw-r--r-- | fs/nfs/nfs4session.h | 13 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 15 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 62 | ||||
-rw-r--r-- | net/sunrpc/netns.h | 4 | ||||
-rw-r--r-- | net/sunrpc/rpc_pipe.c | 5 | ||||
-rw-r--r-- | net/sunrpc/sched.c | 8 |
11 files changed, 78 insertions, 41 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index a13d26ede254..0bc27684ebfa 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -414,7 +414,7 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, | |||
414 | 414 | ||
415 | spin_lock(&tbl->slot_tbl_lock); | 415 | spin_lock(&tbl->slot_tbl_lock); |
416 | /* state manager is resetting the session */ | 416 | /* state manager is resetting the session */ |
417 | if (test_bit(NFS4_SESSION_DRAINING, &clp->cl_session->session_state)) { | 417 | if (test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state)) { |
418 | spin_unlock(&tbl->slot_tbl_lock); | 418 | spin_unlock(&tbl->slot_tbl_lock); |
419 | status = htonl(NFS4ERR_DELAY); | 419 | status = htonl(NFS4ERR_DELAY); |
420 | /* Return NFS4ERR_BADSESSION if we're draining the session | 420 | /* Return NFS4ERR_BADSESSION if we're draining the session |
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 59461c957d9d..a35582c9d444 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -763,7 +763,7 @@ static void nfs4_callback_free_slot(struct nfs4_session *session) | |||
763 | * A single slot, so highest used slotid is either 0 or -1 | 763 | * A single slot, so highest used slotid is either 0 or -1 |
764 | */ | 764 | */ |
765 | tbl->highest_used_slotid = NFS4_NO_SLOT; | 765 | tbl->highest_used_slotid = NFS4_NO_SLOT; |
766 | nfs4_session_drain_complete(session, tbl); | 766 | nfs4_slot_tbl_drain_complete(tbl); |
767 | spin_unlock(&tbl->slot_tbl_lock); | 767 | spin_unlock(&tbl->slot_tbl_lock); |
768 | } | 768 | } |
769 | 769 | ||
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 947b0c908aa9..4cbad5d6b276 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c | |||
@@ -203,7 +203,7 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp, | |||
203 | __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); | 203 | __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); |
204 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I); | 204 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I); |
205 | if (error == -EINVAL) | 205 | if (error == -EINVAL) |
206 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_NULL); | 206 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX); |
207 | if (error < 0) | 207 | if (error < 0) |
208 | goto error; | 208 | goto error; |
209 | 209 | ||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8fbc10054115..4e2fe714d5c2 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -572,7 +572,7 @@ int nfs41_setup_sequence(struct nfs4_session *session, | |||
572 | task->tk_timeout = 0; | 572 | task->tk_timeout = 0; |
573 | 573 | ||
574 | spin_lock(&tbl->slot_tbl_lock); | 574 | spin_lock(&tbl->slot_tbl_lock); |
575 | if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) && | 575 | if (test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state) && |
576 | !args->sa_privileged) { | 576 | !args->sa_privileged) { |
577 | /* The state manager will wait until the slot table is empty */ | 577 | /* The state manager will wait until the slot table is empty */ |
578 | dprintk("%s session is draining\n", __func__); | 578 | dprintk("%s session is draining\n", __func__); |
diff --git a/fs/nfs/nfs4session.c b/fs/nfs/nfs4session.c index ebda5f4a031b..c4e225e4a9af 100644 --- a/fs/nfs/nfs4session.c +++ b/fs/nfs/nfs4session.c | |||
@@ -73,7 +73,7 @@ void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot) | |||
73 | tbl->highest_used_slotid = new_max; | 73 | tbl->highest_used_slotid = new_max; |
74 | else { | 74 | else { |
75 | tbl->highest_used_slotid = NFS4_NO_SLOT; | 75 | tbl->highest_used_slotid = NFS4_NO_SLOT; |
76 | nfs4_session_drain_complete(tbl->session, tbl); | 76 | nfs4_slot_tbl_drain_complete(tbl); |
77 | } | 77 | } |
78 | } | 78 | } |
79 | dprintk("%s: slotid %u highest_used_slotid %d\n", __func__, | 79 | dprintk("%s: slotid %u highest_used_slotid %d\n", __func__, |
@@ -226,7 +226,7 @@ static bool nfs41_assign_slot(struct rpc_task *task, void *pslot) | |||
226 | struct nfs4_slot *slot = pslot; | 226 | struct nfs4_slot *slot = pslot; |
227 | struct nfs4_slot_table *tbl = slot->table; | 227 | struct nfs4_slot_table *tbl = slot->table; |
228 | 228 | ||
229 | if (nfs4_session_draining(tbl->session) && !args->sa_privileged) | 229 | if (nfs4_slot_tbl_draining(tbl) && !args->sa_privileged) |
230 | return false; | 230 | return false; |
231 | slot->generation = tbl->generation; | 231 | slot->generation = tbl->generation; |
232 | args->sa_slot = slot; | 232 | args->sa_slot = slot; |
diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h index 6f3cb39386d4..ff7d9f0f8a65 100644 --- a/fs/nfs/nfs4session.h +++ b/fs/nfs/nfs4session.h | |||
@@ -25,6 +25,10 @@ struct nfs4_slot { | |||
25 | }; | 25 | }; |
26 | 26 | ||
27 | /* Sessions */ | 27 | /* Sessions */ |
28 | enum nfs4_slot_tbl_state { | ||
29 | NFS4_SLOT_TBL_DRAINING, | ||
30 | }; | ||
31 | |||
28 | #define SLOT_TABLE_SZ DIV_ROUND_UP(NFS4_MAX_SLOT_TABLE, 8*sizeof(long)) | 32 | #define SLOT_TABLE_SZ DIV_ROUND_UP(NFS4_MAX_SLOT_TABLE, 8*sizeof(long)) |
29 | struct nfs4_slot_table { | 33 | struct nfs4_slot_table { |
30 | struct nfs4_session *session; /* Parent session */ | 34 | struct nfs4_session *session; /* Parent session */ |
@@ -43,6 +47,7 @@ struct nfs4_slot_table { | |||
43 | unsigned long generation; /* Generation counter for | 47 | unsigned long generation; /* Generation counter for |
44 | target_highest_slotid */ | 48 | target_highest_slotid */ |
45 | struct completion complete; | 49 | struct completion complete; |
50 | unsigned long slot_tbl_state; | ||
46 | }; | 51 | }; |
47 | 52 | ||
48 | /* | 53 | /* |
@@ -68,7 +73,6 @@ struct nfs4_session { | |||
68 | 73 | ||
69 | enum nfs4_session_state { | 74 | enum nfs4_session_state { |
70 | NFS4_SESSION_INITING, | 75 | NFS4_SESSION_INITING, |
71 | NFS4_SESSION_DRAINING, | ||
72 | }; | 76 | }; |
73 | 77 | ||
74 | #if defined(CONFIG_NFS_V4_1) | 78 | #if defined(CONFIG_NFS_V4_1) |
@@ -88,12 +92,11 @@ extern void nfs4_destroy_session(struct nfs4_session *session); | |||
88 | extern int nfs4_init_session(struct nfs_server *server); | 92 | extern int nfs4_init_session(struct nfs_server *server); |
89 | extern int nfs4_init_ds_session(struct nfs_client *, unsigned long); | 93 | extern int nfs4_init_ds_session(struct nfs_client *, unsigned long); |
90 | 94 | ||
91 | extern void nfs4_session_drain_complete(struct nfs4_session *session, | 95 | extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl); |
92 | struct nfs4_slot_table *tbl); | ||
93 | 96 | ||
94 | static inline bool nfs4_session_draining(struct nfs4_session *session) | 97 | static inline bool nfs4_slot_tbl_draining(struct nfs4_slot_table *tbl) |
95 | { | 98 | { |
96 | return !!test_bit(NFS4_SESSION_DRAINING, &session->session_state); | 99 | return !!test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state); |
97 | } | 100 | } |
98 | 101 | ||
99 | bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl, | 102 | bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl, |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 300d17d85c0e..1fab140764c4 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -241,7 +241,7 @@ static void nfs4_end_drain_session(struct nfs_client *clp) | |||
241 | if (ses == NULL) | 241 | if (ses == NULL) |
242 | return; | 242 | return; |
243 | tbl = &ses->fc_slot_table; | 243 | tbl = &ses->fc_slot_table; |
244 | if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { | 244 | if (test_and_clear_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state)) { |
245 | spin_lock(&tbl->slot_tbl_lock); | 245 | spin_lock(&tbl->slot_tbl_lock); |
246 | nfs41_wake_slot_table(tbl); | 246 | nfs41_wake_slot_table(tbl); |
247 | spin_unlock(&tbl->slot_tbl_lock); | 247 | spin_unlock(&tbl->slot_tbl_lock); |
@@ -251,15 +251,15 @@ static void nfs4_end_drain_session(struct nfs_client *clp) | |||
251 | /* | 251 | /* |
252 | * Signal state manager thread if session fore channel is drained | 252 | * Signal state manager thread if session fore channel is drained |
253 | */ | 253 | */ |
254 | void nfs4_session_drain_complete(struct nfs4_session *session, | 254 | void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl) |
255 | struct nfs4_slot_table *tbl) | ||
256 | { | 255 | { |
257 | if (nfs4_session_draining(session)) | 256 | if (nfs4_slot_tbl_draining(tbl)) |
258 | complete(&tbl->complete); | 257 | complete(&tbl->complete); |
259 | } | 258 | } |
260 | 259 | ||
261 | static int nfs4_wait_on_slot_tbl(struct nfs4_slot_table *tbl) | 260 | static int nfs4_drain_slot_tbl(struct nfs4_slot_table *tbl) |
262 | { | 261 | { |
262 | set_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state); | ||
263 | spin_lock(&tbl->slot_tbl_lock); | 263 | spin_lock(&tbl->slot_tbl_lock); |
264 | if (tbl->highest_used_slotid != NFS4_NO_SLOT) { | 264 | if (tbl->highest_used_slotid != NFS4_NO_SLOT) { |
265 | INIT_COMPLETION(tbl->complete); | 265 | INIT_COMPLETION(tbl->complete); |
@@ -275,13 +275,12 @@ static int nfs4_begin_drain_session(struct nfs_client *clp) | |||
275 | struct nfs4_session *ses = clp->cl_session; | 275 | struct nfs4_session *ses = clp->cl_session; |
276 | int ret = 0; | 276 | int ret = 0; |
277 | 277 | ||
278 | set_bit(NFS4_SESSION_DRAINING, &ses->session_state); | ||
279 | /* back channel */ | 278 | /* back channel */ |
280 | ret = nfs4_wait_on_slot_tbl(&ses->bc_slot_table); | 279 | ret = nfs4_drain_slot_tbl(&ses->bc_slot_table); |
281 | if (ret) | 280 | if (ret) |
282 | return ret; | 281 | return ret; |
283 | /* fore channel */ | 282 | /* fore channel */ |
284 | return nfs4_wait_on_slot_tbl(&ses->fc_slot_table); | 283 | return nfs4_drain_slot_tbl(&ses->fc_slot_table); |
285 | } | 284 | } |
286 | 285 | ||
287 | static void nfs41_finish_session_reset(struct nfs_client *clp) | 286 | static void nfs41_finish_session_reset(struct nfs_client *clp) |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 7da6b457f66a..fc2f78d6a9b4 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -52,6 +52,8 @@ | |||
52 | #include <linux/sunrpc/gss_api.h> | 52 | #include <linux/sunrpc/gss_api.h> |
53 | #include <asm/uaccess.h> | 53 | #include <asm/uaccess.h> |
54 | 54 | ||
55 | #include "../netns.h" | ||
56 | |||
55 | static const struct rpc_authops authgss_ops; | 57 | static const struct rpc_authops authgss_ops; |
56 | 58 | ||
57 | static const struct rpc_credops gss_credops; | 59 | static const struct rpc_credops gss_credops; |
@@ -85,8 +87,6 @@ struct gss_auth { | |||
85 | }; | 87 | }; |
86 | 88 | ||
87 | /* pipe_version >= 0 if and only if someone has a pipe open. */ | 89 | /* pipe_version >= 0 if and only if someone has a pipe open. */ |
88 | static int pipe_version = -1; | ||
89 | static atomic_t pipe_users = ATOMIC_INIT(0); | ||
90 | static DEFINE_SPINLOCK(pipe_version_lock); | 90 | static DEFINE_SPINLOCK(pipe_version_lock); |
91 | static struct rpc_wait_queue pipe_version_rpc_waitqueue; | 91 | static struct rpc_wait_queue pipe_version_rpc_waitqueue; |
92 | static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); | 92 | static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); |
@@ -266,24 +266,27 @@ struct gss_upcall_msg { | |||
266 | char databuf[UPCALL_BUF_LEN]; | 266 | char databuf[UPCALL_BUF_LEN]; |
267 | }; | 267 | }; |
268 | 268 | ||
269 | static int get_pipe_version(void) | 269 | static int get_pipe_version(struct net *net) |
270 | { | 270 | { |
271 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
271 | int ret; | 272 | int ret; |
272 | 273 | ||
273 | spin_lock(&pipe_version_lock); | 274 | spin_lock(&pipe_version_lock); |
274 | if (pipe_version >= 0) { | 275 | if (sn->pipe_version >= 0) { |
275 | atomic_inc(&pipe_users); | 276 | atomic_inc(&sn->pipe_users); |
276 | ret = pipe_version; | 277 | ret = sn->pipe_version; |
277 | } else | 278 | } else |
278 | ret = -EAGAIN; | 279 | ret = -EAGAIN; |
279 | spin_unlock(&pipe_version_lock); | 280 | spin_unlock(&pipe_version_lock); |
280 | return ret; | 281 | return ret; |
281 | } | 282 | } |
282 | 283 | ||
283 | static void put_pipe_version(void) | 284 | static void put_pipe_version(struct net *net) |
284 | { | 285 | { |
285 | if (atomic_dec_and_lock(&pipe_users, &pipe_version_lock)) { | 286 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
286 | pipe_version = -1; | 287 | |
288 | if (atomic_dec_and_lock(&sn->pipe_users, &pipe_version_lock)) { | ||
289 | sn->pipe_version = -1; | ||
287 | spin_unlock(&pipe_version_lock); | 290 | spin_unlock(&pipe_version_lock); |
288 | } | 291 | } |
289 | } | 292 | } |
@@ -291,9 +294,10 @@ static void put_pipe_version(void) | |||
291 | static void | 294 | static void |
292 | gss_release_msg(struct gss_upcall_msg *gss_msg) | 295 | gss_release_msg(struct gss_upcall_msg *gss_msg) |
293 | { | 296 | { |
297 | struct net *net = rpc_net_ns(gss_msg->auth->client); | ||
294 | if (!atomic_dec_and_test(&gss_msg->count)) | 298 | if (!atomic_dec_and_test(&gss_msg->count)) |
295 | return; | 299 | return; |
296 | put_pipe_version(); | 300 | put_pipe_version(net); |
297 | BUG_ON(!list_empty(&gss_msg->list)); | 301 | BUG_ON(!list_empty(&gss_msg->list)); |
298 | if (gss_msg->ctx != NULL) | 302 | if (gss_msg->ctx != NULL) |
299 | gss_put_ctx(gss_msg->ctx); | 303 | gss_put_ctx(gss_msg->ctx); |
@@ -439,7 +443,10 @@ static void gss_encode_msg(struct gss_upcall_msg *gss_msg, | |||
439 | struct rpc_clnt *clnt, | 443 | struct rpc_clnt *clnt, |
440 | const char *service_name) | 444 | const char *service_name) |
441 | { | 445 | { |
442 | if (pipe_version == 0) | 446 | struct net *net = rpc_net_ns(clnt); |
447 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
448 | |||
449 | if (sn->pipe_version == 0) | ||
443 | gss_encode_v0_msg(gss_msg); | 450 | gss_encode_v0_msg(gss_msg); |
444 | else /* pipe_version == 1 */ | 451 | else /* pipe_version == 1 */ |
445 | gss_encode_v1_msg(gss_msg, clnt, service_name); | 452 | gss_encode_v1_msg(gss_msg, clnt, service_name); |
@@ -455,7 +462,7 @@ gss_alloc_msg(struct gss_auth *gss_auth, struct rpc_clnt *clnt, | |||
455 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); | 462 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); |
456 | if (gss_msg == NULL) | 463 | if (gss_msg == NULL) |
457 | return ERR_PTR(-ENOMEM); | 464 | return ERR_PTR(-ENOMEM); |
458 | vers = get_pipe_version(); | 465 | vers = get_pipe_version(rpc_net_ns(clnt)); |
459 | if (vers < 0) { | 466 | if (vers < 0) { |
460 | kfree(gss_msg); | 467 | kfree(gss_msg); |
461 | return ERR_PTR(vers); | 468 | return ERR_PTR(vers); |
@@ -559,24 +566,34 @@ out: | |||
559 | static inline int | 566 | static inline int |
560 | gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | 567 | gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) |
561 | { | 568 | { |
569 | struct net *net = rpc_net_ns(gss_auth->client); | ||
570 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
562 | struct rpc_pipe *pipe; | 571 | struct rpc_pipe *pipe; |
563 | struct rpc_cred *cred = &gss_cred->gc_base; | 572 | struct rpc_cred *cred = &gss_cred->gc_base; |
564 | struct gss_upcall_msg *gss_msg; | 573 | struct gss_upcall_msg *gss_msg; |
574 | unsigned long timeout; | ||
565 | DEFINE_WAIT(wait); | 575 | DEFINE_WAIT(wait); |
566 | int err = 0; | 576 | int err; |
567 | 577 | ||
568 | dprintk("RPC: %s for uid %u\n", | 578 | dprintk("RPC: %s for uid %u\n", |
569 | __func__, from_kuid(&init_user_ns, cred->cr_uid)); | 579 | __func__, from_kuid(&init_user_ns, cred->cr_uid)); |
570 | retry: | 580 | retry: |
581 | err = 0; | ||
582 | /* Default timeout is 15s unless we know that gssd is not running */ | ||
583 | timeout = 15 * HZ; | ||
584 | if (!sn->gssd_running) | ||
585 | timeout = HZ >> 2; | ||
571 | gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); | 586 | gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); |
572 | if (PTR_ERR(gss_msg) == -EAGAIN) { | 587 | if (PTR_ERR(gss_msg) == -EAGAIN) { |
573 | err = wait_event_interruptible_timeout(pipe_version_waitqueue, | 588 | err = wait_event_interruptible_timeout(pipe_version_waitqueue, |
574 | pipe_version >= 0, 15*HZ); | 589 | sn->pipe_version >= 0, timeout); |
575 | if (pipe_version < 0) { | 590 | if (sn->pipe_version < 0) { |
591 | if (err == 0) | ||
592 | sn->gssd_running = 0; | ||
576 | warn_gssd(); | 593 | warn_gssd(); |
577 | err = -EACCES; | 594 | err = -EACCES; |
578 | } | 595 | } |
579 | if (err) | 596 | if (err < 0) |
580 | goto out; | 597 | goto out; |
581 | goto retry; | 598 | goto retry; |
582 | } | 599 | } |
@@ -707,20 +724,22 @@ out: | |||
707 | 724 | ||
708 | static int gss_pipe_open(struct inode *inode, int new_version) | 725 | static int gss_pipe_open(struct inode *inode, int new_version) |
709 | { | 726 | { |
727 | struct net *net = inode->i_sb->s_fs_info; | ||
728 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
710 | int ret = 0; | 729 | int ret = 0; |
711 | 730 | ||
712 | spin_lock(&pipe_version_lock); | 731 | spin_lock(&pipe_version_lock); |
713 | if (pipe_version < 0) { | 732 | if (sn->pipe_version < 0) { |
714 | /* First open of any gss pipe determines the version: */ | 733 | /* First open of any gss pipe determines the version: */ |
715 | pipe_version = new_version; | 734 | sn->pipe_version = new_version; |
716 | rpc_wake_up(&pipe_version_rpc_waitqueue); | 735 | rpc_wake_up(&pipe_version_rpc_waitqueue); |
717 | wake_up(&pipe_version_waitqueue); | 736 | wake_up(&pipe_version_waitqueue); |
718 | } else if (pipe_version != new_version) { | 737 | } else if (sn->pipe_version != new_version) { |
719 | /* Trying to open a pipe of a different version */ | 738 | /* Trying to open a pipe of a different version */ |
720 | ret = -EBUSY; | 739 | ret = -EBUSY; |
721 | goto out; | 740 | goto out; |
722 | } | 741 | } |
723 | atomic_inc(&pipe_users); | 742 | atomic_inc(&sn->pipe_users); |
724 | out: | 743 | out: |
725 | spin_unlock(&pipe_version_lock); | 744 | spin_unlock(&pipe_version_lock); |
726 | return ret; | 745 | return ret; |
@@ -740,6 +759,7 @@ static int gss_pipe_open_v1(struct inode *inode) | |||
740 | static void | 759 | static void |
741 | gss_pipe_release(struct inode *inode) | 760 | gss_pipe_release(struct inode *inode) |
742 | { | 761 | { |
762 | struct net *net = inode->i_sb->s_fs_info; | ||
743 | struct rpc_pipe *pipe = RPC_I(inode)->pipe; | 763 | struct rpc_pipe *pipe = RPC_I(inode)->pipe; |
744 | struct gss_upcall_msg *gss_msg; | 764 | struct gss_upcall_msg *gss_msg; |
745 | 765 | ||
@@ -758,7 +778,7 @@ restart: | |||
758 | } | 778 | } |
759 | spin_unlock(&pipe->lock); | 779 | spin_unlock(&pipe->lock); |
760 | 780 | ||
761 | put_pipe_version(); | 781 | put_pipe_version(net); |
762 | } | 782 | } |
763 | 783 | ||
764 | static void | 784 | static void |
diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h index 7111a4c9113b..74d948f5d5a1 100644 --- a/net/sunrpc/netns.h +++ b/net/sunrpc/netns.h | |||
@@ -28,7 +28,11 @@ struct sunrpc_net { | |||
28 | wait_queue_head_t gssp_wq; | 28 | wait_queue_head_t gssp_wq; |
29 | struct rpc_clnt *gssp_clnt; | 29 | struct rpc_clnt *gssp_clnt; |
30 | int use_gss_proxy; | 30 | int use_gss_proxy; |
31 | int pipe_version; | ||
32 | atomic_t pipe_users; | ||
31 | struct proc_dir_entry *use_gssp_proc; | 33 | struct proc_dir_entry *use_gssp_proc; |
34 | |||
35 | unsigned int gssd_running; | ||
32 | }; | 36 | }; |
33 | 37 | ||
34 | extern int sunrpc_net_id; | 38 | extern int sunrpc_net_id; |
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index a9129f8d7070..e7ce4b3eb0bd 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
@@ -216,11 +216,14 @@ rpc_destroy_inode(struct inode *inode) | |||
216 | static int | 216 | static int |
217 | rpc_pipe_open(struct inode *inode, struct file *filp) | 217 | rpc_pipe_open(struct inode *inode, struct file *filp) |
218 | { | 218 | { |
219 | struct net *net = inode->i_sb->s_fs_info; | ||
220 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
219 | struct rpc_pipe *pipe; | 221 | struct rpc_pipe *pipe; |
220 | int first_open; | 222 | int first_open; |
221 | int res = -ENXIO; | 223 | int res = -ENXIO; |
222 | 224 | ||
223 | mutex_lock(&inode->i_mutex); | 225 | mutex_lock(&inode->i_mutex); |
226 | sn->gssd_running = 1; | ||
224 | pipe = RPC_I(inode)->pipe; | 227 | pipe = RPC_I(inode)->pipe; |
225 | if (pipe == NULL) | 228 | if (pipe == NULL) |
226 | goto out; | 229 | goto out; |
@@ -1069,6 +1072,8 @@ void rpc_pipefs_init_net(struct net *net) | |||
1069 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 1072 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
1070 | 1073 | ||
1071 | mutex_init(&sn->pipefs_sb_lock); | 1074 | mutex_init(&sn->pipefs_sb_lock); |
1075 | sn->gssd_running = 1; | ||
1076 | sn->pipe_version = -1; | ||
1072 | } | 1077 | } |
1073 | 1078 | ||
1074 | /* | 1079 | /* |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index f8529fc8e542..5356b120dbf8 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -324,11 +324,17 @@ EXPORT_SYMBOL_GPL(__rpc_wait_for_completion_task); | |||
324 | * Note: If the task is ASYNC, and is being made runnable after sitting on an | 324 | * Note: If the task is ASYNC, and is being made runnable after sitting on an |
325 | * rpc_wait_queue, this must be called with the queue spinlock held to protect | 325 | * rpc_wait_queue, this must be called with the queue spinlock held to protect |
326 | * the wait queue operation. | 326 | * the wait queue operation. |
327 | * Note the ordering of rpc_test_and_set_running() and rpc_clear_queued(), | ||
328 | * which is needed to ensure that __rpc_execute() doesn't loop (due to the | ||
329 | * lockless RPC_IS_QUEUED() test) before we've had a chance to test | ||
330 | * the RPC_TASK_RUNNING flag. | ||
327 | */ | 331 | */ |
328 | static void rpc_make_runnable(struct rpc_task *task) | 332 | static void rpc_make_runnable(struct rpc_task *task) |
329 | { | 333 | { |
334 | bool need_wakeup = !rpc_test_and_set_running(task); | ||
335 | |||
330 | rpc_clear_queued(task); | 336 | rpc_clear_queued(task); |
331 | if (rpc_test_and_set_running(task)) | 337 | if (!need_wakeup) |
332 | return; | 338 | return; |
333 | if (RPC_IS_ASYNC(task)) { | 339 | if (RPC_IS_ASYNC(task)) { |
334 | INIT_WORK(&task->u.tk_work, rpc_async_schedule); | 340 | INIT_WORK(&task->u.tk_work, rpc_async_schedule); |