From b1a7a91ada8388936ffff92cf1ad57b3e926f412 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Sun, 29 Aug 2010 12:13:15 -0400 Subject: sunrpc: don't shorten buflen twice in xdr_shrink_pagelen On Jan. 14, 2009, 2:50 +0200, andros@netapp.com wrote: > From: Andy Adamson > > The buflen is reset for all cases at the end of xdr_shrink_pagelen. > The data left in the tail after xdr_read_pages is not processed when the > buflen is incorrectly set. Note that in this case we also lose (len - tail->iov_len) bytes from the buffered data in pages. Reported-by: Andy Adamson Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust --- net/sunrpc/xdr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index a1f82a87d34..91f0de944d0 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -407,8 +407,7 @@ xdr_shrink_pagelen(struct xdr_buf *buf, size_t len) if (tail->iov_len > len) { copy = tail->iov_len - len; memmove(p, tail->iov_base, copy); - } else - buf->buflen -= len; + } /* Copy from the inlined pages into the tail */ copy = len; if (copy > tail->iov_len) -- cgit v1.2.3 From 0fe62a35903e11fb41b492bd5b0e8e4c751d5c94 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Sun, 29 Aug 2010 12:13:15 -0400 Subject: sunrpc: clean up xdr_shrink_pagelen use of temporary pointer char *p is used only as a shorthand for tail->iov_base + len in a nested block. Move it there. Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust --- net/sunrpc/xdr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 91f0de944d0..41be21f7f7b 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -395,7 +395,6 @@ xdr_shrink_pagelen(struct xdr_buf *buf, size_t len) { struct kvec *tail; size_t copy; - char *p; unsigned int pglen = buf->page_len; tail = buf->tail; @@ -403,8 +402,8 @@ xdr_shrink_pagelen(struct xdr_buf *buf, size_t len) /* Shift the tail first */ if (tail->iov_len != 0) { - p = (char *)tail->iov_base + len; if (tail->iov_len > len) { + char *p = (char *)tail->iov_base + len; copy = tail->iov_len - len; memmove(p, tail->iov_base, copy); } -- cgit v1.2.3 From 2e29ebb8119e6037133921fac09cc5f9d625b511 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Sun, 29 Aug 2010 12:13:15 -0400 Subject: sunrpc: don't use the copy variable in nested block to clean up the code "copy" will be set prior to the block hence it mustn't be used there. Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust --- net/sunrpc/xdr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 41be21f7f7b..42a7ebf2a32 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -404,8 +404,7 @@ xdr_shrink_pagelen(struct xdr_buf *buf, size_t len) if (tail->iov_len != 0) { if (tail->iov_len > len) { char *p = (char *)tail->iov_base + len; - copy = tail->iov_len - len; - memmove(p, tail->iov_base, copy); + memmove(p, tail->iov_base, tail->iov_len - len); } /* Copy from the inlined pages into the tail */ copy = len; -- cgit v1.2.3 From 42d6d8ab51ca04afcb8a64759076da624cdb71e8 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Sun, 29 Aug 2010 12:13:15 -0400 Subject: sunrpc: simplify xdr_shrink_pagelen use of "copy" The "copy" variable value can be computed using the existing logic rather than repeating it. Signed-off-by: Benny Halevy Signed-off-by: Trond Myklebust --- net/sunrpc/xdr.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 42a7ebf2a32..3317db3cb10 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -402,14 +402,13 @@ xdr_shrink_pagelen(struct xdr_buf *buf, size_t len) /* Shift the tail first */ if (tail->iov_len != 0) { + copy = len; if (tail->iov_len > len) { char *p = (char *)tail->iov_base + len; memmove(p, tail->iov_base, tail->iov_len - len); - } - /* Copy from the inlined pages into the tail */ - copy = len; - if (copy > tail->iov_len) + } else copy = tail->iov_len; + /* Copy from the inlined pages into the tail */ _copy_from_pages((char *)tail->iov_base, buf->pages, buf->page_base + pglen - len, copy); -- cgit v1.2.3 From cf187c2d7ec763cdd459fe43933a5cc4f5f48e1b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 29 Aug 2010 12:13:16 -0400 Subject: SUNRPC: Don't truncate tail data unnecessarily in xdr_shrink_pagelen If we have unused buffer space, then we should make use of that rather than unnecessarily truncating the message. Signed-off-by: Trond Myklebust --- net/sunrpc/xdr.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 3317db3cb10..3bbef7f5f82 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -396,12 +396,21 @@ xdr_shrink_pagelen(struct xdr_buf *buf, size_t len) struct kvec *tail; size_t copy; unsigned int pglen = buf->page_len; + unsigned int tailbuf_len; tail = buf->tail; BUG_ON (len > pglen); + tailbuf_len = buf->buflen - buf->head->iov_len - buf->page_len; + /* Shift the tail first */ - if (tail->iov_len != 0) { + if (tailbuf_len != 0) { + unsigned int free_space = tailbuf_len - tail->iov_len; + + if (len < free_space) + free_space = len; + tail->iov_len += free_space; + copy = len; if (tail->iov_len > len) { char *p = (char *)tail->iov_base + len; -- cgit v1.2.3 From 859d5024f450686ad0a42ed3c06f2fa20295c9e6 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 17 Sep 2010 10:54:37 -0400 Subject: SUNRPC: Remove rpcb_getport_sync() Clean up: rpcb_getport_sync() has no more users, so remove it. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/rpcb_clnt.c | 51 -------------------------------------------------- 1 file changed, 51 deletions(-) (limited to 'net') diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index dac219a56ae..c961094ebc6 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -475,57 +475,6 @@ int rpcb_v4_register(const u32 program, const u32 version, return -EAFNOSUPPORT; } -/** - * rpcb_getport_sync - obtain the port for an RPC service on a given host - * @sin: address of remote peer - * @prog: RPC program number to bind - * @vers: RPC version number to bind - * @prot: transport protocol to use to make this request - * - * Return value is the requested advertised port number, - * or a negative errno value. - * - * Called from outside the RPC client in a synchronous task context. - * Uses default timeout parameters specified by underlying transport. - * - * XXX: Needs to support IPv6 - */ -int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot) -{ - struct rpcbind_args map = { - .r_prog = prog, - .r_vers = vers, - .r_prot = prot, - .r_port = 0, - }; - struct rpc_message msg = { - .rpc_proc = &rpcb_procedures2[RPCBPROC_GETPORT], - .rpc_argp = &map, - .rpc_resp = &map, - }; - struct rpc_clnt *rpcb_clnt; - int status; - - dprintk("RPC: %s(%pI4, %u, %u, %d)\n", - __func__, &sin->sin_addr.s_addr, prog, vers, prot); - - rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin, - sizeof(*sin), prot, RPCBVERS_2); - if (IS_ERR(rpcb_clnt)) - return PTR_ERR(rpcb_clnt); - - status = rpc_call_sync(rpcb_clnt, &msg, 0); - rpc_shutdown_client(rpcb_clnt); - - if (status >= 0) { - if (map.r_port != 0) - return map.r_port; - status = -EACCES; - } - return status; -} -EXPORT_SYMBOL_GPL(rpcb_getport_sync); - static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbind_args *map, struct rpc_procinfo *proc) { struct rpc_message msg = { -- cgit v1.2.3 From 4fbf6e507888da902b02a3c4f5f493fab1071312 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 21 Sep 2010 16:54:34 -0400 Subject: SUNRPC: Convert rpciod to use the alloc_workqueue() interface create_workqueue() is a deprecated function. Signed-off-by: Trond Myklebust --- net/sunrpc/sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index cace6049e4a..2b08c3d2f4d 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -908,7 +908,7 @@ static int rpciod_start(void) * Create the rpciod thread and wait for it to start. */ dprintk("RPC: creating workqueue rpciod\n"); - wq = create_workqueue("rpciod"); + wq = alloc_workqueue("rpciod", WQ_RESCUER, 0); rpciod_workqueue = wq; return rpciod_workqueue != NULL; } -- cgit v1.2.3 From 38359352fcb0d776b562a9e0ed4f0d355d5a332e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 21 Sep 2010 16:55:48 -0400 Subject: SUNRPC: Correct an rpcbind debugging message Clean up. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/rpcb_clnt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index c961094ebc6..63ec116b4dd 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -211,8 +211,9 @@ static int rpcb_create_local(void) */ clnt4 = rpc_bind_new_program(clnt, &rpcb_program, RPCBVERS_4); if (IS_ERR(clnt4)) { - dprintk("RPC: failed to create local rpcbind v4 " - "cleint (errno %ld).\n", PTR_ERR(clnt4)); + dprintk("RPC: failed to bind second program to " + "rpcbind v4 client (errno %ld).\n", + PTR_ERR(clnt4)); clnt4 = NULL; } -- cgit v1.2.3 From b4687da7fc5f741af7fee9b0248a2cf2ad9c4478 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 21 Sep 2010 16:55:48 -0400 Subject: SUNRPC: Refactor logic to NUL-terminate strings in pages Clean up: Introduce a helper to '\0'-terminate XDR strings that are placed in a page in the page cache. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/xdr.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'net') diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 3bbef7f5f82..e0725d9d810 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -111,6 +111,23 @@ xdr_decode_string_inplace(__be32 *p, char **sp, } EXPORT_SYMBOL_GPL(xdr_decode_string_inplace); +/** + * xdr_terminate_string - '\0'-terminate a string residing in an xdr_buf + * @buf: XDR buffer where string resides + * @len: length of string, in bytes + * + */ +void +xdr_terminate_string(struct xdr_buf *buf, const u32 len) +{ + char *kaddr; + + kaddr = kmap_atomic(buf->pages[0], KM_USER0); + kaddr[buf->page_base + len] = '\0'; + kunmap_atomic(kaddr, KM_USER0); +} +EXPORT_SYMBOL(xdr_terminate_string); + void xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base, unsigned int len) -- cgit v1.2.3 From ba8e452a4fe64a51b74d43761e14d99f0666cc45 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 19 Oct 2010 19:58:49 -0400 Subject: SUNRPC: Add a helper function xdr_inline_peek We sometimes need to be able to read ahead in an xdr_stream without incrementing the current pointer position. Signed-off-by: Trond Myklebust --- net/sunrpc/xdr.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'net') diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index e0725d9d810..cd9e841e749 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -572,6 +572,27 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p) } EXPORT_SYMBOL_GPL(xdr_init_decode); +/** + * xdr_inline_peek - Allow read-ahead in the XDR data stream + * @xdr: pointer to xdr_stream struct + * @nbytes: number of bytes of data to decode + * + * Check if the input buffer is long enough to enable us to decode + * 'nbytes' more bytes of data starting at the current position. + * If so return the current pointer without updating the current + * pointer position. + */ +__be32 * xdr_inline_peek(struct xdr_stream *xdr, size_t nbytes) +{ + __be32 *p = xdr->p; + __be32 *q = p + XDR_QUADLEN(nbytes); + + if (unlikely(q > xdr->end || q < p)) + return NULL; + return p; +} +EXPORT_SYMBOL_GPL(xdr_inline_peek); + /** * xdr_inline_decode - Retrieve non-page XDR data to decode * @xdr: pointer to xdr_stream struct -- cgit v1.2.3 From 118df3d17f11733b294ea2cd988d56ee376ef9fd Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 24 Oct 2010 17:17:31 -0400 Subject: SUNRPC: After calling xprt_release(), we must restart from call_reserve Rob Leslie reports seeing the following Oops after his Kerberos session expired. BUG: unable to handle kernel NULL pointer dereference at 00000058 IP: [] rpcauth_refreshcred+0x11/0x12c [sunrpc] *pde = 00000000 Oops: 0000 [#1] last sysfs file: /sys/devices/platform/pc87360.26144/temp3_input Modules linked in: autofs4 authenc esp4 xfrm4_mode_transport ipt_LOG ipt_REJECT xt_limit xt_state ipt_REDIRECT xt_owner xt_HL xt_hl xt_tcpudp xt_mark cls_u32 cls_tcindex sch_sfq sch_htb sch_dsmark geodewdt deflate ctr twofish_generic twofish_i586 twofish_common camellia serpent blowfish cast5 cbc xcbc rmd160 sha512_generic sha1_generic hmac crypto_null af_key rpcsec_gss_krb5 nfsd exportfs nfs lockd fscache nfs_acl auth_rpcgss sunrpc ip_gre sit tunnel4 dummy ext3 jbd nf_nat_irc nf_conntrack_irc nf_nat_ftp nf_conntrack_ftp iptable_mangle iptable_nat nf_nat nf_conntrack_ipv4 nf_conntrack nf_defrag_ipv4 iptable_filter ip_tables x_tables pc8736x_gpio nsc_gpio pc87360 hwmon_vid loop aes_i586 aes_generic sha256_generic dm_crypt cs5535_gpio serio_raw cs5535_mfgpt hifn_795x des_generic geode_rng rng_core led_class ext4 mbcache jbd2 crc16 dm_mirror dm_region_hash dm_log dm_snapshot dm_mod sd_mod crc_t10dif ide_pci_generic cs5536 amd74xx ide_core pata_cs5536 ata_generic libata usb_storage via_rhine mii scsi_mod btrfs zlib_deflate crc32c libcrc32c [last unloaded: scsi_wait_scan] Pid: 12875, comm: sudo Not tainted 2.6.36-net5501 #1 / EIP: 0060:[] EFLAGS: 00010292 CPU: 0 EIP is at rpcauth_refreshcred+0x11/0x12c [sunrpc] EAX: 00000000 EBX: defb13a0 ECX: 00000006 EDX: e18683b8 ESI: defb13a0 EDI: 00000000 EBP: 00000000 ESP: de571d58 DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068 Process sudo (pid: 12875, ti=de570000 task=decd1430 task.ti=de570000) Stack: e186e008 00000000 defb13a0 0000000d deda6000 e1868f22 e196f12b defb13a0 <0> defb13d8 00000000 00000000 e186e0aa 00000000 defb13a0 de571dac 00000000 <0> e186956c de571e34 debea5c0 de571dc8 e186967a 00000000 debea5c0 de571e34 Call Trace: [] ? rpc_wake_up_next+0x114/0x11b [sunrpc] [] ? call_decode+0x24a/0x5af [sunrpc] [] ? nfs4_xdr_dec_access+0x0/0xa2 [nfs] [] ? __rpc_execute+0x62/0x17b [sunrpc] [] ? rpc_run_task+0x91/0x97 [sunrpc] [] ? rpc_call_sync+0x40/0x5b [sunrpc] [] ? nfs4_proc_access+0x10a/0x176 [nfs] [] ? nfs_do_access+0x2b1/0x2c0 [nfs] [] ? rpcauth_lookupcred+0x62/0x84 [sunrpc] [] ? nfs_permission+0xad/0x13b [nfs] [] ? exec_permission+0x15/0x4b [] ? link_path_walk+0x4f/0x456 [] ? path_walk+0x4c/0xa8 [] ? do_path_lookup+0x1f/0x68 [] ? user_path_at+0x37/0x5f [] ? handle_mm_fault+0x229/0x55b [] ? sys_faccessat+0x93/0x146 [] ? sys_access+0xf/0x13 [] ? syscall_call+0x7/0xb Code: 0f 94 c2 84 d2 74 09 8b 44 24 0c e8 6a e9 8b de 83 c4 14 89 d8 5b 5e 5f 5d c3 55 57 56 53 83 ec 1c fc 89 c6 8b 40 10 89 44 24 04 <8b> 58 58 85 db 0f 85 d4 00 00 00 0f b7 46 70 8b 56 20 89 c5 83 EIP: [] rpcauth_refreshcred+0x11/0x12c [sunrpc] SS:ESP 0068:de571d58 CR2: 0000000000000058 This appears to be caused by the function rpc_verify_header() first calling xprt_release(), then doing a call_refresh. If we release the transport slot, we should _always_ jump back to call_reserve before calling anything else. Signed-off-by: Trond Myklebust Cc: stable@kernel.org --- net/sunrpc/clnt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 2388d83b68f..3d28ae8a888 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1677,7 +1677,7 @@ rpc_verify_header(struct rpc_task *task) rpcauth_invalcred(task); /* Ensure we obtain a new XID! */ xprt_release(task); - task->tk_action = call_refresh; + task->tk_action = call_reserve; goto out_retry; case RPC_AUTH_BADCRED: case RPC_AUTH_BADVERF: -- cgit v1.2.3 From 9a84d38031c258a17bb39beed1e500eadee67407 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 24 Oct 2010 18:00:46 -0400 Subject: SUNRPC: Cleanup duplicate assignment in rpcauth_refreshcred Signed-off-by: Trond Myklebust --- net/sunrpc/auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 36cb66022a2..b457db034cc 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -595,7 +595,7 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, int rpcauth_refreshcred(struct rpc_task *task) { - struct rpc_cred *cred = task->tk_rqstp->rq_cred; + struct rpc_cred *cred; int err; cred = task->tk_rqstp->rq_cred; -- cgit v1.2.3