diff options
author | Jeff Garzik <jgarzik@pretzel.yyz.us> | 2005-06-26 23:38:58 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-06-26 23:38:58 -0400 |
commit | 5696c1944a33b4434a9a1ebb6383b906afd43a10 (patch) | |
tree | 16fbe6ba431bcf949ee8645510b0c2fd39b5810f /net/sunrpc/clnt.c | |
parent | 66b04a80eea60cabf9d89fd34deb3234a740052f (diff) | |
parent | 020f46a39eb7b99a575b9f4d105fce2b142acdf1 (diff) |
Merge /spare/repo/linux-2.6/
Diffstat (limited to 'net/sunrpc/clnt.c')
-rw-r--r-- | net/sunrpc/clnt.c | 205 |
1 files changed, 157 insertions, 48 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 02bc029d46fe..f17e6153b688 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -97,12 +97,13 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) | |||
97 | * made to sleep too long. | 97 | * made to sleep too long. |
98 | */ | 98 | */ |
99 | struct rpc_clnt * | 99 | struct rpc_clnt * |
100 | rpc_create_client(struct rpc_xprt *xprt, char *servname, | 100 | rpc_new_client(struct rpc_xprt *xprt, char *servname, |
101 | struct rpc_program *program, u32 vers, | 101 | struct rpc_program *program, u32 vers, |
102 | rpc_authflavor_t flavor) | 102 | rpc_authflavor_t flavor) |
103 | { | 103 | { |
104 | struct rpc_version *version; | 104 | struct rpc_version *version; |
105 | struct rpc_clnt *clnt = NULL; | 105 | struct rpc_clnt *clnt = NULL; |
106 | struct rpc_auth *auth; | ||
106 | int err; | 107 | int err; |
107 | int len; | 108 | int len; |
108 | 109 | ||
@@ -157,10 +158,11 @@ rpc_create_client(struct rpc_xprt *xprt, char *servname, | |||
157 | if (err < 0) | 158 | if (err < 0) |
158 | goto out_no_path; | 159 | goto out_no_path; |
159 | 160 | ||
160 | err = -ENOMEM; | 161 | auth = rpcauth_create(flavor, clnt); |
161 | if (!rpcauth_create(flavor, clnt)) { | 162 | if (IS_ERR(auth)) { |
162 | printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n", | 163 | printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n", |
163 | flavor); | 164 | flavor); |
165 | err = PTR_ERR(auth); | ||
164 | goto out_no_auth; | 166 | goto out_no_auth; |
165 | } | 167 | } |
166 | 168 | ||
@@ -178,6 +180,37 @@ out_no_path: | |||
178 | kfree(clnt->cl_server); | 180 | kfree(clnt->cl_server); |
179 | kfree(clnt); | 181 | kfree(clnt); |
180 | out_err: | 182 | out_err: |
183 | xprt_destroy(xprt); | ||
184 | return ERR_PTR(err); | ||
185 | } | ||
186 | |||
187 | /** | ||
188 | * Create an RPC client | ||
189 | * @xprt - pointer to xprt struct | ||
190 | * @servname - name of server | ||
191 | * @info - rpc_program | ||
192 | * @version - rpc_program version | ||
193 | * @authflavor - rpc_auth flavour to use | ||
194 | * | ||
195 | * Creates an RPC client structure, then pings the server in order to | ||
196 | * determine if it is up, and if it supports this program and version. | ||
197 | * | ||
198 | * This function should never be called by asynchronous tasks such as | ||
199 | * the portmapper. | ||
200 | */ | ||
201 | struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname, | ||
202 | struct rpc_program *info, u32 version, rpc_authflavor_t authflavor) | ||
203 | { | ||
204 | struct rpc_clnt *clnt; | ||
205 | int err; | ||
206 | |||
207 | clnt = rpc_new_client(xprt, servname, info, version, authflavor); | ||
208 | if (IS_ERR(clnt)) | ||
209 | return clnt; | ||
210 | err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR); | ||
211 | if (err == 0) | ||
212 | return clnt; | ||
213 | rpc_shutdown_client(clnt); | ||
181 | return ERR_PTR(err); | 214 | return ERR_PTR(err); |
182 | } | 215 | } |
183 | 216 | ||
@@ -208,6 +241,8 @@ rpc_clone_client(struct rpc_clnt *clnt) | |||
208 | rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); | 241 | rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); |
209 | if (new->cl_auth) | 242 | if (new->cl_auth) |
210 | atomic_inc(&new->cl_auth->au_count); | 243 | atomic_inc(&new->cl_auth->au_count); |
244 | new->cl_pmap = &new->cl_pmap_default; | ||
245 | rpc_init_wait_queue(&new->cl_pmap_default.pm_bindwait, "bindwait"); | ||
211 | return new; | 246 | return new; |
212 | out_no_clnt: | 247 | out_no_clnt: |
213 | printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__); | 248 | printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__); |
@@ -296,6 +331,44 @@ rpc_release_client(struct rpc_clnt *clnt) | |||
296 | rpc_destroy_client(clnt); | 331 | rpc_destroy_client(clnt); |
297 | } | 332 | } |
298 | 333 | ||
334 | /** | ||
335 | * rpc_bind_new_program - bind a new RPC program to an existing client | ||
336 | * @old - old rpc_client | ||
337 | * @program - rpc program to set | ||
338 | * @vers - rpc program version | ||
339 | * | ||
340 | * Clones the rpc client and sets up a new RPC program. This is mainly | ||
341 | * of use for enabling different RPC programs to share the same transport. | ||
342 | * The Sun NFSv2/v3 ACL protocol can do this. | ||
343 | */ | ||
344 | struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old, | ||
345 | struct rpc_program *program, | ||
346 | int vers) | ||
347 | { | ||
348 | struct rpc_clnt *clnt; | ||
349 | struct rpc_version *version; | ||
350 | int err; | ||
351 | |||
352 | BUG_ON(vers >= program->nrvers || !program->version[vers]); | ||
353 | version = program->version[vers]; | ||
354 | clnt = rpc_clone_client(old); | ||
355 | if (IS_ERR(clnt)) | ||
356 | goto out; | ||
357 | clnt->cl_procinfo = version->procs; | ||
358 | clnt->cl_maxproc = version->nrprocs; | ||
359 | clnt->cl_protname = program->name; | ||
360 | clnt->cl_prog = program->number; | ||
361 | clnt->cl_vers = version->number; | ||
362 | clnt->cl_stats = program->stats; | ||
363 | err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR); | ||
364 | if (err != 0) { | ||
365 | rpc_shutdown_client(clnt); | ||
366 | clnt = ERR_PTR(err); | ||
367 | } | ||
368 | out: | ||
369 | return clnt; | ||
370 | } | ||
371 | |||
299 | /* | 372 | /* |
300 | * Default callback for async RPC calls | 373 | * Default callback for async RPC calls |
301 | */ | 374 | */ |
@@ -305,38 +378,41 @@ rpc_default_callback(struct rpc_task *task) | |||
305 | } | 378 | } |
306 | 379 | ||
307 | /* | 380 | /* |
308 | * Export the signal mask handling for aysnchronous code that | 381 | * Export the signal mask handling for synchronous code that |
309 | * sleeps on RPC calls | 382 | * sleeps on RPC calls |
310 | */ | 383 | */ |
384 | #define RPC_INTR_SIGNALS (sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGKILL)) | ||
311 | 385 | ||
386 | static void rpc_save_sigmask(sigset_t *oldset, int intr) | ||
387 | { | ||
388 | unsigned long sigallow = 0; | ||
389 | sigset_t sigmask; | ||
390 | |||
391 | /* Block all signals except those listed in sigallow */ | ||
392 | if (intr) | ||
393 | sigallow |= RPC_INTR_SIGNALS; | ||
394 | siginitsetinv(&sigmask, sigallow); | ||
395 | sigprocmask(SIG_BLOCK, &sigmask, oldset); | ||
396 | } | ||
397 | |||
398 | static inline void rpc_task_sigmask(struct rpc_task *task, sigset_t *oldset) | ||
399 | { | ||
400 | rpc_save_sigmask(oldset, !RPC_TASK_UNINTERRUPTIBLE(task)); | ||
401 | } | ||
402 | |||
403 | static inline void rpc_restore_sigmask(sigset_t *oldset) | ||
404 | { | ||
405 | sigprocmask(SIG_SETMASK, oldset, NULL); | ||
406 | } | ||
407 | |||
312 | void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset) | 408 | void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset) |
313 | { | 409 | { |
314 | unsigned long sigallow = sigmask(SIGKILL); | 410 | rpc_save_sigmask(oldset, clnt->cl_intr); |
315 | unsigned long irqflags; | ||
316 | |||
317 | /* Turn off various signals */ | ||
318 | if (clnt->cl_intr) { | ||
319 | struct k_sigaction *action = current->sighand->action; | ||
320 | if (action[SIGINT-1].sa.sa_handler == SIG_DFL) | ||
321 | sigallow |= sigmask(SIGINT); | ||
322 | if (action[SIGQUIT-1].sa.sa_handler == SIG_DFL) | ||
323 | sigallow |= sigmask(SIGQUIT); | ||
324 | } | ||
325 | spin_lock_irqsave(¤t->sighand->siglock, irqflags); | ||
326 | *oldset = current->blocked; | ||
327 | siginitsetinv(¤t->blocked, sigallow & ~oldset->sig[0]); | ||
328 | recalc_sigpending(); | ||
329 | spin_unlock_irqrestore(¤t->sighand->siglock, irqflags); | ||
330 | } | 411 | } |
331 | 412 | ||
332 | void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset) | 413 | void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset) |
333 | { | 414 | { |
334 | unsigned long irqflags; | 415 | rpc_restore_sigmask(oldset); |
335 | |||
336 | spin_lock_irqsave(¤t->sighand->siglock, irqflags); | ||
337 | current->blocked = *oldset; | ||
338 | recalc_sigpending(); | ||
339 | spin_unlock_irqrestore(¤t->sighand->siglock, irqflags); | ||
340 | } | 416 | } |
341 | 417 | ||
342 | /* | 418 | /* |
@@ -354,26 +430,26 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) | |||
354 | 430 | ||
355 | BUG_ON(flags & RPC_TASK_ASYNC); | 431 | BUG_ON(flags & RPC_TASK_ASYNC); |
356 | 432 | ||
357 | rpc_clnt_sigmask(clnt, &oldset); | ||
358 | |||
359 | status = -ENOMEM; | 433 | status = -ENOMEM; |
360 | task = rpc_new_task(clnt, NULL, flags); | 434 | task = rpc_new_task(clnt, NULL, flags); |
361 | if (task == NULL) | 435 | if (task == NULL) |
362 | goto out; | 436 | goto out; |
363 | 437 | ||
438 | /* Mask signals on RPC calls _and_ GSS_AUTH upcalls */ | ||
439 | rpc_task_sigmask(task, &oldset); | ||
440 | |||
364 | rpc_call_setup(task, msg, 0); | 441 | rpc_call_setup(task, msg, 0); |
365 | 442 | ||
366 | /* Set up the call info struct and execute the task */ | 443 | /* Set up the call info struct and execute the task */ |
367 | if (task->tk_status == 0) | 444 | if (task->tk_status == 0) { |
368 | status = rpc_execute(task); | 445 | status = rpc_execute(task); |
369 | else { | 446 | } else { |
370 | status = task->tk_status; | 447 | status = task->tk_status; |
371 | rpc_release_task(task); | 448 | rpc_release_task(task); |
372 | } | 449 | } |
373 | 450 | ||
451 | rpc_restore_sigmask(&oldset); | ||
374 | out: | 452 | out: |
375 | rpc_clnt_sigunmask(clnt, &oldset); | ||
376 | |||
377 | return status; | 453 | return status; |
378 | } | 454 | } |
379 | 455 | ||
@@ -394,8 +470,6 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, | |||
394 | 470 | ||
395 | flags |= RPC_TASK_ASYNC; | 471 | flags |= RPC_TASK_ASYNC; |
396 | 472 | ||
397 | rpc_clnt_sigmask(clnt, &oldset); | ||
398 | |||
399 | /* Create/initialize a new RPC task */ | 473 | /* Create/initialize a new RPC task */ |
400 | if (!callback) | 474 | if (!callback) |
401 | callback = rpc_default_callback; | 475 | callback = rpc_default_callback; |
@@ -404,6 +478,9 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, | |||
404 | goto out; | 478 | goto out; |
405 | task->tk_calldata = data; | 479 | task->tk_calldata = data; |
406 | 480 | ||
481 | /* Mask signals on GSS_AUTH upcalls */ | ||
482 | rpc_task_sigmask(task, &oldset); | ||
483 | |||
407 | rpc_call_setup(task, msg, 0); | 484 | rpc_call_setup(task, msg, 0); |
408 | 485 | ||
409 | /* Set up the call info struct and execute the task */ | 486 | /* Set up the call info struct and execute the task */ |
@@ -413,9 +490,8 @@ rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, | |||
413 | else | 490 | else |
414 | rpc_release_task(task); | 491 | rpc_release_task(task); |
415 | 492 | ||
493 | rpc_restore_sigmask(&oldset); | ||
416 | out: | 494 | out: |
417 | rpc_clnt_sigunmask(clnt, &oldset); | ||
418 | |||
419 | return status; | 495 | return status; |
420 | } | 496 | } |
421 | 497 | ||
@@ -593,7 +669,7 @@ call_allocate(struct rpc_task *task) | |||
593 | return; | 669 | return; |
594 | printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task); | 670 | printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task); |
595 | 671 | ||
596 | if (RPC_IS_ASYNC(task) || !(task->tk_client->cl_intr && signalled())) { | 672 | if (RPC_IS_ASYNC(task) || !signalled()) { |
597 | xprt_release(task); | 673 | xprt_release(task); |
598 | task->tk_action = call_reserve; | 674 | task->tk_action = call_reserve; |
599 | rpc_delay(task, HZ>>4); | 675 | rpc_delay(task, HZ>>4); |
@@ -957,7 +1033,9 @@ call_header(struct rpc_task *task) | |||
957 | *p++ = htonl(clnt->cl_prog); /* program number */ | 1033 | *p++ = htonl(clnt->cl_prog); /* program number */ |
958 | *p++ = htonl(clnt->cl_vers); /* program version */ | 1034 | *p++ = htonl(clnt->cl_vers); /* program version */ |
959 | *p++ = htonl(task->tk_msg.rpc_proc->p_proc); /* procedure */ | 1035 | *p++ = htonl(task->tk_msg.rpc_proc->p_proc); /* procedure */ |
960 | return rpcauth_marshcred(task, p); | 1036 | p = rpcauth_marshcred(task, p); |
1037 | req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p); | ||
1038 | return p; | ||
961 | } | 1039 | } |
962 | 1040 | ||
963 | /* | 1041 | /* |
@@ -986,10 +1064,11 @@ call_verify(struct rpc_task *task) | |||
986 | case RPC_AUTH_ERROR: | 1064 | case RPC_AUTH_ERROR: |
987 | break; | 1065 | break; |
988 | case RPC_MISMATCH: | 1066 | case RPC_MISMATCH: |
989 | printk(KERN_WARNING "%s: RPC call version mismatch!\n", __FUNCTION__); | 1067 | dprintk("%s: RPC call version mismatch!\n", __FUNCTION__); |
990 | goto out_eio; | 1068 | error = -EPROTONOSUPPORT; |
1069 | goto out_err; | ||
991 | default: | 1070 | default: |
992 | printk(KERN_WARNING "%s: RPC call rejected, unknown error: %x\n", __FUNCTION__, n); | 1071 | dprintk("%s: RPC call rejected, unknown error: %x\n", __FUNCTION__, n); |
993 | goto out_eio; | 1072 | goto out_eio; |
994 | } | 1073 | } |
995 | if (--len < 0) | 1074 | if (--len < 0) |
@@ -1040,23 +1119,26 @@ call_verify(struct rpc_task *task) | |||
1040 | case RPC_SUCCESS: | 1119 | case RPC_SUCCESS: |
1041 | return p; | 1120 | return p; |
1042 | case RPC_PROG_UNAVAIL: | 1121 | case RPC_PROG_UNAVAIL: |
1043 | printk(KERN_WARNING "RPC: call_verify: program %u is unsupported by server %s\n", | 1122 | dprintk("RPC: call_verify: program %u is unsupported by server %s\n", |
1044 | (unsigned int)task->tk_client->cl_prog, | 1123 | (unsigned int)task->tk_client->cl_prog, |
1045 | task->tk_client->cl_server); | 1124 | task->tk_client->cl_server); |
1046 | goto out_eio; | 1125 | error = -EPFNOSUPPORT; |
1126 | goto out_err; | ||
1047 | case RPC_PROG_MISMATCH: | 1127 | case RPC_PROG_MISMATCH: |
1048 | printk(KERN_WARNING "RPC: call_verify: program %u, version %u unsupported by server %s\n", | 1128 | dprintk("RPC: call_verify: program %u, version %u unsupported by server %s\n", |
1049 | (unsigned int)task->tk_client->cl_prog, | 1129 | (unsigned int)task->tk_client->cl_prog, |
1050 | (unsigned int)task->tk_client->cl_vers, | 1130 | (unsigned int)task->tk_client->cl_vers, |
1051 | task->tk_client->cl_server); | 1131 | task->tk_client->cl_server); |
1052 | goto out_eio; | 1132 | error = -EPROTONOSUPPORT; |
1133 | goto out_err; | ||
1053 | case RPC_PROC_UNAVAIL: | 1134 | case RPC_PROC_UNAVAIL: |
1054 | printk(KERN_WARNING "RPC: call_verify: proc %p unsupported by program %u, version %u on server %s\n", | 1135 | dprintk("RPC: call_verify: proc %p unsupported by program %u, version %u on server %s\n", |
1055 | task->tk_msg.rpc_proc, | 1136 | task->tk_msg.rpc_proc, |
1056 | task->tk_client->cl_prog, | 1137 | task->tk_client->cl_prog, |
1057 | task->tk_client->cl_vers, | 1138 | task->tk_client->cl_vers, |
1058 | task->tk_client->cl_server); | 1139 | task->tk_client->cl_server); |
1059 | goto out_eio; | 1140 | error = -EOPNOTSUPP; |
1141 | goto out_err; | ||
1060 | case RPC_GARBAGE_ARGS: | 1142 | case RPC_GARBAGE_ARGS: |
1061 | dprintk("RPC: %4d %s: server saw garbage\n", task->tk_pid, __FUNCTION__); | 1143 | dprintk("RPC: %4d %s: server saw garbage\n", task->tk_pid, __FUNCTION__); |
1062 | break; /* retry */ | 1144 | break; /* retry */ |
@@ -1069,7 +1151,7 @@ out_retry: | |||
1069 | task->tk_client->cl_stats->rpcgarbage++; | 1151 | task->tk_client->cl_stats->rpcgarbage++; |
1070 | if (task->tk_garb_retry) { | 1152 | if (task->tk_garb_retry) { |
1071 | task->tk_garb_retry--; | 1153 | task->tk_garb_retry--; |
1072 | dprintk(KERN_WARNING "RPC %s: retrying %4d\n", __FUNCTION__, task->tk_pid); | 1154 | dprintk("RPC %s: retrying %4d\n", __FUNCTION__, task->tk_pid); |
1073 | task->tk_action = call_bind; | 1155 | task->tk_action = call_bind; |
1074 | return NULL; | 1156 | return NULL; |
1075 | } | 1157 | } |
@@ -1083,3 +1165,30 @@ out_overflow: | |||
1083 | printk(KERN_WARNING "RPC %s: server reply was truncated.\n", __FUNCTION__); | 1165 | printk(KERN_WARNING "RPC %s: server reply was truncated.\n", __FUNCTION__); |
1084 | goto out_retry; | 1166 | goto out_retry; |
1085 | } | 1167 | } |
1168 | |||
1169 | static int rpcproc_encode_null(void *rqstp, u32 *data, void *obj) | ||
1170 | { | ||
1171 | return 0; | ||
1172 | } | ||
1173 | |||
1174 | static int rpcproc_decode_null(void *rqstp, u32 *data, void *obj) | ||
1175 | { | ||
1176 | return 0; | ||
1177 | } | ||
1178 | |||
1179 | static struct rpc_procinfo rpcproc_null = { | ||
1180 | .p_encode = rpcproc_encode_null, | ||
1181 | .p_decode = rpcproc_decode_null, | ||
1182 | }; | ||
1183 | |||
1184 | int rpc_ping(struct rpc_clnt *clnt, int flags) | ||
1185 | { | ||
1186 | struct rpc_message msg = { | ||
1187 | .rpc_proc = &rpcproc_null, | ||
1188 | }; | ||
1189 | int err; | ||
1190 | msg.rpc_cred = authnull_ops.lookup_cred(NULL, NULL, 0); | ||
1191 | err = rpc_call_sync(clnt, &msg, flags); | ||
1192 | put_rpccred(msg.rpc_cred); | ||
1193 | return err; | ||
1194 | } | ||