diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/auth.c | 6 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 18 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 205 | ||||
-rw-r--r-- | net/sunrpc/pmap_clnt.c | 9 | ||||
-rw-r--r-- | net/sunrpc/sched.c | 84 | ||||
-rw-r--r-- | net/sunrpc/sunrpc_syms.c | 6 | ||||
-rw-r--r-- | net/sunrpc/svc.c | 36 | ||||
-rw-r--r-- | net/sunrpc/xdr.c | 298 | ||||
-rw-r--r-- | net/sunrpc/xprt.c | 71 |
9 files changed, 593 insertions, 140 deletions
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 9bcec9b927b9..505e2d4b3d62 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -66,10 +66,10 @@ rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) | |||
66 | u32 flavor = pseudoflavor_to_flavor(pseudoflavor); | 66 | u32 flavor = pseudoflavor_to_flavor(pseudoflavor); |
67 | 67 | ||
68 | if (flavor >= RPC_AUTH_MAXFLAVOR || !(ops = auth_flavors[flavor])) | 68 | if (flavor >= RPC_AUTH_MAXFLAVOR || !(ops = auth_flavors[flavor])) |
69 | return NULL; | 69 | return ERR_PTR(-EINVAL); |
70 | auth = ops->create(clnt, pseudoflavor); | 70 | auth = ops->create(clnt, pseudoflavor); |
71 | if (!auth) | 71 | if (IS_ERR(auth)) |
72 | return NULL; | 72 | return auth; |
73 | if (clnt->cl_auth) | 73 | if (clnt->cl_auth) |
74 | rpcauth_destroy(clnt->cl_auth); | 74 | rpcauth_destroy(clnt->cl_auth); |
75 | clnt->cl_auth = auth; | 75 | clnt->cl_auth = auth; |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index a33b627cbef4..2f7b867161d2 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -660,14 +660,16 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |||
660 | { | 660 | { |
661 | struct gss_auth *gss_auth; | 661 | struct gss_auth *gss_auth; |
662 | struct rpc_auth * auth; | 662 | struct rpc_auth * auth; |
663 | int err = -ENOMEM; /* XXX? */ | ||
663 | 664 | ||
664 | dprintk("RPC: creating GSS authenticator for client %p\n",clnt); | 665 | dprintk("RPC: creating GSS authenticator for client %p\n",clnt); |
665 | 666 | ||
666 | if (!try_module_get(THIS_MODULE)) | 667 | if (!try_module_get(THIS_MODULE)) |
667 | return NULL; | 668 | return ERR_PTR(err); |
668 | if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL))) | 669 | if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL))) |
669 | goto out_dec; | 670 | goto out_dec; |
670 | gss_auth->client = clnt; | 671 | gss_auth->client = clnt; |
672 | err = -EINVAL; | ||
671 | gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor); | 673 | gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor); |
672 | if (!gss_auth->mech) { | 674 | if (!gss_auth->mech) { |
673 | printk(KERN_WARNING "%s: Pseudoflavor %d not found!", | 675 | printk(KERN_WARNING "%s: Pseudoflavor %d not found!", |
@@ -675,9 +677,8 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |||
675 | goto err_free; | 677 | goto err_free; |
676 | } | 678 | } |
677 | gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor); | 679 | gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor); |
678 | /* FIXME: Will go away once privacy support is merged in */ | 680 | if (gss_auth->service == 0) |
679 | if (gss_auth->service == RPC_GSS_SVC_PRIVACY) | 681 | goto err_put_mech; |
680 | gss_auth->service = RPC_GSS_SVC_INTEGRITY; | ||
681 | INIT_LIST_HEAD(&gss_auth->upcalls); | 682 | INIT_LIST_HEAD(&gss_auth->upcalls); |
682 | spin_lock_init(&gss_auth->lock); | 683 | spin_lock_init(&gss_auth->lock); |
683 | auth = &gss_auth->rpc_auth; | 684 | auth = &gss_auth->rpc_auth; |
@@ -687,15 +688,18 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |||
687 | auth->au_flavor = flavor; | 688 | auth->au_flavor = flavor; |
688 | atomic_set(&auth->au_count, 1); | 689 | atomic_set(&auth->au_count, 1); |
689 | 690 | ||
690 | if (rpcauth_init_credcache(auth, GSS_CRED_EXPIRE) < 0) | 691 | err = rpcauth_init_credcache(auth, GSS_CRED_EXPIRE); |
692 | if (err) | ||
691 | goto err_put_mech; | 693 | goto err_put_mech; |
692 | 694 | ||
693 | snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s", | 695 | snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s", |
694 | clnt->cl_pathname, | 696 | clnt->cl_pathname, |
695 | gss_auth->mech->gm_name); | 697 | gss_auth->mech->gm_name); |
696 | gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); | 698 | gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); |
697 | if (IS_ERR(gss_auth->dentry)) | 699 | if (IS_ERR(gss_auth->dentry)) { |
700 | err = PTR_ERR(gss_auth->dentry); | ||
698 | goto err_put_mech; | 701 | goto err_put_mech; |
702 | } | ||
699 | 703 | ||
700 | return auth; | 704 | return auth; |
701 | err_put_mech: | 705 | err_put_mech: |
@@ -704,7 +708,7 @@ err_free: | |||
704 | kfree(gss_auth); | 708 | kfree(gss_auth); |
705 | out_dec: | 709 | out_dec: |
706 | module_put(THIS_MODULE); | 710 | module_put(THIS_MODULE); |
707 | return NULL; | 711 | return ERR_PTR(err); |
708 | } | 712 | } |
709 | 713 | ||
710 | static void | 714 | static void |
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 | } | ||
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index d0b1d2c34a4d..4e81f2766923 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c | |||
@@ -53,6 +53,9 @@ rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt) | |||
53 | task->tk_pid, clnt->cl_server, | 53 | task->tk_pid, clnt->cl_server, |
54 | map->pm_prog, map->pm_vers, map->pm_prot); | 54 | map->pm_prog, map->pm_vers, map->pm_prot); |
55 | 55 | ||
56 | /* Autobind on cloned rpc clients is discouraged */ | ||
57 | BUG_ON(clnt->cl_parent != clnt); | ||
58 | |||
56 | spin_lock(&pmap_lock); | 59 | spin_lock(&pmap_lock); |
57 | if (map->pm_binding) { | 60 | if (map->pm_binding) { |
58 | rpc_sleep_on(&map->pm_bindwait, task, NULL, NULL); | 61 | rpc_sleep_on(&map->pm_bindwait, task, NULL, NULL); |
@@ -207,12 +210,10 @@ pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto) | |||
207 | xprt->addr.sin_port = htons(RPC_PMAP_PORT); | 210 | xprt->addr.sin_port = htons(RPC_PMAP_PORT); |
208 | 211 | ||
209 | /* printk("pmap: create clnt\n"); */ | 212 | /* printk("pmap: create clnt\n"); */ |
210 | clnt = rpc_create_client(xprt, hostname, | 213 | clnt = rpc_new_client(xprt, hostname, |
211 | &pmap_program, RPC_PMAP_VERSION, | 214 | &pmap_program, RPC_PMAP_VERSION, |
212 | RPC_AUTH_UNIX); | 215 | RPC_AUTH_UNIX); |
213 | if (IS_ERR(clnt)) { | 216 | if (!IS_ERR(clnt)) { |
214 | xprt_destroy(xprt); | ||
215 | } else { | ||
216 | clnt->cl_softrtry = 1; | 217 | clnt->cl_softrtry = 1; |
217 | clnt->cl_chatty = 1; | 218 | clnt->cl_chatty = 1; |
218 | clnt->cl_oneshot = 1; | 219 | clnt->cl_oneshot = 1; |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index c06614d0e31d..2d9eb7fbd521 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -290,7 +290,7 @@ static void rpc_make_runnable(struct rpc_task *task) | |||
290 | return; | 290 | return; |
291 | } | 291 | } |
292 | } else | 292 | } else |
293 | wake_up(&task->u.tk_wait.waitq); | 293 | wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED); |
294 | } | 294 | } |
295 | 295 | ||
296 | /* | 296 | /* |
@@ -555,6 +555,38 @@ __rpc_atrun(struct rpc_task *task) | |||
555 | } | 555 | } |
556 | 556 | ||
557 | /* | 557 | /* |
558 | * Helper that calls task->tk_exit if it exists and then returns | ||
559 | * true if we should exit __rpc_execute. | ||
560 | */ | ||
561 | static inline int __rpc_do_exit(struct rpc_task *task) | ||
562 | { | ||
563 | if (task->tk_exit != NULL) { | ||
564 | lock_kernel(); | ||
565 | task->tk_exit(task); | ||
566 | unlock_kernel(); | ||
567 | /* If tk_action is non-null, we should restart the call */ | ||
568 | if (task->tk_action != NULL) { | ||
569 | if (!RPC_ASSASSINATED(task)) { | ||
570 | /* Release RPC slot and buffer memory */ | ||
571 | xprt_release(task); | ||
572 | rpc_free(task); | ||
573 | return 0; | ||
574 | } | ||
575 | printk(KERN_ERR "RPC: dead task tried to walk away.\n"); | ||
576 | } | ||
577 | } | ||
578 | return 1; | ||
579 | } | ||
580 | |||
581 | static int rpc_wait_bit_interruptible(void *word) | ||
582 | { | ||
583 | if (signal_pending(current)) | ||
584 | return -ERESTARTSYS; | ||
585 | schedule(); | ||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | /* | ||
558 | * This is the RPC `scheduler' (or rather, the finite state machine). | 590 | * This is the RPC `scheduler' (or rather, the finite state machine). |
559 | */ | 591 | */ |
560 | static int __rpc_execute(struct rpc_task *task) | 592 | static int __rpc_execute(struct rpc_task *task) |
@@ -566,8 +598,7 @@ static int __rpc_execute(struct rpc_task *task) | |||
566 | 598 | ||
567 | BUG_ON(RPC_IS_QUEUED(task)); | 599 | BUG_ON(RPC_IS_QUEUED(task)); |
568 | 600 | ||
569 | restarted: | 601 | for (;;) { |
570 | while (1) { | ||
571 | /* | 602 | /* |
572 | * Garbage collection of pending timers... | 603 | * Garbage collection of pending timers... |
573 | */ | 604 | */ |
@@ -600,11 +631,12 @@ static int __rpc_execute(struct rpc_task *task) | |||
600 | * by someone else. | 631 | * by someone else. |
601 | */ | 632 | */ |
602 | if (!RPC_IS_QUEUED(task)) { | 633 | if (!RPC_IS_QUEUED(task)) { |
603 | if (!task->tk_action) | 634 | if (task->tk_action != NULL) { |
635 | lock_kernel(); | ||
636 | task->tk_action(task); | ||
637 | unlock_kernel(); | ||
638 | } else if (__rpc_do_exit(task)) | ||
604 | break; | 639 | break; |
605 | lock_kernel(); | ||
606 | task->tk_action(task); | ||
607 | unlock_kernel(); | ||
608 | } | 640 | } |
609 | 641 | ||
610 | /* | 642 | /* |
@@ -624,44 +656,26 @@ static int __rpc_execute(struct rpc_task *task) | |||
624 | 656 | ||
625 | /* sync task: sleep here */ | 657 | /* sync task: sleep here */ |
626 | dprintk("RPC: %4d sync task going to sleep\n", task->tk_pid); | 658 | dprintk("RPC: %4d sync task going to sleep\n", task->tk_pid); |
627 | if (RPC_TASK_UNINTERRUPTIBLE(task)) { | 659 | /* Note: Caller should be using rpc_clnt_sigmask() */ |
628 | __wait_event(task->u.tk_wait.waitq, !RPC_IS_QUEUED(task)); | 660 | status = out_of_line_wait_on_bit(&task->tk_runstate, |
629 | } else { | 661 | RPC_TASK_QUEUED, rpc_wait_bit_interruptible, |
630 | __wait_event_interruptible(task->u.tk_wait.waitq, !RPC_IS_QUEUED(task), status); | 662 | TASK_INTERRUPTIBLE); |
663 | if (status == -ERESTARTSYS) { | ||
631 | /* | 664 | /* |
632 | * When a sync task receives a signal, it exits with | 665 | * When a sync task receives a signal, it exits with |
633 | * -ERESTARTSYS. In order to catch any callbacks that | 666 | * -ERESTARTSYS. In order to catch any callbacks that |
634 | * clean up after sleeping on some queue, we don't | 667 | * clean up after sleeping on some queue, we don't |
635 | * break the loop here, but go around once more. | 668 | * break the loop here, but go around once more. |
636 | */ | 669 | */ |
637 | if (status == -ERESTARTSYS) { | 670 | dprintk("RPC: %4d got signal\n", task->tk_pid); |
638 | dprintk("RPC: %4d got signal\n", task->tk_pid); | 671 | task->tk_flags |= RPC_TASK_KILLED; |
639 | task->tk_flags |= RPC_TASK_KILLED; | 672 | rpc_exit(task, -ERESTARTSYS); |
640 | rpc_exit(task, -ERESTARTSYS); | 673 | rpc_wake_up_task(task); |
641 | rpc_wake_up_task(task); | ||
642 | } | ||
643 | } | 674 | } |
644 | rpc_set_running(task); | 675 | rpc_set_running(task); |
645 | dprintk("RPC: %4d sync task resuming\n", task->tk_pid); | 676 | dprintk("RPC: %4d sync task resuming\n", task->tk_pid); |
646 | } | 677 | } |
647 | 678 | ||
648 | if (task->tk_exit) { | ||
649 | lock_kernel(); | ||
650 | task->tk_exit(task); | ||
651 | unlock_kernel(); | ||
652 | /* If tk_action is non-null, the user wants us to restart */ | ||
653 | if (task->tk_action) { | ||
654 | if (!RPC_ASSASSINATED(task)) { | ||
655 | /* Release RPC slot and buffer memory */ | ||
656 | if (task->tk_rqstp) | ||
657 | xprt_release(task); | ||
658 | rpc_free(task); | ||
659 | goto restarted; | ||
660 | } | ||
661 | printk(KERN_ERR "RPC: dead task tries to walk away.\n"); | ||
662 | } | ||
663 | } | ||
664 | |||
665 | dprintk("RPC: %4d exit() = %d\n", task->tk_pid, task->tk_status); | 679 | dprintk("RPC: %4d exit() = %d\n", task->tk_pid, task->tk_status); |
666 | status = task->tk_status; | 680 | status = task->tk_status; |
667 | 681 | ||
@@ -759,8 +773,6 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, rpc_action call | |||
759 | 773 | ||
760 | /* Initialize workqueue for async tasks */ | 774 | /* Initialize workqueue for async tasks */ |
761 | task->tk_workqueue = rpciod_workqueue; | 775 | task->tk_workqueue = rpciod_workqueue; |
762 | if (!RPC_IS_ASYNC(task)) | ||
763 | init_waitqueue_head(&task->u.tk_wait.waitq); | ||
764 | 776 | ||
765 | if (clnt) { | 777 | if (clnt) { |
766 | atomic_inc(&clnt->cl_users); | 778 | atomic_inc(&clnt->cl_users); |
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index d4f26bf9e732..32e8acbc60fe 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c | |||
@@ -42,6 +42,7 @@ EXPORT_SYMBOL(rpc_release_task); | |||
42 | /* RPC client functions */ | 42 | /* RPC client functions */ |
43 | EXPORT_SYMBOL(rpc_create_client); | 43 | EXPORT_SYMBOL(rpc_create_client); |
44 | EXPORT_SYMBOL(rpc_clone_client); | 44 | EXPORT_SYMBOL(rpc_clone_client); |
45 | EXPORT_SYMBOL(rpc_bind_new_program); | ||
45 | EXPORT_SYMBOL(rpc_destroy_client); | 46 | EXPORT_SYMBOL(rpc_destroy_client); |
46 | EXPORT_SYMBOL(rpc_shutdown_client); | 47 | EXPORT_SYMBOL(rpc_shutdown_client); |
47 | EXPORT_SYMBOL(rpc_release_client); | 48 | EXPORT_SYMBOL(rpc_release_client); |
@@ -61,7 +62,6 @@ EXPORT_SYMBOL(rpc_mkpipe); | |||
61 | 62 | ||
62 | /* Client transport */ | 63 | /* Client transport */ |
63 | EXPORT_SYMBOL(xprt_create_proto); | 64 | EXPORT_SYMBOL(xprt_create_proto); |
64 | EXPORT_SYMBOL(xprt_destroy); | ||
65 | EXPORT_SYMBOL(xprt_set_timeout); | 65 | EXPORT_SYMBOL(xprt_set_timeout); |
66 | EXPORT_SYMBOL(xprt_udp_slot_table_entries); | 66 | EXPORT_SYMBOL(xprt_udp_slot_table_entries); |
67 | EXPORT_SYMBOL(xprt_tcp_slot_table_entries); | 67 | EXPORT_SYMBOL(xprt_tcp_slot_table_entries); |
@@ -129,6 +129,10 @@ EXPORT_SYMBOL(xdr_encode_netobj); | |||
129 | EXPORT_SYMBOL(xdr_encode_pages); | 129 | EXPORT_SYMBOL(xdr_encode_pages); |
130 | EXPORT_SYMBOL(xdr_inline_pages); | 130 | EXPORT_SYMBOL(xdr_inline_pages); |
131 | EXPORT_SYMBOL(xdr_shift_buf); | 131 | EXPORT_SYMBOL(xdr_shift_buf); |
132 | EXPORT_SYMBOL(xdr_encode_word); | ||
133 | EXPORT_SYMBOL(xdr_decode_word); | ||
134 | EXPORT_SYMBOL(xdr_encode_array2); | ||
135 | EXPORT_SYMBOL(xdr_decode_array2); | ||
132 | EXPORT_SYMBOL(xdr_buf_from_iov); | 136 | EXPORT_SYMBOL(xdr_buf_from_iov); |
133 | EXPORT_SYMBOL(xdr_buf_subsegment); | 137 | EXPORT_SYMBOL(xdr_buf_subsegment); |
134 | EXPORT_SYMBOL(xdr_buf_read_netobj); | 138 | EXPORT_SYMBOL(xdr_buf_read_netobj); |
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index bb2d99f33315..e9bd91265f70 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
@@ -35,20 +35,24 @@ svc_create(struct svc_program *prog, unsigned int bufsize) | |||
35 | if (!(serv = (struct svc_serv *) kmalloc(sizeof(*serv), GFP_KERNEL))) | 35 | if (!(serv = (struct svc_serv *) kmalloc(sizeof(*serv), GFP_KERNEL))) |
36 | return NULL; | 36 | return NULL; |
37 | memset(serv, 0, sizeof(*serv)); | 37 | memset(serv, 0, sizeof(*serv)); |
38 | serv->sv_name = prog->pg_name; | ||
38 | serv->sv_program = prog; | 39 | serv->sv_program = prog; |
39 | serv->sv_nrthreads = 1; | 40 | serv->sv_nrthreads = 1; |
40 | serv->sv_stats = prog->pg_stats; | 41 | serv->sv_stats = prog->pg_stats; |
41 | serv->sv_bufsz = bufsize? bufsize : 4096; | 42 | serv->sv_bufsz = bufsize? bufsize : 4096; |
42 | prog->pg_lovers = prog->pg_nvers-1; | ||
43 | xdrsize = 0; | 43 | xdrsize = 0; |
44 | for (vers=0; vers<prog->pg_nvers ; vers++) | 44 | while (prog) { |
45 | if (prog->pg_vers[vers]) { | 45 | prog->pg_lovers = prog->pg_nvers-1; |
46 | prog->pg_hivers = vers; | 46 | for (vers=0; vers<prog->pg_nvers ; vers++) |
47 | if (prog->pg_lovers > vers) | 47 | if (prog->pg_vers[vers]) { |
48 | prog->pg_lovers = vers; | 48 | prog->pg_hivers = vers; |
49 | if (prog->pg_vers[vers]->vs_xdrsize > xdrsize) | 49 | if (prog->pg_lovers > vers) |
50 | xdrsize = prog->pg_vers[vers]->vs_xdrsize; | 50 | prog->pg_lovers = vers; |
51 | } | 51 | if (prog->pg_vers[vers]->vs_xdrsize > xdrsize) |
52 | xdrsize = prog->pg_vers[vers]->vs_xdrsize; | ||
53 | } | ||
54 | prog = prog->pg_next; | ||
55 | } | ||
52 | serv->sv_xdrsize = xdrsize; | 56 | serv->sv_xdrsize = xdrsize; |
53 | INIT_LIST_HEAD(&serv->sv_threads); | 57 | INIT_LIST_HEAD(&serv->sv_threads); |
54 | INIT_LIST_HEAD(&serv->sv_sockets); | 58 | INIT_LIST_HEAD(&serv->sv_sockets); |
@@ -56,8 +60,6 @@ svc_create(struct svc_program *prog, unsigned int bufsize) | |||
56 | INIT_LIST_HEAD(&serv->sv_permsocks); | 60 | INIT_LIST_HEAD(&serv->sv_permsocks); |
57 | spin_lock_init(&serv->sv_lock); | 61 | spin_lock_init(&serv->sv_lock); |
58 | 62 | ||
59 | serv->sv_name = prog->pg_name; | ||
60 | |||
61 | /* Remove any stale portmap registrations */ | 63 | /* Remove any stale portmap registrations */ |
62 | svc_register(serv, 0, 0); | 64 | svc_register(serv, 0, 0); |
63 | 65 | ||
@@ -281,6 +283,7 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) | |||
281 | rqstp->rq_res.len = 0; | 283 | rqstp->rq_res.len = 0; |
282 | rqstp->rq_res.page_base = 0; | 284 | rqstp->rq_res.page_base = 0; |
283 | rqstp->rq_res.page_len = 0; | 285 | rqstp->rq_res.page_len = 0; |
286 | rqstp->rq_res.buflen = PAGE_SIZE; | ||
284 | rqstp->rq_res.tail[0].iov_len = 0; | 287 | rqstp->rq_res.tail[0].iov_len = 0; |
285 | /* tcp needs a space for the record length... */ | 288 | /* tcp needs a space for the record length... */ |
286 | if (rqstp->rq_prot == IPPROTO_TCP) | 289 | if (rqstp->rq_prot == IPPROTO_TCP) |
@@ -338,7 +341,10 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) | |||
338 | goto sendit; | 341 | goto sendit; |
339 | } | 342 | } |
340 | 343 | ||
341 | if (prog != progp->pg_prog) | 344 | for (progp = serv->sv_program; progp; progp = progp->pg_next) |
345 | if (prog == progp->pg_prog) | ||
346 | break; | ||
347 | if (progp == NULL) | ||
342 | goto err_bad_prog; | 348 | goto err_bad_prog; |
343 | 349 | ||
344 | if (vers >= progp->pg_nvers || | 350 | if (vers >= progp->pg_nvers || |
@@ -451,11 +457,7 @@ err_bad_auth: | |||
451 | goto sendit; | 457 | goto sendit; |
452 | 458 | ||
453 | err_bad_prog: | 459 | err_bad_prog: |
454 | #ifdef RPC_PARANOIA | 460 | dprintk("svc: unknown program %d\n", prog); |
455 | if (prog != 100227 || progp->pg_prog != 100003) | ||
456 | printk("svc: unknown program %d (me %d)\n", prog, progp->pg_prog); | ||
457 | /* else it is just a Solaris client seeing if ACLs are supported */ | ||
458 | #endif | ||
459 | serv->sv_stats->rpcbadfmt++; | 461 | serv->sv_stats->rpcbadfmt++; |
460 | svc_putu32(resv, rpc_prog_unavail); | 462 | svc_putu32(resv, rpc_prog_unavail); |
461 | goto sendit; | 463 | goto sendit; |
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 67b9f035ba86..8a4d9c106af1 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c | |||
@@ -176,21 +176,23 @@ xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, | |||
176 | xdr->buflen += len; | 176 | xdr->buflen += len; |
177 | } | 177 | } |
178 | 178 | ||
179 | void | 179 | ssize_t |
180 | xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, | 180 | xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, |
181 | skb_reader_t *desc, | 181 | skb_reader_t *desc, |
182 | skb_read_actor_t copy_actor) | 182 | skb_read_actor_t copy_actor) |
183 | { | 183 | { |
184 | struct page **ppage = xdr->pages; | 184 | struct page **ppage = xdr->pages; |
185 | unsigned int len, pglen = xdr->page_len; | 185 | unsigned int len, pglen = xdr->page_len; |
186 | ssize_t copied = 0; | ||
186 | int ret; | 187 | int ret; |
187 | 188 | ||
188 | len = xdr->head[0].iov_len; | 189 | len = xdr->head[0].iov_len; |
189 | if (base < len) { | 190 | if (base < len) { |
190 | len -= base; | 191 | len -= base; |
191 | ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len); | 192 | ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len); |
193 | copied += ret; | ||
192 | if (ret != len || !desc->count) | 194 | if (ret != len || !desc->count) |
193 | return; | 195 | goto out; |
194 | base = 0; | 196 | base = 0; |
195 | } else | 197 | } else |
196 | base -= len; | 198 | base -= len; |
@@ -210,6 +212,17 @@ xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, | |||
210 | do { | 212 | do { |
211 | char *kaddr; | 213 | char *kaddr; |
212 | 214 | ||
215 | /* ACL likes to be lazy in allocating pages - ACLs | ||
216 | * are small by default but can get huge. */ | ||
217 | if (unlikely(*ppage == NULL)) { | ||
218 | *ppage = alloc_page(GFP_ATOMIC); | ||
219 | if (unlikely(*ppage == NULL)) { | ||
220 | if (copied == 0) | ||
221 | copied = -ENOMEM; | ||
222 | goto out; | ||
223 | } | ||
224 | } | ||
225 | |||
213 | len = PAGE_CACHE_SIZE; | 226 | len = PAGE_CACHE_SIZE; |
214 | kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA); | 227 | kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA); |
215 | if (base) { | 228 | if (base) { |
@@ -225,14 +238,17 @@ xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, | |||
225 | } | 238 | } |
226 | flush_dcache_page(*ppage); | 239 | flush_dcache_page(*ppage); |
227 | kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA); | 240 | kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA); |
241 | copied += ret; | ||
228 | if (ret != len || !desc->count) | 242 | if (ret != len || !desc->count) |
229 | return; | 243 | goto out; |
230 | ppage++; | 244 | ppage++; |
231 | } while ((pglen -= len) != 0); | 245 | } while ((pglen -= len) != 0); |
232 | copy_tail: | 246 | copy_tail: |
233 | len = xdr->tail[0].iov_len; | 247 | len = xdr->tail[0].iov_len; |
234 | if (base < len) | 248 | if (base < len) |
235 | copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base); | 249 | copied += copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base); |
250 | out: | ||
251 | return copied; | ||
236 | } | 252 | } |
237 | 253 | ||
238 | 254 | ||
@@ -616,12 +632,24 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len) | |||
616 | void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) | 632 | void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) |
617 | { | 633 | { |
618 | struct kvec *iov = buf->head; | 634 | struct kvec *iov = buf->head; |
635 | int scratch_len = buf->buflen - buf->page_len - buf->tail[0].iov_len; | ||
619 | 636 | ||
637 | BUG_ON(scratch_len < 0); | ||
620 | xdr->buf = buf; | 638 | xdr->buf = buf; |
621 | xdr->iov = iov; | 639 | xdr->iov = iov; |
622 | xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len); | 640 | xdr->p = (uint32_t *)((char *)iov->iov_base + iov->iov_len); |
623 | buf->len = iov->iov_len = (char *)p - (char *)iov->iov_base; | 641 | xdr->end = (uint32_t *)((char *)iov->iov_base + scratch_len); |
624 | xdr->p = p; | 642 | BUG_ON(iov->iov_len > scratch_len); |
643 | |||
644 | if (p != xdr->p && p != NULL) { | ||
645 | size_t len; | ||
646 | |||
647 | BUG_ON(p < xdr->p || p > xdr->end); | ||
648 | len = (char *)p - (char *)xdr->p; | ||
649 | xdr->p = p; | ||
650 | buf->len += len; | ||
651 | iov->iov_len += len; | ||
652 | } | ||
625 | } | 653 | } |
626 | EXPORT_SYMBOL(xdr_init_encode); | 654 | EXPORT_SYMBOL(xdr_init_encode); |
627 | 655 | ||
@@ -859,8 +887,34 @@ out: | |||
859 | return status; | 887 | return status; |
860 | } | 888 | } |
861 | 889 | ||
862 | static int | 890 | /* obj is assumed to point to allocated memory of size at least len: */ |
863 | read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj) | 891 | int |
892 | write_bytes_to_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len) | ||
893 | { | ||
894 | struct xdr_buf subbuf; | ||
895 | int this_len; | ||
896 | int status; | ||
897 | |||
898 | status = xdr_buf_subsegment(buf, &subbuf, base, len); | ||
899 | if (status) | ||
900 | goto out; | ||
901 | this_len = min(len, (int)subbuf.head[0].iov_len); | ||
902 | memcpy(subbuf.head[0].iov_base, obj, this_len); | ||
903 | len -= this_len; | ||
904 | obj += this_len; | ||
905 | this_len = min(len, (int)subbuf.page_len); | ||
906 | if (this_len) | ||
907 | _copy_to_pages(subbuf.pages, subbuf.page_base, obj, this_len); | ||
908 | len -= this_len; | ||
909 | obj += this_len; | ||
910 | this_len = min(len, (int)subbuf.tail[0].iov_len); | ||
911 | memcpy(subbuf.tail[0].iov_base, obj, this_len); | ||
912 | out: | ||
913 | return status; | ||
914 | } | ||
915 | |||
916 | int | ||
917 | xdr_decode_word(struct xdr_buf *buf, int base, u32 *obj) | ||
864 | { | 918 | { |
865 | u32 raw; | 919 | u32 raw; |
866 | int status; | 920 | int status; |
@@ -872,6 +926,14 @@ read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj) | |||
872 | return 0; | 926 | return 0; |
873 | } | 927 | } |
874 | 928 | ||
929 | int | ||
930 | xdr_encode_word(struct xdr_buf *buf, int base, u32 obj) | ||
931 | { | ||
932 | u32 raw = htonl(obj); | ||
933 | |||
934 | return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj)); | ||
935 | } | ||
936 | |||
875 | /* If the netobj starting offset bytes from the start of xdr_buf is contained | 937 | /* If the netobj starting offset bytes from the start of xdr_buf is contained |
876 | * entirely in the head or the tail, set object to point to it; otherwise | 938 | * entirely in the head or the tail, set object to point to it; otherwise |
877 | * try to find space for it at the end of the tail, copy it there, and | 939 | * try to find space for it at the end of the tail, copy it there, and |
@@ -882,7 +944,7 @@ xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, int offset) | |||
882 | u32 tail_offset = buf->head[0].iov_len + buf->page_len; | 944 | u32 tail_offset = buf->head[0].iov_len + buf->page_len; |
883 | u32 obj_end_offset; | 945 | u32 obj_end_offset; |
884 | 946 | ||
885 | if (read_u32_from_xdr_buf(buf, offset, &obj->len)) | 947 | if (xdr_decode_word(buf, offset, &obj->len)) |
886 | goto out; | 948 | goto out; |
887 | obj_end_offset = offset + 4 + obj->len; | 949 | obj_end_offset = offset + 4 + obj->len; |
888 | 950 | ||
@@ -915,3 +977,219 @@ xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, int offset) | |||
915 | out: | 977 | out: |
916 | return -1; | 978 | return -1; |
917 | } | 979 | } |
980 | |||
981 | /* Returns 0 on success, or else a negative error code. */ | ||
982 | static int | ||
983 | xdr_xcode_array2(struct xdr_buf *buf, unsigned int base, | ||
984 | struct xdr_array2_desc *desc, int encode) | ||
985 | { | ||
986 | char *elem = NULL, *c; | ||
987 | unsigned int copied = 0, todo, avail_here; | ||
988 | struct page **ppages = NULL; | ||
989 | int err; | ||
990 | |||
991 | if (encode) { | ||
992 | if (xdr_encode_word(buf, base, desc->array_len) != 0) | ||
993 | return -EINVAL; | ||
994 | } else { | ||
995 | if (xdr_decode_word(buf, base, &desc->array_len) != 0 || | ||
996 | (unsigned long) base + 4 + desc->array_len * | ||
997 | desc->elem_size > buf->len) | ||
998 | return -EINVAL; | ||
999 | } | ||
1000 | base += 4; | ||
1001 | |||
1002 | if (!desc->xcode) | ||
1003 | return 0; | ||
1004 | |||
1005 | todo = desc->array_len * desc->elem_size; | ||
1006 | |||
1007 | /* process head */ | ||
1008 | if (todo && base < buf->head->iov_len) { | ||
1009 | c = buf->head->iov_base + base; | ||
1010 | avail_here = min_t(unsigned int, todo, | ||
1011 | buf->head->iov_len - base); | ||
1012 | todo -= avail_here; | ||
1013 | |||
1014 | while (avail_here >= desc->elem_size) { | ||
1015 | err = desc->xcode(desc, c); | ||
1016 | if (err) | ||
1017 | goto out; | ||
1018 | c += desc->elem_size; | ||
1019 | avail_here -= desc->elem_size; | ||
1020 | } | ||
1021 | if (avail_here) { | ||
1022 | if (!elem) { | ||
1023 | elem = kmalloc(desc->elem_size, GFP_KERNEL); | ||
1024 | err = -ENOMEM; | ||
1025 | if (!elem) | ||
1026 | goto out; | ||
1027 | } | ||
1028 | if (encode) { | ||
1029 | err = desc->xcode(desc, elem); | ||
1030 | if (err) | ||
1031 | goto out; | ||
1032 | memcpy(c, elem, avail_here); | ||
1033 | } else | ||
1034 | memcpy(elem, c, avail_here); | ||
1035 | copied = avail_here; | ||
1036 | } | ||
1037 | base = buf->head->iov_len; /* align to start of pages */ | ||
1038 | } | ||
1039 | |||
1040 | /* process pages array */ | ||
1041 | base -= buf->head->iov_len; | ||
1042 | if (todo && base < buf->page_len) { | ||
1043 | unsigned int avail_page; | ||
1044 | |||
1045 | avail_here = min(todo, buf->page_len - base); | ||
1046 | todo -= avail_here; | ||
1047 | |||
1048 | base += buf->page_base; | ||
1049 | ppages = buf->pages + (base >> PAGE_CACHE_SHIFT); | ||
1050 | base &= ~PAGE_CACHE_MASK; | ||
1051 | avail_page = min_t(unsigned int, PAGE_CACHE_SIZE - base, | ||
1052 | avail_here); | ||
1053 | c = kmap(*ppages) + base; | ||
1054 | |||
1055 | while (avail_here) { | ||
1056 | avail_here -= avail_page; | ||
1057 | if (copied || avail_page < desc->elem_size) { | ||
1058 | unsigned int l = min(avail_page, | ||
1059 | desc->elem_size - copied); | ||
1060 | if (!elem) { | ||
1061 | elem = kmalloc(desc->elem_size, | ||
1062 | GFP_KERNEL); | ||
1063 | err = -ENOMEM; | ||
1064 | if (!elem) | ||
1065 | goto out; | ||
1066 | } | ||
1067 | if (encode) { | ||
1068 | if (!copied) { | ||
1069 | err = desc->xcode(desc, elem); | ||
1070 | if (err) | ||
1071 | goto out; | ||
1072 | } | ||
1073 | memcpy(c, elem + copied, l); | ||
1074 | copied += l; | ||
1075 | if (copied == desc->elem_size) | ||
1076 | copied = 0; | ||
1077 | } else { | ||
1078 | memcpy(elem + copied, c, l); | ||
1079 | copied += l; | ||
1080 | if (copied == desc->elem_size) { | ||
1081 | err = desc->xcode(desc, elem); | ||
1082 | if (err) | ||
1083 | goto out; | ||
1084 | copied = 0; | ||
1085 | } | ||
1086 | } | ||
1087 | avail_page -= l; | ||
1088 | c += l; | ||
1089 | } | ||
1090 | while (avail_page >= desc->elem_size) { | ||
1091 | err = desc->xcode(desc, c); | ||
1092 | if (err) | ||
1093 | goto out; | ||
1094 | c += desc->elem_size; | ||
1095 | avail_page -= desc->elem_size; | ||
1096 | } | ||
1097 | if (avail_page) { | ||
1098 | unsigned int l = min(avail_page, | ||
1099 | desc->elem_size - copied); | ||
1100 | if (!elem) { | ||
1101 | elem = kmalloc(desc->elem_size, | ||
1102 | GFP_KERNEL); | ||
1103 | err = -ENOMEM; | ||
1104 | if (!elem) | ||
1105 | goto out; | ||
1106 | } | ||
1107 | if (encode) { | ||
1108 | if (!copied) { | ||
1109 | err = desc->xcode(desc, elem); | ||
1110 | if (err) | ||
1111 | goto out; | ||
1112 | } | ||
1113 | memcpy(c, elem + copied, l); | ||
1114 | copied += l; | ||
1115 | if (copied == desc->elem_size) | ||
1116 | copied = 0; | ||
1117 | } else { | ||
1118 | memcpy(elem + copied, c, l); | ||
1119 | copied += l; | ||
1120 | if (copied == desc->elem_size) { | ||
1121 | err = desc->xcode(desc, elem); | ||
1122 | if (err) | ||
1123 | goto out; | ||
1124 | copied = 0; | ||
1125 | } | ||
1126 | } | ||
1127 | } | ||
1128 | if (avail_here) { | ||
1129 | kunmap(*ppages); | ||
1130 | ppages++; | ||
1131 | c = kmap(*ppages); | ||
1132 | } | ||
1133 | |||
1134 | avail_page = min(avail_here, | ||
1135 | (unsigned int) PAGE_CACHE_SIZE); | ||
1136 | } | ||
1137 | base = buf->page_len; /* align to start of tail */ | ||
1138 | } | ||
1139 | |||
1140 | /* process tail */ | ||
1141 | base -= buf->page_len; | ||
1142 | if (todo) { | ||
1143 | c = buf->tail->iov_base + base; | ||
1144 | if (copied) { | ||
1145 | unsigned int l = desc->elem_size - copied; | ||
1146 | |||
1147 | if (encode) | ||
1148 | memcpy(c, elem + copied, l); | ||
1149 | else { | ||
1150 | memcpy(elem + copied, c, l); | ||
1151 | err = desc->xcode(desc, elem); | ||
1152 | if (err) | ||
1153 | goto out; | ||
1154 | } | ||
1155 | todo -= l; | ||
1156 | c += l; | ||
1157 | } | ||
1158 | while (todo) { | ||
1159 | err = desc->xcode(desc, c); | ||
1160 | if (err) | ||
1161 | goto out; | ||
1162 | c += desc->elem_size; | ||
1163 | todo -= desc->elem_size; | ||
1164 | } | ||
1165 | } | ||
1166 | err = 0; | ||
1167 | |||
1168 | out: | ||
1169 | if (elem) | ||
1170 | kfree(elem); | ||
1171 | if (ppages) | ||
1172 | kunmap(*ppages); | ||
1173 | return err; | ||
1174 | } | ||
1175 | |||
1176 | int | ||
1177 | xdr_decode_array2(struct xdr_buf *buf, unsigned int base, | ||
1178 | struct xdr_array2_desc *desc) | ||
1179 | { | ||
1180 | if (base >= buf->len) | ||
1181 | return -EINVAL; | ||
1182 | |||
1183 | return xdr_xcode_array2(buf, base, desc, 0); | ||
1184 | } | ||
1185 | |||
1186 | int | ||
1187 | xdr_encode_array2(struct xdr_buf *buf, unsigned int base, | ||
1188 | struct xdr_array2_desc *desc) | ||
1189 | { | ||
1190 | if ((unsigned long) base + 4 + desc->array_len * desc->elem_size > | ||
1191 | buf->head->iov_len + buf->page_len + buf->tail->iov_len) | ||
1192 | return -EINVAL; | ||
1193 | |||
1194 | return xdr_xcode_array2(buf, base, desc, 1); | ||
1195 | } | ||
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index c74a6bb94074..eca92405948f 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -569,8 +569,11 @@ void xprt_connect(struct rpc_task *task) | |||
569 | if (xprt->sock != NULL) | 569 | if (xprt->sock != NULL) |
570 | schedule_delayed_work(&xprt->sock_connect, | 570 | schedule_delayed_work(&xprt->sock_connect, |
571 | RPC_REESTABLISH_TIMEOUT); | 571 | RPC_REESTABLISH_TIMEOUT); |
572 | else | 572 | else { |
573 | schedule_work(&xprt->sock_connect); | 573 | schedule_work(&xprt->sock_connect); |
574 | if (!RPC_IS_ASYNC(task)) | ||
575 | flush_scheduled_work(); | ||
576 | } | ||
574 | } | 577 | } |
575 | return; | 578 | return; |
576 | out_write: | 579 | out_write: |
@@ -725,7 +728,8 @@ csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) | |||
725 | goto no_checksum; | 728 | goto no_checksum; |
726 | 729 | ||
727 | desc.csum = csum_partial(skb->data, desc.offset, skb->csum); | 730 | desc.csum = csum_partial(skb->data, desc.offset, skb->csum); |
728 | xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits); | 731 | if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits) < 0) |
732 | return -1; | ||
729 | if (desc.offset != skb->len) { | 733 | if (desc.offset != skb->len) { |
730 | unsigned int csum2; | 734 | unsigned int csum2; |
731 | csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0); | 735 | csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0); |
@@ -737,7 +741,8 @@ csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) | |||
737 | return -1; | 741 | return -1; |
738 | return 0; | 742 | return 0; |
739 | no_checksum: | 743 | no_checksum: |
740 | xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits); | 744 | if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits) < 0) |
745 | return -1; | ||
741 | if (desc.count) | 746 | if (desc.count) |
742 | return -1; | 747 | return -1; |
743 | return 0; | 748 | return 0; |
@@ -821,10 +826,15 @@ tcp_copy_data(skb_reader_t *desc, void *p, size_t len) | |||
821 | { | 826 | { |
822 | if (len > desc->count) | 827 | if (len > desc->count) |
823 | len = desc->count; | 828 | len = desc->count; |
824 | if (skb_copy_bits(desc->skb, desc->offset, p, len)) | 829 | if (skb_copy_bits(desc->skb, desc->offset, p, len)) { |
830 | dprintk("RPC: failed to copy %zu bytes from skb. %zu bytes remain\n", | ||
831 | len, desc->count); | ||
825 | return 0; | 832 | return 0; |
833 | } | ||
826 | desc->offset += len; | 834 | desc->offset += len; |
827 | desc->count -= len; | 835 | desc->count -= len; |
836 | dprintk("RPC: copied %zu bytes from skb. %zu bytes remain\n", | ||
837 | len, desc->count); | ||
828 | return len; | 838 | return len; |
829 | } | 839 | } |
830 | 840 | ||
@@ -863,6 +873,8 @@ tcp_read_fraghdr(struct rpc_xprt *xprt, skb_reader_t *desc) | |||
863 | static void | 873 | static void |
864 | tcp_check_recm(struct rpc_xprt *xprt) | 874 | tcp_check_recm(struct rpc_xprt *xprt) |
865 | { | 875 | { |
876 | dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u, tcp_flags = %lx\n", | ||
877 | xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen, xprt->tcp_flags); | ||
866 | if (xprt->tcp_offset == xprt->tcp_reclen) { | 878 | if (xprt->tcp_offset == xprt->tcp_reclen) { |
867 | xprt->tcp_flags |= XPRT_COPY_RECM; | 879 | xprt->tcp_flags |= XPRT_COPY_RECM; |
868 | xprt->tcp_offset = 0; | 880 | xprt->tcp_offset = 0; |
@@ -907,6 +919,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) | |||
907 | struct rpc_rqst *req; | 919 | struct rpc_rqst *req; |
908 | struct xdr_buf *rcvbuf; | 920 | struct xdr_buf *rcvbuf; |
909 | size_t len; | 921 | size_t len; |
922 | ssize_t r; | ||
910 | 923 | ||
911 | /* Find and lock the request corresponding to this xid */ | 924 | /* Find and lock the request corresponding to this xid */ |
912 | spin_lock(&xprt->sock_lock); | 925 | spin_lock(&xprt->sock_lock); |
@@ -927,15 +940,40 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) | |||
927 | len = xprt->tcp_reclen - xprt->tcp_offset; | 940 | len = xprt->tcp_reclen - xprt->tcp_offset; |
928 | memcpy(&my_desc, desc, sizeof(my_desc)); | 941 | memcpy(&my_desc, desc, sizeof(my_desc)); |
929 | my_desc.count = len; | 942 | my_desc.count = len; |
930 | xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, | 943 | r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, |
931 | &my_desc, tcp_copy_data); | 944 | &my_desc, tcp_copy_data); |
932 | desc->count -= len; | 945 | desc->count -= r; |
933 | desc->offset += len; | 946 | desc->offset += r; |
934 | } else | 947 | } else |
935 | xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, | 948 | r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, |
936 | desc, tcp_copy_data); | 949 | desc, tcp_copy_data); |
937 | xprt->tcp_copied += len; | 950 | |
938 | xprt->tcp_offset += len; | 951 | if (r > 0) { |
952 | xprt->tcp_copied += r; | ||
953 | xprt->tcp_offset += r; | ||
954 | } | ||
955 | if (r != len) { | ||
956 | /* Error when copying to the receive buffer, | ||
957 | * usually because we weren't able to allocate | ||
958 | * additional buffer pages. All we can do now | ||
959 | * is turn off XPRT_COPY_DATA, so the request | ||
960 | * will not receive any additional updates, | ||
961 | * and time out. | ||
962 | * Any remaining data from this record will | ||
963 | * be discarded. | ||
964 | */ | ||
965 | xprt->tcp_flags &= ~XPRT_COPY_DATA; | ||
966 | dprintk("RPC: XID %08x truncated request\n", | ||
967 | ntohl(xprt->tcp_xid)); | ||
968 | dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", | ||
969 | xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); | ||
970 | goto out; | ||
971 | } | ||
972 | |||
973 | dprintk("RPC: XID %08x read %u bytes\n", | ||
974 | ntohl(xprt->tcp_xid), r); | ||
975 | dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n", | ||
976 | xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen); | ||
939 | 977 | ||
940 | if (xprt->tcp_copied == req->rq_private_buf.buflen) | 978 | if (xprt->tcp_copied == req->rq_private_buf.buflen) |
941 | xprt->tcp_flags &= ~XPRT_COPY_DATA; | 979 | xprt->tcp_flags &= ~XPRT_COPY_DATA; |
@@ -944,6 +982,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) | |||
944 | xprt->tcp_flags &= ~XPRT_COPY_DATA; | 982 | xprt->tcp_flags &= ~XPRT_COPY_DATA; |
945 | } | 983 | } |
946 | 984 | ||
985 | out: | ||
947 | if (!(xprt->tcp_flags & XPRT_COPY_DATA)) { | 986 | if (!(xprt->tcp_flags & XPRT_COPY_DATA)) { |
948 | dprintk("RPC: %4d received reply complete\n", | 987 | dprintk("RPC: %4d received reply complete\n", |
949 | req->rq_task->tk_pid); | 988 | req->rq_task->tk_pid); |
@@ -967,6 +1006,7 @@ tcp_read_discard(struct rpc_xprt *xprt, skb_reader_t *desc) | |||
967 | desc->count -= len; | 1006 | desc->count -= len; |
968 | desc->offset += len; | 1007 | desc->offset += len; |
969 | xprt->tcp_offset += len; | 1008 | xprt->tcp_offset += len; |
1009 | dprintk("RPC: discarded %u bytes\n", len); | ||
970 | tcp_check_recm(xprt); | 1010 | tcp_check_recm(xprt); |
971 | } | 1011 | } |
972 | 1012 | ||
@@ -1064,8 +1104,7 @@ tcp_state_change(struct sock *sk) | |||
1064 | case TCP_SYN_RECV: | 1104 | case TCP_SYN_RECV: |
1065 | break; | 1105 | break; |
1066 | default: | 1106 | default: |
1067 | if (xprt_test_and_clear_connected(xprt)) | 1107 | xprt_disconnect(xprt); |
1068 | rpc_wake_up_status(&xprt->pending, -ENOTCONN); | ||
1069 | break; | 1108 | break; |
1070 | } | 1109 | } |
1071 | out: | 1110 | out: |
@@ -1203,6 +1242,8 @@ xprt_transmit(struct rpc_task *task) | |||
1203 | list_add_tail(&req->rq_list, &xprt->recv); | 1242 | list_add_tail(&req->rq_list, &xprt->recv); |
1204 | spin_unlock_bh(&xprt->sock_lock); | 1243 | spin_unlock_bh(&xprt->sock_lock); |
1205 | xprt_reset_majortimeo(req); | 1244 | xprt_reset_majortimeo(req); |
1245 | /* Turn off autodisconnect */ | ||
1246 | del_singleshot_timer_sync(&xprt->timer); | ||
1206 | } | 1247 | } |
1207 | } else if (!req->rq_bytes_sent) | 1248 | } else if (!req->rq_bytes_sent) |
1208 | return; | 1249 | return; |
@@ -1333,8 +1374,6 @@ xprt_reserve(struct rpc_task *task) | |||
1333 | spin_lock(&xprt->xprt_lock); | 1374 | spin_lock(&xprt->xprt_lock); |
1334 | do_xprt_reserve(task); | 1375 | do_xprt_reserve(task); |
1335 | spin_unlock(&xprt->xprt_lock); | 1376 | spin_unlock(&xprt->xprt_lock); |
1336 | if (task->tk_rqstp) | ||
1337 | del_timer_sync(&xprt->timer); | ||
1338 | } | 1377 | } |
1339 | } | 1378 | } |
1340 | 1379 | ||
@@ -1649,6 +1688,10 @@ xprt_shutdown(struct rpc_xprt *xprt) | |||
1649 | rpc_wake_up(&xprt->backlog); | 1688 | rpc_wake_up(&xprt->backlog); |
1650 | wake_up(&xprt->cong_wait); | 1689 | wake_up(&xprt->cong_wait); |
1651 | del_timer_sync(&xprt->timer); | 1690 | del_timer_sync(&xprt->timer); |
1691 | |||
1692 | /* synchronously wait for connect worker to finish */ | ||
1693 | cancel_delayed_work(&xprt->sock_connect); | ||
1694 | flush_scheduled_work(); | ||
1652 | } | 1695 | } |
1653 | 1696 | ||
1654 | /* | 1697 | /* |