aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-09-03 00:51:55 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-09-22 23:25:01 -0400
commit762d4527c2fc19d821a13d9a3455ccc2d4073731 (patch)
tree8e2f9ad313c1c8faececce38d43e15c9dc94a65c /net
parent6b6ca86b77b62b798cf9ca2599036420abce7796 (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')
-rw-r--r--net/sunrpc/pmap_clnt.c46
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
36static struct rpc_procinfo pmap_procedures[]; 36static 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
74static inline void pmap_wake_portmap_waiters(struct rpc_xprt *xprt) 74static 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
145bailout: 142bailout:
146 pmap_map_free(map); 143 pmap_map_free(map);
144 xprt_put(xprt);
147bailout_nofree: 145bailout_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
201static void pmap_getport_done(struct rpc_task *child, void *data) 200static 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/**