diff options
Diffstat (limited to 'net/sunrpc/rpcb_clnt.c')
-rw-r--r-- | net/sunrpc/rpcb_clnt.c | 377 |
1 files changed, 297 insertions, 80 deletions
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 0517967a68bf..24db2b4d12d3 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
@@ -32,6 +32,10 @@ | |||
32 | #define RPCBIND_PROGRAM (100000u) | 32 | #define RPCBIND_PROGRAM (100000u) |
33 | #define RPCBIND_PORT (111u) | 33 | #define RPCBIND_PORT (111u) |
34 | 34 | ||
35 | #define RPCBVERS_2 (2u) | ||
36 | #define RPCBVERS_3 (3u) | ||
37 | #define RPCBVERS_4 (4u) | ||
38 | |||
35 | enum { | 39 | enum { |
36 | RPCBPROC_NULL, | 40 | RPCBPROC_NULL, |
37 | RPCBPROC_SET, | 41 | RPCBPROC_SET, |
@@ -64,6 +68,7 @@ enum { | |||
64 | #define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING) | 68 | #define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING) |
65 | 69 | ||
66 | 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); | ||
67 | static struct rpc_program rpcb_program; | 72 | static struct rpc_program rpcb_program; |
68 | 73 | ||
69 | struct rpcbind_args { | 74 | struct rpcbind_args { |
@@ -76,41 +81,73 @@ struct rpcbind_args { | |||
76 | const char * r_netid; | 81 | const char * r_netid; |
77 | const char * r_addr; | 82 | const char * r_addr; |
78 | const char * r_owner; | 83 | const char * r_owner; |
84 | |||
85 | int r_status; | ||
79 | }; | 86 | }; |
80 | 87 | ||
81 | static struct rpc_procinfo rpcb_procedures2[]; | 88 | static struct rpc_procinfo rpcb_procedures2[]; |
82 | static struct rpc_procinfo rpcb_procedures3[]; | 89 | static struct rpc_procinfo rpcb_procedures3[]; |
90 | static struct rpc_procinfo rpcb_procedures4[]; | ||
83 | 91 | ||
84 | struct rpcb_info { | 92 | struct rpcb_info { |
85 | int rpc_vers; | 93 | u32 rpc_vers; |
86 | struct rpc_procinfo * rpc_proc; | 94 | struct rpc_procinfo * rpc_proc; |
87 | }; | 95 | }; |
88 | 96 | ||
89 | static struct rpcb_info rpcb_next_version[]; | 97 | static struct rpcb_info rpcb_next_version[]; |
90 | static struct rpcb_info rpcb_next_version6[]; | 98 | static struct rpcb_info rpcb_next_version6[]; |
91 | 99 | ||
100 | static const struct rpc_call_ops rpcb_getport_ops = { | ||
101 | .rpc_call_done = rpcb_getport_done, | ||
102 | .rpc_release = rpcb_map_release, | ||
103 | }; | ||
104 | |||
105 | static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status) | ||
106 | { | ||
107 | xprt_clear_binding(xprt); | ||
108 | rpc_wake_up_status(&xprt->binding, status); | ||
109 | } | ||
110 | |||
92 | static void rpcb_map_release(void *data) | 111 | static void rpcb_map_release(void *data) |
93 | { | 112 | { |
94 | struct rpcbind_args *map = data; | 113 | struct rpcbind_args *map = data; |
95 | 114 | ||
115 | rpcb_wake_rpcbind_waiters(map->r_xprt, map->r_status); | ||
96 | xprt_put(map->r_xprt); | 116 | xprt_put(map->r_xprt); |
97 | kfree(map); | 117 | kfree(map); |
98 | } | 118 | } |
99 | 119 | ||
100 | static const struct rpc_call_ops rpcb_getport_ops = { | 120 | static const struct sockaddr_in rpcb_inaddr_loopback = { |
101 | .rpc_call_done = rpcb_getport_done, | 121 | .sin_family = AF_INET, |
102 | .rpc_release = rpcb_map_release, | 122 | .sin_addr.s_addr = htonl(INADDR_LOOPBACK), |
123 | .sin_port = htons(RPCBIND_PORT), | ||
103 | }; | 124 | }; |
104 | 125 | ||
105 | static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status) | 126 | static const struct sockaddr_in6 rpcb_in6addr_loopback = { |
127 | .sin6_family = AF_INET6, | ||
128 | .sin6_addr = IN6ADDR_LOOPBACK_INIT, | ||
129 | .sin6_port = htons(RPCBIND_PORT), | ||
130 | }; | ||
131 | |||
132 | static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr, | ||
133 | size_t addrlen, u32 version) | ||
106 | { | 134 | { |
107 | xprt_clear_binding(xprt); | 135 | struct rpc_create_args args = { |
108 | rpc_wake_up_status(&xprt->binding, status); | 136 | .protocol = XPRT_TRANSPORT_UDP, |
137 | .address = addr, | ||
138 | .addrsize = addrlen, | ||
139 | .servername = "localhost", | ||
140 | .program = &rpcb_program, | ||
141 | .version = version, | ||
142 | .authflavor = RPC_AUTH_UNIX, | ||
143 | .flags = RPC_CLNT_CREATE_NOPING, | ||
144 | }; | ||
145 | |||
146 | return rpc_create(&args); | ||
109 | } | 147 | } |
110 | 148 | ||
111 | static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, | 149 | static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, |
112 | size_t salen, int proto, u32 version, | 150 | size_t salen, int proto, u32 version) |
113 | int privileged) | ||
114 | { | 151 | { |
115 | struct rpc_create_args args = { | 152 | struct rpc_create_args args = { |
116 | .protocol = proto, | 153 | .protocol = proto, |
@@ -120,7 +157,8 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, | |||
120 | .program = &rpcb_program, | 157 | .program = &rpcb_program, |
121 | .version = version, | 158 | .version = version, |
122 | .authflavor = RPC_AUTH_UNIX, | 159 | .authflavor = RPC_AUTH_UNIX, |
123 | .flags = RPC_CLNT_CREATE_NOPING, | 160 | .flags = (RPC_CLNT_CREATE_NOPING | |
161 | RPC_CLNT_CREATE_NONPRIVPORT), | ||
124 | }; | 162 | }; |
125 | 163 | ||
126 | switch (srvaddr->sa_family) { | 164 | switch (srvaddr->sa_family) { |
@@ -134,29 +172,72 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, | |||
134 | return NULL; | 172 | return NULL; |
135 | } | 173 | } |
136 | 174 | ||
137 | if (!privileged) | ||
138 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; | ||
139 | return rpc_create(&args); | 175 | return rpc_create(&args); |
140 | } | 176 | } |
141 | 177 | ||
178 | static int rpcb_register_call(struct sockaddr *addr, size_t addrlen, | ||
179 | u32 version, struct rpc_message *msg, | ||
180 | int *result) | ||
181 | { | ||
182 | struct rpc_clnt *rpcb_clnt; | ||
183 | int error = 0; | ||
184 | |||
185 | *result = 0; | ||
186 | |||
187 | rpcb_clnt = rpcb_create_local(addr, addrlen, version); | ||
188 | if (!IS_ERR(rpcb_clnt)) { | ||
189 | error = rpc_call_sync(rpcb_clnt, msg, 0); | ||
190 | rpc_shutdown_client(rpcb_clnt); | ||
191 | } else | ||
192 | error = PTR_ERR(rpcb_clnt); | ||
193 | |||
194 | if (error < 0) | ||
195 | printk(KERN_WARNING "RPC: failed to contact local rpcbind " | ||
196 | "server (errno %d).\n", -error); | ||
197 | dprintk("RPC: registration status %d/%d\n", error, *result); | ||
198 | |||
199 | return error; | ||
200 | } | ||
201 | |||
142 | /** | 202 | /** |
143 | * rpcb_register - set or unset a port registration with the local rpcbind svc | 203 | * rpcb_register - set or unset a port registration with the local rpcbind svc |
144 | * @prog: RPC program number to bind | 204 | * @prog: RPC program number to bind |
145 | * @vers: RPC version number to bind | 205 | * @vers: RPC version number to bind |
146 | * @prot: transport protocol to use to make this request | 206 | * @prot: transport protocol to register |
147 | * @port: port value to register | 207 | * @port: port value to register |
148 | * @okay: result code | 208 | * @okay: OUT: result code |
209 | * | ||
210 | * RPC services invoke this function to advertise their contact | ||
211 | * information via the system's rpcbind daemon. RPC services | ||
212 | * invoke this function once for each [program, version, transport] | ||
213 | * tuple they wish to advertise. | ||
214 | * | ||
215 | * Callers may also unregister RPC services that are no longer | ||
216 | * available by setting the passed-in port to zero. This removes | ||
217 | * all registered transports for [program, version] from the local | ||
218 | * rpcbind database. | ||
219 | * | ||
220 | * Returns zero if the registration request was dispatched | ||
221 | * successfully and a reply was received. The rpcbind daemon's | ||
222 | * boolean result code is stored in *okay. | ||
223 | * | ||
224 | * Returns an errno value and sets *result to zero if there was | ||
225 | * some problem that prevented the rpcbind request from being | ||
226 | * dispatched, or if the rpcbind daemon did not respond within | ||
227 | * the timeout. | ||
149 | * | 228 | * |
150 | * port == 0 means unregister, port != 0 means register. | 229 | * This function uses rpcbind protocol version 2 to contact the |
230 | * local rpcbind daemon. | ||
151 | * | 231 | * |
152 | * This routine supports only rpcbind version 2. | 232 | * Registration works over both AF_INET and AF_INET6, and services |
233 | * registered via this function are advertised as available for any | ||
234 | * address. If the local rpcbind daemon is listening on AF_INET6, | ||
235 | * services registered via this function will be advertised on | ||
236 | * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6 | ||
237 | * addresses). | ||
153 | */ | 238 | */ |
154 | int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | 239 | int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) |
155 | { | 240 | { |
156 | struct sockaddr_in sin = { | ||
157 | .sin_family = AF_INET, | ||
158 | .sin_addr.s_addr = htonl(INADDR_LOOPBACK), | ||
159 | }; | ||
160 | struct rpcbind_args map = { | 241 | struct rpcbind_args map = { |
161 | .r_prog = prog, | 242 | .r_prog = prog, |
162 | .r_vers = vers, | 243 | .r_vers = vers, |
@@ -164,32 +245,159 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | |||
164 | .r_port = port, | 245 | .r_port = port, |
165 | }; | 246 | }; |
166 | struct rpc_message msg = { | 247 | struct rpc_message msg = { |
167 | .rpc_proc = &rpcb_procedures2[port ? | ||
168 | RPCBPROC_SET : RPCBPROC_UNSET], | ||
169 | .rpc_argp = &map, | 248 | .rpc_argp = &map, |
170 | .rpc_resp = okay, | 249 | .rpc_resp = okay, |
171 | }; | 250 | }; |
172 | struct rpc_clnt *rpcb_clnt; | ||
173 | int error = 0; | ||
174 | 251 | ||
175 | dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " | 252 | dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " |
176 | "rpcbind\n", (port ? "" : "un"), | 253 | "rpcbind\n", (port ? "" : "un"), |
177 | prog, vers, prot, port); | 254 | prog, vers, prot, port); |
178 | 255 | ||
179 | rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin, | 256 | msg.rpc_proc = &rpcb_procedures2[RPCBPROC_UNSET]; |
180 | sizeof(sin), XPRT_TRANSPORT_UDP, 2, 1); | 257 | if (port) |
181 | if (IS_ERR(rpcb_clnt)) | 258 | msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET]; |
182 | return PTR_ERR(rpcb_clnt); | ||
183 | 259 | ||
184 | error = rpc_call_sync(rpcb_clnt, &msg, 0); | 260 | return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback, |
261 | sizeof(rpcb_inaddr_loopback), | ||
262 | RPCBVERS_2, &msg, okay); | ||
263 | } | ||
185 | 264 | ||
186 | rpc_shutdown_client(rpcb_clnt); | 265 | /* |
187 | if (error < 0) | 266 | * Fill in AF_INET family-specific arguments to register |
188 | printk(KERN_WARNING "RPC: failed to contact local rpcbind " | 267 | */ |
189 | "server (errno %d).\n", -error); | 268 | static int rpcb_register_netid4(struct sockaddr_in *address_to_register, |
190 | dprintk("RPC: registration status %d/%d\n", error, *okay); | 269 | struct rpc_message *msg) |
270 | { | ||
271 | struct rpcbind_args *map = msg->rpc_argp; | ||
272 | unsigned short port = ntohs(address_to_register->sin_port); | ||
273 | char buf[32]; | ||
274 | |||
275 | /* Construct AF_INET universal address */ | ||
276 | snprintf(buf, sizeof(buf), | ||
277 | NIPQUAD_FMT".%u.%u", | ||
278 | NIPQUAD(address_to_register->sin_addr.s_addr), | ||
279 | port >> 8, port & 0xff); | ||
280 | map->r_addr = buf; | ||
281 | |||
282 | dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with " | ||
283 | "local rpcbind\n", (port ? "" : "un"), | ||
284 | map->r_prog, map->r_vers, | ||
285 | map->r_addr, map->r_netid); | ||
286 | |||
287 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; | ||
288 | if (port) | ||
289 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; | ||
290 | |||
291 | return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback, | ||
292 | sizeof(rpcb_inaddr_loopback), | ||
293 | RPCBVERS_4, msg, msg->rpc_resp); | ||
294 | } | ||
191 | 295 | ||
192 | return error; | 296 | /* |
297 | * Fill in AF_INET6 family-specific arguments to register | ||
298 | */ | ||
299 | static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register, | ||
300 | struct rpc_message *msg) | ||
301 | { | ||
302 | struct rpcbind_args *map = msg->rpc_argp; | ||
303 | unsigned short port = ntohs(address_to_register->sin6_port); | ||
304 | char buf[64]; | ||
305 | |||
306 | /* Construct AF_INET6 universal address */ | ||
307 | snprintf(buf, sizeof(buf), | ||
308 | NIP6_FMT".%u.%u", | ||
309 | NIP6(address_to_register->sin6_addr), | ||
310 | port >> 8, port & 0xff); | ||
311 | map->r_addr = buf; | ||
312 | |||
313 | dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with " | ||
314 | "local rpcbind\n", (port ? "" : "un"), | ||
315 | map->r_prog, map->r_vers, | ||
316 | map->r_addr, map->r_netid); | ||
317 | |||
318 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; | ||
319 | if (port) | ||
320 | msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; | ||
321 | |||
322 | return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback, | ||
323 | sizeof(rpcb_in6addr_loopback), | ||
324 | RPCBVERS_4, msg, msg->rpc_resp); | ||
325 | } | ||
326 | |||
327 | /** | ||
328 | * rpcb_v4_register - set or unset a port registration with the local rpcbind | ||
329 | * @program: RPC program number of service to (un)register | ||
330 | * @version: RPC version number of service to (un)register | ||
331 | * @address: address family, IP address, and port to (un)register | ||
332 | * @netid: netid of transport protocol to (un)register | ||
333 | * @result: result code from rpcbind RPC call | ||
334 | * | ||
335 | * RPC services invoke this function to advertise their contact | ||
336 | * information via the system's rpcbind daemon. RPC services | ||
337 | * invoke this function once for each [program, version, address, | ||
338 | * netid] tuple they wish to advertise. | ||
339 | * | ||
340 | * Callers may also unregister RPC services that are no longer | ||
341 | * available by setting the port number in the passed-in address | ||
342 | * to zero. Callers pass a netid of "" to unregister all | ||
343 | * transport netids associated with [program, version, address]. | ||
344 | * | ||
345 | * Returns zero if the registration request was dispatched | ||
346 | * successfully and a reply was received. The rpcbind daemon's | ||
347 | * result code is stored in *result. | ||
348 | * | ||
349 | * Returns an errno value and sets *result to zero if there was | ||
350 | * some problem that prevented the rpcbind request from being | ||
351 | * dispatched, or if the rpcbind daemon did not respond within | ||
352 | * the timeout. | ||
353 | * | ||
354 | * This function uses rpcbind protocol version 4 to contact the | ||
355 | * local rpcbind daemon. The local rpcbind daemon must support | ||
356 | * version 4 of the rpcbind protocol in order for these functions | ||
357 | * to register a service successfully. | ||
358 | * | ||
359 | * Supported netids include "udp" and "tcp" for UDP and TCP over | ||
360 | * IPv4, and "udp6" and "tcp6" for UDP and TCP over IPv6, | ||
361 | * respectively. | ||
362 | * | ||
363 | * The contents of @address determine the address family and the | ||
364 | * port to be registered. The usual practice is to pass INADDR_ANY | ||
365 | * as the raw address, but specifying a non-zero address is also | ||
366 | * supported by this API if the caller wishes to advertise an RPC | ||
367 | * service on a specific network interface. | ||
368 | * | ||
369 | * Note that passing in INADDR_ANY does not create the same service | ||
370 | * registration as IN6ADDR_ANY. The former advertises an RPC | ||
371 | * service on any IPv4 address, but not on IPv6. The latter | ||
372 | * advertises the service on all IPv4 and IPv6 addresses. | ||
373 | */ | ||
374 | int rpcb_v4_register(const u32 program, const u32 version, | ||
375 | const struct sockaddr *address, const char *netid, | ||
376 | int *result) | ||
377 | { | ||
378 | struct rpcbind_args map = { | ||
379 | .r_prog = program, | ||
380 | .r_vers = version, | ||
381 | .r_netid = netid, | ||
382 | .r_owner = RPCB_OWNER_STRING, | ||
383 | }; | ||
384 | struct rpc_message msg = { | ||
385 | .rpc_argp = &map, | ||
386 | .rpc_resp = result, | ||
387 | }; | ||
388 | |||
389 | *result = 0; | ||
390 | |||
391 | switch (address->sa_family) { | ||
392 | case AF_INET: | ||
393 | return rpcb_register_netid4((struct sockaddr_in *)address, | ||
394 | &msg); | ||
395 | case AF_INET6: | ||
396 | return rpcb_register_netid6((struct sockaddr_in6 *)address, | ||
397 | &msg); | ||
398 | } | ||
399 | |||
400 | return -EAFNOSUPPORT; | ||
193 | } | 401 | } |
194 | 402 | ||
195 | /** | 403 | /** |
@@ -227,7 +435,7 @@ int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot) | |||
227 | __func__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); | 435 | __func__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); |
228 | 436 | ||
229 | rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin, | 437 | rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin, |
230 | sizeof(*sin), prot, 2, 0); | 438 | sizeof(*sin), prot, RPCBVERS_2); |
231 | if (IS_ERR(rpcb_clnt)) | 439 | if (IS_ERR(rpcb_clnt)) |
232 | return PTR_ERR(rpcb_clnt); | 440 | return PTR_ERR(rpcb_clnt); |
233 | 441 | ||
@@ -243,10 +451,10 @@ int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot) | |||
243 | } | 451 | } |
244 | EXPORT_SYMBOL_GPL(rpcb_getport_sync); | 452 | EXPORT_SYMBOL_GPL(rpcb_getport_sync); |
245 | 453 | ||
246 | static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbind_args *map, int version) | 454 | static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbind_args *map, struct rpc_procinfo *proc) |
247 | { | 455 | { |
248 | struct rpc_message msg = { | 456 | struct rpc_message msg = { |
249 | .rpc_proc = rpcb_next_version[version].rpc_proc, | 457 | .rpc_proc = proc, |
250 | .rpc_argp = map, | 458 | .rpc_argp = map, |
251 | .rpc_resp = &map->r_port, | 459 | .rpc_resp = &map->r_port, |
252 | }; | 460 | }; |
@@ -271,6 +479,7 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi | |||
271 | void rpcb_getport_async(struct rpc_task *task) | 479 | void rpcb_getport_async(struct rpc_task *task) |
272 | { | 480 | { |
273 | struct rpc_clnt *clnt = task->tk_client; | 481 | struct rpc_clnt *clnt = task->tk_client; |
482 | struct rpc_procinfo *proc; | ||
274 | u32 bind_version; | 483 | u32 bind_version; |
275 | struct rpc_xprt *xprt = task->tk_xprt; | 484 | struct rpc_xprt *xprt = task->tk_xprt; |
276 | struct rpc_clnt *rpcb_clnt; | 485 | struct rpc_clnt *rpcb_clnt; |
@@ -280,7 +489,6 @@ void rpcb_getport_async(struct rpc_task *task) | |||
280 | struct sockaddr *sap = (struct sockaddr *)&addr; | 489 | struct sockaddr *sap = (struct sockaddr *)&addr; |
281 | size_t salen; | 490 | size_t salen; |
282 | int status; | 491 | int status; |
283 | struct rpcb_info *info; | ||
284 | 492 | ||
285 | dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", | 493 | dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", |
286 | task->tk_pid, __func__, | 494 | task->tk_pid, __func__, |
@@ -289,17 +497,16 @@ void rpcb_getport_async(struct rpc_task *task) | |||
289 | /* Autobind on cloned rpc clients is discouraged */ | 497 | /* Autobind on cloned rpc clients is discouraged */ |
290 | BUG_ON(clnt->cl_parent != clnt); | 498 | BUG_ON(clnt->cl_parent != clnt); |
291 | 499 | ||
500 | /* Put self on the wait queue to ensure we get notified if | ||
501 | * some other task is already attempting to bind the port */ | ||
502 | rpc_sleep_on(&xprt->binding, task, NULL); | ||
503 | |||
292 | if (xprt_test_and_set_binding(xprt)) { | 504 | if (xprt_test_and_set_binding(xprt)) { |
293 | status = -EAGAIN; /* tell caller to check again */ | ||
294 | dprintk("RPC: %5u %s: waiting for another binder\n", | 505 | dprintk("RPC: %5u %s: waiting for another binder\n", |
295 | task->tk_pid, __func__); | 506 | task->tk_pid, __func__); |
296 | goto bailout_nowake; | 507 | return; |
297 | } | 508 | } |
298 | 509 | ||
299 | /* Put self on queue before sending rpcbind request, in case | ||
300 | * rpcb_getport_done completes before we return from rpc_run_task */ | ||
301 | rpc_sleep_on(&xprt->binding, task, NULL); | ||
302 | |||
303 | /* Someone else may have bound if we slept */ | 510 | /* Someone else may have bound if we slept */ |
304 | if (xprt_bound(xprt)) { | 511 | if (xprt_bound(xprt)) { |
305 | status = 0; | 512 | status = 0; |
@@ -313,10 +520,12 @@ void rpcb_getport_async(struct rpc_task *task) | |||
313 | /* Don't ever use rpcbind v2 for AF_INET6 requests */ | 520 | /* Don't ever use rpcbind v2 for AF_INET6 requests */ |
314 | switch (sap->sa_family) { | 521 | switch (sap->sa_family) { |
315 | case AF_INET: | 522 | case AF_INET: |
316 | info = rpcb_next_version; | 523 | proc = rpcb_next_version[xprt->bind_index].rpc_proc; |
524 | bind_version = rpcb_next_version[xprt->bind_index].rpc_vers; | ||
317 | break; | 525 | break; |
318 | case AF_INET6: | 526 | case AF_INET6: |
319 | info = rpcb_next_version6; | 527 | proc = rpcb_next_version6[xprt->bind_index].rpc_proc; |
528 | bind_version = rpcb_next_version6[xprt->bind_index].rpc_vers; | ||
320 | break; | 529 | break; |
321 | default: | 530 | default: |
322 | status = -EAFNOSUPPORT; | 531 | status = -EAFNOSUPPORT; |
@@ -324,20 +533,19 @@ void rpcb_getport_async(struct rpc_task *task) | |||
324 | task->tk_pid, __func__); | 533 | task->tk_pid, __func__); |
325 | goto bailout_nofree; | 534 | goto bailout_nofree; |
326 | } | 535 | } |
327 | if (info[xprt->bind_index].rpc_proc == NULL) { | 536 | if (proc == NULL) { |
328 | xprt->bind_index = 0; | 537 | xprt->bind_index = 0; |
329 | status = -EPFNOSUPPORT; | 538 | status = -EPFNOSUPPORT; |
330 | dprintk("RPC: %5u %s: no more getport versions available\n", | 539 | dprintk("RPC: %5u %s: no more getport versions available\n", |
331 | task->tk_pid, __func__); | 540 | task->tk_pid, __func__); |
332 | goto bailout_nofree; | 541 | goto bailout_nofree; |
333 | } | 542 | } |
334 | bind_version = info[xprt->bind_index].rpc_vers; | ||
335 | 543 | ||
336 | dprintk("RPC: %5u %s: trying rpcbind version %u\n", | 544 | dprintk("RPC: %5u %s: trying rpcbind version %u\n", |
337 | task->tk_pid, __func__, bind_version); | 545 | task->tk_pid, __func__, bind_version); |
338 | 546 | ||
339 | rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot, | 547 | rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot, |
340 | bind_version, 0); | 548 | bind_version); |
341 | if (IS_ERR(rpcb_clnt)) { | 549 | if (IS_ERR(rpcb_clnt)) { |
342 | status = PTR_ERR(rpcb_clnt); | 550 | status = PTR_ERR(rpcb_clnt); |
343 | dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n", | 551 | dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n", |
@@ -360,26 +568,23 @@ void rpcb_getport_async(struct rpc_task *task) | |||
360 | map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); | 568 | map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); |
361 | map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR); | 569 | map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR); |
362 | map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */ | 570 | map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */ |
571 | map->r_status = -EIO; | ||
363 | 572 | ||
364 | child = rpcb_call_async(rpcb_clnt, map, xprt->bind_index); | 573 | child = rpcb_call_async(rpcb_clnt, map, proc); |
365 | rpc_release_client(rpcb_clnt); | 574 | rpc_release_client(rpcb_clnt); |
366 | if (IS_ERR(child)) { | 575 | if (IS_ERR(child)) { |
367 | status = -EIO; | 576 | /* rpcb_map_release() has freed the arguments */ |
368 | dprintk("RPC: %5u %s: rpc_run_task failed\n", | 577 | dprintk("RPC: %5u %s: rpc_run_task failed\n", |
369 | task->tk_pid, __func__); | 578 | task->tk_pid, __func__); |
370 | goto bailout; | 579 | return; |
371 | } | 580 | } |
372 | rpc_put_task(child); | 581 | rpc_put_task(child); |
373 | 582 | ||
374 | task->tk_xprt->stat.bind_count++; | 583 | task->tk_xprt->stat.bind_count++; |
375 | return; | 584 | return; |
376 | 585 | ||
377 | bailout: | ||
378 | kfree(map); | ||
379 | xprt_put(xprt); | ||
380 | bailout_nofree: | 586 | bailout_nofree: |
381 | rpcb_wake_rpcbind_waiters(xprt, status); | 587 | rpcb_wake_rpcbind_waiters(xprt, status); |
382 | bailout_nowake: | ||
383 | task->tk_status = status; | 588 | task->tk_status = status; |
384 | } | 589 | } |
385 | EXPORT_SYMBOL_GPL(rpcb_getport_async); | 590 | EXPORT_SYMBOL_GPL(rpcb_getport_async); |
@@ -418,9 +623,13 @@ static void rpcb_getport_done(struct rpc_task *child, void *data) | |||
418 | dprintk("RPC: %5u rpcb_getport_done(status %d, port %u)\n", | 623 | dprintk("RPC: %5u rpcb_getport_done(status %d, port %u)\n", |
419 | child->tk_pid, status, map->r_port); | 624 | child->tk_pid, status, map->r_port); |
420 | 625 | ||
421 | rpcb_wake_rpcbind_waiters(xprt, status); | 626 | map->r_status = status; |
422 | } | 627 | } |
423 | 628 | ||
629 | /* | ||
630 | * XDR functions for rpcbind | ||
631 | */ | ||
632 | |||
424 | static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p, | 633 | static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p, |
425 | struct rpcbind_args *rpcb) | 634 | struct rpcbind_args *rpcb) |
426 | { | 635 | { |
@@ -439,7 +648,7 @@ static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p, | |||
439 | unsigned short *portp) | 648 | unsigned short *portp) |
440 | { | 649 | { |
441 | *portp = (unsigned short) ntohl(*p++); | 650 | *portp = (unsigned short) ntohl(*p++); |
442 | dprintk("RPC: rpcb_decode_getport result %u\n", | 651 | dprintk("RPC: rpcb_decode_getport result %u\n", |
443 | *portp); | 652 | *portp); |
444 | return 0; | 653 | return 0; |
445 | } | 654 | } |
@@ -448,8 +657,8 @@ static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p, | |||
448 | unsigned int *boolp) | 657 | unsigned int *boolp) |
449 | { | 658 | { |
450 | *boolp = (unsigned int) ntohl(*p++); | 659 | *boolp = (unsigned int) ntohl(*p++); |
451 | dprintk("RPC: rpcb_decode_set result %u\n", | 660 | dprintk("RPC: rpcb_decode_set: call %s\n", |
452 | *boolp); | 661 | (*boolp ? "succeeded" : "failed")); |
453 | return 0; | 662 | return 0; |
454 | } | 663 | } |
455 | 664 | ||
@@ -572,52 +781,60 @@ out_err: | |||
572 | static struct rpc_procinfo rpcb_procedures2[] = { | 781 | static struct rpc_procinfo rpcb_procedures2[] = { |
573 | PROC(SET, mapping, set), | 782 | PROC(SET, mapping, set), |
574 | PROC(UNSET, mapping, set), | 783 | PROC(UNSET, mapping, set), |
575 | PROC(GETADDR, mapping, getport), | 784 | PROC(GETPORT, mapping, getport), |
576 | }; | 785 | }; |
577 | 786 | ||
578 | static struct rpc_procinfo rpcb_procedures3[] = { | 787 | static struct rpc_procinfo rpcb_procedures3[] = { |
579 | PROC(SET, mapping, set), | 788 | PROC(SET, getaddr, set), |
580 | PROC(UNSET, mapping, set), | 789 | PROC(UNSET, getaddr, set), |
581 | PROC(GETADDR, getaddr, getaddr), | 790 | PROC(GETADDR, getaddr, getaddr), |
582 | }; | 791 | }; |
583 | 792 | ||
584 | static struct rpc_procinfo rpcb_procedures4[] = { | 793 | static struct rpc_procinfo rpcb_procedures4[] = { |
585 | PROC(SET, mapping, set), | 794 | PROC(SET, getaddr, set), |
586 | PROC(UNSET, mapping, set), | 795 | PROC(UNSET, getaddr, set), |
796 | PROC(GETADDR, getaddr, getaddr), | ||
587 | PROC(GETVERSADDR, getaddr, getaddr), | 797 | PROC(GETVERSADDR, getaddr, getaddr), |
588 | }; | 798 | }; |
589 | 799 | ||
590 | static struct rpcb_info rpcb_next_version[] = { | 800 | static struct rpcb_info rpcb_next_version[] = { |
591 | #ifdef CONFIG_SUNRPC_BIND34 | 801 | { |
592 | { 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] }, | 802 | .rpc_vers = RPCBVERS_2, |
593 | { 3, &rpcb_procedures3[RPCBPROC_GETADDR] }, | 803 | .rpc_proc = &rpcb_procedures2[RPCBPROC_GETPORT], |
594 | #endif | 804 | }, |
595 | { 2, &rpcb_procedures2[RPCBPROC_GETPORT] }, | 805 | { |
596 | { 0, NULL }, | 806 | .rpc_proc = NULL, |
807 | }, | ||
597 | }; | 808 | }; |
598 | 809 | ||
599 | static struct rpcb_info rpcb_next_version6[] = { | 810 | static struct rpcb_info rpcb_next_version6[] = { |
600 | #ifdef CONFIG_SUNRPC_BIND34 | 811 | { |
601 | { 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] }, | 812 | .rpc_vers = RPCBVERS_4, |
602 | { 3, &rpcb_procedures3[RPCBPROC_GETADDR] }, | 813 | .rpc_proc = &rpcb_procedures4[RPCBPROC_GETADDR], |
603 | #endif | 814 | }, |
604 | { 0, NULL }, | 815 | { |
816 | .rpc_vers = RPCBVERS_3, | ||
817 | .rpc_proc = &rpcb_procedures3[RPCBPROC_GETADDR], | ||
818 | }, | ||
819 | { | ||
820 | .rpc_proc = NULL, | ||
821 | }, | ||
605 | }; | 822 | }; |
606 | 823 | ||
607 | static struct rpc_version rpcb_version2 = { | 824 | static struct rpc_version rpcb_version2 = { |
608 | .number = 2, | 825 | .number = RPCBVERS_2, |
609 | .nrprocs = RPCB_HIGHPROC_2, | 826 | .nrprocs = RPCB_HIGHPROC_2, |
610 | .procs = rpcb_procedures2 | 827 | .procs = rpcb_procedures2 |
611 | }; | 828 | }; |
612 | 829 | ||
613 | static struct rpc_version rpcb_version3 = { | 830 | static struct rpc_version rpcb_version3 = { |
614 | .number = 3, | 831 | .number = RPCBVERS_3, |
615 | .nrprocs = RPCB_HIGHPROC_3, | 832 | .nrprocs = RPCB_HIGHPROC_3, |
616 | .procs = rpcb_procedures3 | 833 | .procs = rpcb_procedures3 |
617 | }; | 834 | }; |
618 | 835 | ||
619 | static struct rpc_version rpcb_version4 = { | 836 | static struct rpc_version rpcb_version4 = { |
620 | .number = 4, | 837 | .number = RPCBVERS_4, |
621 | .nrprocs = RPCB_HIGHPROC_4, | 838 | .nrprocs = RPCB_HIGHPROC_4, |
622 | .procs = rpcb_procedures4 | 839 | .procs = rpcb_procedures4 |
623 | }; | 840 | }; |