diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-09-03 00:51:55 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-09-22 23:25:01 -0400 |
commit | 762d4527c2fc19d821a13d9a3455ccc2d4073731 (patch) | |
tree | 8e2f9ad313c1c8faececce38d43e15c9dc94a65c /net/sunrpc/pmap_clnt.c | |
parent | 6b6ca86b77b62b798cf9ca2599036420abce7796 (diff) |
SUNRPC: Fix Oops in pmap_getport_done
There is no guarantee that the parent task still exists when we exit from
the portmapper. Save the xprt instead.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc/pmap_clnt.c')
-rw-r--r-- | net/sunrpc/pmap_clnt.c | 46 |
1 files changed, 22 insertions, 24 deletions
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index f476f4df0f48..c04609d3476a 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c | |||
@@ -30,7 +30,7 @@ struct portmap_args { | |||
30 | u32 pm_vers; | 30 | u32 pm_vers; |
31 | u32 pm_prot; | 31 | u32 pm_prot; |
32 | unsigned short pm_port; | 32 | unsigned short pm_port; |
33 | struct rpc_task * pm_task; | 33 | struct rpc_xprt * pm_xprt; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | static struct rpc_procinfo pmap_procedures[]; | 36 | static struct rpc_procinfo pmap_procedures[]; |
@@ -71,10 +71,10 @@ static const struct rpc_call_ops pmap_getport_ops = { | |||
71 | .rpc_release = pmap_map_release, | 71 | .rpc_release = pmap_map_release, |
72 | }; | 72 | }; |
73 | 73 | ||
74 | static inline void pmap_wake_portmap_waiters(struct rpc_xprt *xprt) | 74 | static inline void pmap_wake_portmap_waiters(struct rpc_xprt *xprt, int status) |
75 | { | 75 | { |
76 | xprt_clear_binding(xprt); | 76 | xprt_clear_binding(xprt); |
77 | rpc_wake_up(&xprt->binding); | 77 | rpc_wake_up_status(&xprt->binding, status); |
78 | } | 78 | } |
79 | 79 | ||
80 | /** | 80 | /** |
@@ -92,6 +92,7 @@ void rpc_getport(struct rpc_task *task) | |||
92 | struct portmap_args *map; | 92 | struct portmap_args *map; |
93 | struct rpc_clnt *pmap_clnt; | 93 | struct rpc_clnt *pmap_clnt; |
94 | struct rpc_task *child; | 94 | struct rpc_task *child; |
95 | int status; | ||
95 | 96 | ||
96 | dprintk("RPC: %4d rpc_getport(%s, %u, %u, %d)\n", | 97 | dprintk("RPC: %4d rpc_getport(%s, %u, %u, %d)\n", |
97 | task->tk_pid, clnt->cl_server, | 98 | task->tk_pid, clnt->cl_server, |
@@ -107,34 +108,30 @@ void rpc_getport(struct rpc_task *task) | |||
107 | } | 108 | } |
108 | 109 | ||
109 | /* Someone else may have bound if we slept */ | 110 | /* Someone else may have bound if we slept */ |
110 | if (xprt_bound(xprt)) { | 111 | status = 0; |
111 | task->tk_status = 0; | 112 | if (xprt_bound(xprt)) |
112 | goto bailout_nofree; | 113 | goto bailout_nofree; |
113 | } | ||
114 | 114 | ||
115 | status = -ENOMEM; | ||
115 | map = pmap_map_alloc(); | 116 | map = pmap_map_alloc(); |
116 | if (!map) { | 117 | if (!map) |
117 | task->tk_status = -ENOMEM; | ||
118 | goto bailout_nofree; | 118 | goto bailout_nofree; |
119 | } | ||
120 | map->pm_prog = clnt->cl_prog; | 119 | map->pm_prog = clnt->cl_prog; |
121 | map->pm_vers = clnt->cl_vers; | 120 | map->pm_vers = clnt->cl_vers; |
122 | map->pm_prot = xprt->prot; | 121 | map->pm_prot = xprt->prot; |
123 | map->pm_port = 0; | 122 | map->pm_port = 0; |
124 | map->pm_task = task; | 123 | map->pm_xprt = xprt_get(xprt); |
125 | 124 | ||
126 | rpc_peeraddr(clnt, (struct sockaddr *) &addr, sizeof(addr)); | 125 | rpc_peeraddr(clnt, (struct sockaddr *) &addr, sizeof(addr)); |
127 | pmap_clnt = pmap_create(clnt->cl_server, &addr, map->pm_prot, 0); | 126 | pmap_clnt = pmap_create(clnt->cl_server, &addr, map->pm_prot, 0); |
128 | if (IS_ERR(pmap_clnt)) { | 127 | status = PTR_ERR(pmap_clnt); |
129 | task->tk_status = PTR_ERR(pmap_clnt); | 128 | if (IS_ERR(pmap_clnt)) |
130 | goto bailout; | 129 | goto bailout; |
131 | } | ||
132 | 130 | ||
131 | status = -EIO; | ||
133 | child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map); | 132 | child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map); |
134 | if (IS_ERR(child)) { | 133 | if (IS_ERR(child)) |
135 | task->tk_status = -EIO; | ||
136 | goto bailout; | 134 | goto bailout; |
137 | } | ||
138 | rpc_release_task(child); | 135 | rpc_release_task(child); |
139 | 136 | ||
140 | rpc_sleep_on(&xprt->binding, task, NULL, NULL); | 137 | rpc_sleep_on(&xprt->binding, task, NULL, NULL); |
@@ -144,8 +141,10 @@ void rpc_getport(struct rpc_task *task) | |||
144 | 141 | ||
145 | bailout: | 142 | bailout: |
146 | pmap_map_free(map); | 143 | pmap_map_free(map); |
144 | xprt_put(xprt); | ||
147 | bailout_nofree: | 145 | bailout_nofree: |
148 | pmap_wake_portmap_waiters(xprt); | 146 | task->tk_status = status; |
147 | pmap_wake_portmap_waiters(xprt, status); | ||
149 | } | 148 | } |
150 | 149 | ||
151 | #ifdef CONFIG_ROOT_NFS | 150 | #ifdef CONFIG_ROOT_NFS |
@@ -201,29 +200,28 @@ int rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int pr | |||
201 | static void pmap_getport_done(struct rpc_task *child, void *data) | 200 | static void pmap_getport_done(struct rpc_task *child, void *data) |
202 | { | 201 | { |
203 | struct portmap_args *map = data; | 202 | struct portmap_args *map = data; |
204 | struct rpc_task *task = map->pm_task; | 203 | struct rpc_xprt *xprt = map->pm_xprt; |
205 | struct rpc_xprt *xprt = task->tk_xprt; | ||
206 | int status = child->tk_status; | 204 | int status = child->tk_status; |
207 | 205 | ||
208 | if (status < 0) { | 206 | if (status < 0) { |
209 | /* Portmapper not available */ | 207 | /* Portmapper not available */ |
210 | xprt->ops->set_port(xprt, 0); | 208 | xprt->ops->set_port(xprt, 0); |
211 | task->tk_status = status; | ||
212 | } else if (map->pm_port == 0) { | 209 | } else if (map->pm_port == 0) { |
213 | /* Requested RPC service wasn't registered */ | 210 | /* Requested RPC service wasn't registered */ |
214 | xprt->ops->set_port(xprt, 0); | 211 | xprt->ops->set_port(xprt, 0); |
215 | task->tk_status = -EACCES; | 212 | status = -EACCES; |
216 | } else { | 213 | } else { |
217 | /* Succeeded */ | 214 | /* Succeeded */ |
218 | xprt->ops->set_port(xprt, map->pm_port); | 215 | xprt->ops->set_port(xprt, map->pm_port); |
219 | xprt_set_bound(xprt); | 216 | xprt_set_bound(xprt); |
220 | task->tk_status = 0; | 217 | status = 0; |
221 | } | 218 | } |
222 | 219 | ||
223 | dprintk("RPC: %4d pmap_getport_done(status %d, port %u)\n", | 220 | dprintk("RPC: %4d pmap_getport_done(status %d, port %u)\n", |
224 | child->tk_pid, child->tk_status, map->pm_port); | 221 | child->tk_pid, status, map->pm_port); |
225 | 222 | ||
226 | pmap_wake_portmap_waiters(xprt); | 223 | pmap_wake_portmap_waiters(xprt, status); |
224 | xprt_put(xprt); | ||
227 | } | 225 | } |
228 | 226 | ||
229 | /** | 227 | /** |