diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-07-07 12:18:53 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-07-09 12:09:45 -0400 |
commit | 381ba74af55e58bca4c01553835a360a9f6fbb07 (patch) | |
tree | 56e5f5159432ebb350af4adf330afa4f50b77a54 | |
parent | f45663ce5fb30f76a3414ab3ac69f4dd320e760a (diff) |
SUNRPC: Ensure our task is notified when an rpcbind call is done
If another task is busy in rpcb_getport_async number, it is more efficient
to have it wake us up when it has finished instead of arbitrarily sleeping
for 5 seconds.
Also ensure that rpcb_wake_rpcbind_waiters() is called regardless of
whether or not rpcb_getport_done() gets called.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | net/sunrpc/clnt.c | 8 | ||||
-rw-r--r-- | net/sunrpc/rpcb_clnt.c | 38 |
2 files changed, 23 insertions, 23 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 09631f6e30e9..76739e928d0d 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -942,11 +942,9 @@ call_bind_status(struct rpc_task *task) | |||
942 | } | 942 | } |
943 | 943 | ||
944 | switch (task->tk_status) { | 944 | switch (task->tk_status) { |
945 | case -EAGAIN: | 945 | case -ENOMEM: |
946 | dprintk("RPC: %5u rpcbind waiting for another request " | 946 | dprintk("RPC: %5u rpcbind out of memory\n", task->tk_pid); |
947 | "to finish\n", task->tk_pid); | 947 | rpc_delay(task, HZ >> 2); |
948 | /* avoid busy-waiting here -- could be a network outage. */ | ||
949 | rpc_delay(task, 5*HZ); | ||
950 | goto retry_timeout; | 948 | goto retry_timeout; |
951 | case -EACCES: | 949 | case -EACCES: |
952 | dprintk("RPC: %5u remote rpcbind: RPC program/version " | 950 | dprintk("RPC: %5u remote rpcbind: RPC program/version " |
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index c62e446723ae..24e93e0a0a22 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
@@ -68,6 +68,7 @@ enum { | |||
68 | #define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING) | 68 | #define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING) |
69 | 69 | ||
70 | static void rpcb_getport_done(struct rpc_task *, void *); | 70 | static void rpcb_getport_done(struct rpc_task *, void *); |
71 | static void rpcb_map_release(void *data); | ||
71 | static struct rpc_program rpcb_program; | 72 | static struct rpc_program rpcb_program; |
72 | 73 | ||
73 | struct rpcbind_args { | 74 | struct rpcbind_args { |
@@ -80,6 +81,8 @@ struct rpcbind_args { | |||
80 | const char * r_netid; | 81 | const char * r_netid; |
81 | const char * r_addr; | 82 | const char * r_addr; |
82 | const char * r_owner; | 83 | const char * r_owner; |
84 | |||
85 | int r_status; | ||
83 | }; | 86 | }; |
84 | 87 | ||
85 | static struct rpc_procinfo rpcb_procedures2[]; | 88 | static struct rpc_procinfo rpcb_procedures2[]; |
@@ -93,14 +96,6 @@ struct rpcb_info { | |||
93 | static struct rpcb_info rpcb_next_version[]; | 96 | static struct rpcb_info rpcb_next_version[]; |
94 | static struct rpcb_info rpcb_next_version6[]; | 97 | static struct rpcb_info rpcb_next_version6[]; |
95 | 98 | ||
96 | static void rpcb_map_release(void *data) | ||
97 | { | ||
98 | struct rpcbind_args *map = data; | ||
99 | |||
100 | xprt_put(map->r_xprt); | ||
101 | kfree(map); | ||
102 | } | ||
103 | |||
104 | static const struct rpc_call_ops rpcb_getport_ops = { | 99 | static const struct rpc_call_ops rpcb_getport_ops = { |
105 | .rpc_call_done = rpcb_getport_done, | 100 | .rpc_call_done = rpcb_getport_done, |
106 | .rpc_release = rpcb_map_release, | 101 | .rpc_release = rpcb_map_release, |
@@ -112,6 +107,15 @@ static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status) | |||
112 | rpc_wake_up_status(&xprt->binding, status); | 107 | rpc_wake_up_status(&xprt->binding, status); |
113 | } | 108 | } |
114 | 109 | ||
110 | static void rpcb_map_release(void *data) | ||
111 | { | ||
112 | struct rpcbind_args *map = data; | ||
113 | |||
114 | rpcb_wake_rpcbind_waiters(map->r_xprt, map->r_status); | ||
115 | xprt_put(map->r_xprt); | ||
116 | kfree(map); | ||
117 | } | ||
118 | |||
115 | static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, | 119 | static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, |
116 | size_t salen, int proto, u32 version, | 120 | size_t salen, int proto, u32 version, |
117 | int privileged) | 121 | int privileged) |
@@ -293,17 +297,16 @@ void rpcb_getport_async(struct rpc_task *task) | |||
293 | /* Autobind on cloned rpc clients is discouraged */ | 297 | /* Autobind on cloned rpc clients is discouraged */ |
294 | BUG_ON(clnt->cl_parent != clnt); | 298 | BUG_ON(clnt->cl_parent != clnt); |
295 | 299 | ||
300 | /* Put self on the wait queue to ensure we get notified if | ||
301 | * some other task is already attempting to bind the port */ | ||
302 | rpc_sleep_on(&xprt->binding, task, NULL); | ||
303 | |||
296 | if (xprt_test_and_set_binding(xprt)) { | 304 | if (xprt_test_and_set_binding(xprt)) { |
297 | status = -EAGAIN; /* tell caller to check again */ | ||
298 | dprintk("RPC: %5u %s: waiting for another binder\n", | 305 | dprintk("RPC: %5u %s: waiting for another binder\n", |
299 | task->tk_pid, __func__); | 306 | task->tk_pid, __func__); |
300 | goto bailout_nowake; | 307 | return; |
301 | } | 308 | } |
302 | 309 | ||
303 | /* Put self on queue before sending rpcbind request, in case | ||
304 | * rpcb_getport_done completes before we return from rpc_run_task */ | ||
305 | rpc_sleep_on(&xprt->binding, task, NULL); | ||
306 | |||
307 | /* Someone else may have bound if we slept */ | 310 | /* Someone else may have bound if we slept */ |
308 | if (xprt_bound(xprt)) { | 311 | if (xprt_bound(xprt)) { |
309 | status = 0; | 312 | status = 0; |
@@ -365,15 +368,15 @@ void rpcb_getport_async(struct rpc_task *task) | |||
365 | map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); | 368 | map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); |
366 | map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR); | 369 | map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR); |
367 | map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */ | 370 | map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */ |
371 | map->r_status = -EIO; | ||
368 | 372 | ||
369 | child = rpcb_call_async(rpcb_clnt, map, proc); | 373 | child = rpcb_call_async(rpcb_clnt, map, proc); |
370 | rpc_release_client(rpcb_clnt); | 374 | rpc_release_client(rpcb_clnt); |
371 | if (IS_ERR(child)) { | 375 | if (IS_ERR(child)) { |
372 | status = -EIO; | ||
373 | /* rpcb_map_release() has freed the arguments */ | 376 | /* rpcb_map_release() has freed the arguments */ |
374 | dprintk("RPC: %5u %s: rpc_run_task failed\n", | 377 | dprintk("RPC: %5u %s: rpc_run_task failed\n", |
375 | task->tk_pid, __func__); | 378 | task->tk_pid, __func__); |
376 | goto bailout_nofree; | 379 | return; |
377 | } | 380 | } |
378 | rpc_put_task(child); | 381 | rpc_put_task(child); |
379 | 382 | ||
@@ -382,7 +385,6 @@ void rpcb_getport_async(struct rpc_task *task) | |||
382 | 385 | ||
383 | bailout_nofree: | 386 | bailout_nofree: |
384 | rpcb_wake_rpcbind_waiters(xprt, status); | 387 | rpcb_wake_rpcbind_waiters(xprt, status); |
385 | bailout_nowake: | ||
386 | task->tk_status = status; | 388 | task->tk_status = status; |
387 | } | 389 | } |
388 | EXPORT_SYMBOL_GPL(rpcb_getport_async); | 390 | EXPORT_SYMBOL_GPL(rpcb_getport_async); |
@@ -421,7 +423,7 @@ static void rpcb_getport_done(struct rpc_task *child, void *data) | |||
421 | dprintk("RPC: %5u rpcb_getport_done(status %d, port %u)\n", | 423 | dprintk("RPC: %5u rpcb_getport_done(status %d, port %u)\n", |
422 | child->tk_pid, status, map->r_port); | 424 | child->tk_pid, status, map->r_port); |
423 | 425 | ||
424 | rpcb_wake_rpcbind_waiters(xprt, status); | 426 | map->r_status = status; |
425 | } | 427 | } |
426 | 428 | ||
427 | static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p, | 429 | static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p, |