Linux NFS development
 help / color / mirror / Atom feed
* [PATCH 00/24] RPC server support rpcbind v4 plus additional clean ups
@ 2008-04-14 16:26 Chuck Lever
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
  0 siblings, 1 reply; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:26 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Hi Bruce, Trond -

This patch series provides some minor clean ups, and finishes with an
implementation of support for rpcbind version 4 registration.  Version 4
support can be entirely disabled in favor of legacy behavior with a kernel
build option, and the default is to use rpcbind version 2 when registering
kernel RPC services.

There are 24 patches in this series, but only a few are more than trivial and
hopefully fewer yet are controversial.  I've tried to split these so that
server side and client side changes are in separate patches.

It would be helpful for me if they could be considered for 2.6.26.

-- 
corporate:    <chuck dot lever at oracle dot com>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 01/24] NFS: Use NFSDBG_FILE for all fops
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
@ 2008-04-14 16:26   ` Chuck Lever
  2008-04-14 16:26   ` [PATCH 02/24] NFS: Fix trace debugging nits in write.c Chuck Lever
                     ` (23 subsequent siblings)
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:26 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Clean up: some fops use NFSDBG_FILE, some use NFSDBG_VFS.  Let's use
NFSDBG_FILE for all fops, and consistently report file names instead
of inode numbers.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 fs/nfs/dir.c    |   10 +++++----
 fs/nfs/direct.c |    4 ++--
 fs/nfs/file.c   |   60 +++++++++++++++++++++++++++++++++++--------------------
 3 files changed, 45 insertions(+), 29 deletions(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index b9f1a72..9f52a8c 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -134,7 +134,7 @@ nfs_opendir(struct inode *inode, struct file *filp)
 	struct dentry *dentry = filp->f_path.dentry;
 	int res;
 
-	dfprintk(VFS, "NFS: open dir(%s/%s)\n",
+	dfprintk(FILE, "NFS: open dir(%s/%s)\n",
 			dentry->d_parent->d_name.name,
 			dentry->d_name.name);
 
@@ -532,7 +532,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 	struct nfs_fattr fattr;
 	long		res;
 
-	dfprintk(VFS, "NFS: readdir(%s/%s) starting at cookie %Lu\n",
+	dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %Lu\n",
 			dentry->d_parent->d_name.name, dentry->d_name.name,
 			(long long)filp->f_pos);
 	nfs_inc_stats(inode, NFSIOS_VFSGETDENTS);
@@ -599,7 +599,7 @@ out:
 	unlock_kernel();
 	if (res > 0)
 		res = 0;
-	dfprintk(VFS, "NFS: readdir(%s/%s) returns %ld\n",
+	dfprintk(FILE, "NFS: readdir(%s/%s) returns %ld\n",
 			dentry->d_parent->d_name.name, dentry->d_name.name,
 			res);
 	return res;
@@ -610,7 +610,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
 	struct dentry *dentry = filp->f_path.dentry;
 	struct inode *inode = filp->f_path.dentry->d_inode;
 
-	dfprintk(VFS, "NFS: llseek dir(%s/%s, %Ld, %d)\n",
+	dfprintk(FILE, "NFS: llseek dir(%s/%s, %Ld, %d)\n",
 			dentry->d_parent->d_name.name,
 			dentry->d_name.name,
 			offset, origin);
@@ -641,7 +641,7 @@ out:
  */
 static int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync)
 {
-	dfprintk(VFS, "NFS: fsync dir(%s/%s) datasync %d\n",
+	dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d\n",
 			dentry->d_parent->d_name.name, dentry->d_name.name,
 			datasync);
 
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 16844f9..2724d19 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -870,7 +870,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
 	count = iov_length(iov, nr_segs);
 	nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count);
 
-	dprintk("nfs: direct read(%s/%s, %zd@%Ld)\n",
+	dfprintk(FILE, "NFS: direct read(%s/%s, %zd@%Ld)\n",
 		file->f_path.dentry->d_parent->d_name.name,
 		file->f_path.dentry->d_name.name,
 		count, (long long) pos);
@@ -927,7 +927,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
 	count = iov_length(iov, nr_segs);
 	nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count);
 
-	dfprintk(VFS, "nfs: direct write(%s/%s, %zd@%Ld)\n",
+	dfprintk(FILE, "NFS: direct write(%s/%s, %zd@%Ld)\n",
 		file->f_path.dentry->d_parent->d_name.name,
 		file->f_path.dentry->d_name.name,
 		count, (long long) pos);
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 03f00bd..a635457 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -120,7 +120,7 @@ nfs_file_open(struct inode *inode, struct file *filp)
 	struct dentry *dentry = filp->f_path.dentry;
 	int res;
 
-	dfprintk(VFS, "NFS: open file(%s/%s)\n",
+	dprintk("NFS: open file(%s/%s)\n",
 			dentry->d_parent->d_name.name,
 			dentry->d_name.name);
 
@@ -138,6 +138,12 @@ nfs_file_open(struct inode *inode, struct file *filp)
 static int
 nfs_file_release(struct inode *inode, struct file *filp)
 {
+	struct dentry *dentry = filp->f_path.dentry;
+
+	dprintk("NFS: release(%s/%s)\n",
+			dentry->d_parent->d_name.name,
+			dentry->d_name.name);
+
 	/* Ensure that dirty pages are flushed out with the right creds */
 	if (filp->f_mode & FMODE_WRITE)
 		nfs_wb_all(filp->f_path.dentry->d_inode);
@@ -177,7 +183,7 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
 {
 	struct dentry *dentry = filp->f_path.dentry;
 
-	dfprintk(VFS, "NFS: llseek file(%s/%s, %Ld, %d)\n",
+	dprintk("NFS: llseek file(%s/%s, %Ld, %d)\n",
 			dentry->d_parent->d_name.name,
 			dentry->d_name.name,
 			offset, origin);
@@ -219,16 +225,18 @@ static int nfs_do_fsync(struct nfs_open_context *ctx, struct inode *inode)
 
 /*
  * Flush all dirty pages, and check for write errors.
- *
  */
 static int
 nfs_file_flush(struct file *file, fl_owner_t id)
 {
 	struct nfs_open_context *ctx = nfs_file_open_context(file);
-	struct inode	*inode = file->f_path.dentry->d_inode;
+	struct dentry	*dentry = file->f_path.dentry;
+	struct inode	*inode = dentry->d_inode;
 	int		status;
 
-	dfprintk(VFS, "nfs: flush(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
+	dprintk("NFS: flush(%s/%s)\n",
+			dentry->d_parent->d_name.name,
+			dentry->d_name.name);
 
 	if ((file->f_mode & FMODE_WRITE) == 0)
 		return 0;
@@ -253,7 +261,7 @@ nfs_file_read(struct kiocb *iocb, const struct iovec *iov,
 	if (iocb->ki_filp->f_flags & O_DIRECT)
 		return nfs_file_direct_read(iocb, iov, nr_segs, pos);
 
-	dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n",
+	dprintk("NFS: read(%s/%s, %lu@%lu)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
 		(unsigned long) count, (unsigned long) pos);
 
@@ -273,7 +281,7 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos,
 	struct inode *inode = dentry->d_inode;
 	ssize_t res;
 
-	dfprintk(VFS, "nfs: splice_read(%s/%s, %lu@%Lu)\n",
+	dprintk("NFS: splice_read(%s/%s, %lu@%Lu)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
 		(unsigned long) count, (unsigned long long) *ppos);
 
@@ -290,7 +298,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
 	struct inode *inode = dentry->d_inode;
 	int	status;
 
-	dfprintk(VFS, "nfs: mmap(%s/%s)\n",
+	dprintk("NFS: mmap(%s/%s)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 
 	status = nfs_revalidate_mapping(inode, file->f_mapping);
@@ -313,7 +321,7 @@ nfs_file_fsync(struct file *file, struct dentry *dentry, int datasync)
 	struct nfs_open_context *ctx = nfs_file_open_context(file);
 	struct inode *inode = dentry->d_inode;
 
-	dfprintk(VFS, "NFS: fsync file(%s/%s) datasync %d\n",
+	dprintk("NFS: fsync file(%s/%s) datasync %d\n",
 			dentry->d_parent->d_name.name, dentry->d_name.name,
 			datasync);
 
@@ -487,9 +495,9 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
 	if (iocb->ki_filp->f_flags & O_DIRECT)
 		return nfs_file_direct_write(iocb, iov, nr_segs, pos);
 
-	dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%Ld)\n",
+	dprintk("NFS: write(%s/%s, %lu@%Ld)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
-		inode->i_ino, (unsigned long) count, (long long) pos);
+		(unsigned long) count, (long long) pos);
 
 	result = -EBUSY;
 	if (IS_SWAPFILE(inode))
@@ -640,12 +648,14 @@ out:
  */
 static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
 {
-	struct inode * inode = filp->f_mapping->host;
+	struct dentry *dentry = filp->f_path.dentry;
+	struct inode *inode = filp->f_mapping->host;
 
-	dprintk("NFS: nfs_lock(f=%s/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n",
-			inode->i_sb->s_id, inode->i_ino,
+	dprintk("NFS: lock(%s/%s, t=%x, fl=%x, r=%Ld:%Ld)\n",
+			dentry->d_parent->d_name.name, dentry->d_name.name,
 			fl->fl_type, fl->fl_flags,
 			(long long)fl->fl_start, (long long)fl->fl_end);
+
 	nfs_inc_stats(inode, NFSIOS_VFSLOCK);
 
 	/* No mandatory locks over NFS */
@@ -664,9 +674,10 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
  */
 static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
 {
-	dprintk("NFS: nfs_flock(f=%s/%ld, t=%x, fl=%x)\n",
-			filp->f_path.dentry->d_inode->i_sb->s_id,
-			filp->f_path.dentry->d_inode->i_ino,
+	struct dentry *dentry = filp->f_path.dentry;
+
+	dprintk("NFS: flock(%s/%s, t=%x, fl=%x)\n",
+			dentry->d_parent->d_name.name, dentry->d_name.name,
 			fl->fl_type, fl->fl_flags);
 
 	/*
@@ -689,12 +700,17 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
 	return do_setlk(filp, cmd, fl);
 }
 
+/*
+ * There is no protocol support for leases, so we have no way to implement
+ * them correctly in the face of opens by other clients.
+ */
 static int nfs_setlease(struct file *file, long arg, struct file_lock **fl)
 {
-	/*
-	 * There is no protocol support for leases, so we have no way
-	 * to implement them correctly in the face of opens by other
-	 * clients.
-	 */
+	struct dentry *dentry = file->f_path.dentry;
+
+	dprintk("NFS: setlease(%s/%s, arg=%ld)\n",
+			dentry->d_parent->d_name.name,
+			dentry->d_name.name, arg);
+
 	return -EINVAL;
 }


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 02/24] NFS: Fix trace debugging nits in write.c
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
  2008-04-14 16:26   ` [PATCH 01/24] NFS: Use NFSDBG_FILE for all fops Chuck Lever
@ 2008-04-14 16:26   ` Chuck Lever
  2008-04-14 16:27   ` [PATCH 03/24] SUNRPC: RPC server still uses 2.4 method for disabling TCP Nagle Chuck Lever
                     ` (22 subsequent siblings)
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:26 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Clean up.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 fs/nfs/write.c |   16 +++++++++-------
 1 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index bed6341..969658b 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -728,10 +728,10 @@ int nfs_updatepage(struct file *file, struct page *page,
 
 	nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE);
 
-	dprintk("NFS:      nfs_updatepage(%s/%s %d@%Ld)\n",
+	dprintk("NFS:       nfs_updatepage(%s/%s %d@%Ld)\n",
 		file->f_path.dentry->d_parent->d_name.name,
 		file->f_path.dentry->d_name.name, count,
-		(long long)(page_offset(page) +offset));
+		(long long)(page_offset(page) + offset));
 
 	/* If we're not using byte range locks, and we know the page
 	 * is up to date, it may be more efficient to extend the write
@@ -748,7 +748,7 @@ int nfs_updatepage(struct file *file, struct page *page,
 	status = nfs_writepage_setup(ctx, page, offset, count);
 	__set_page_dirty_nobuffers(page);
 
-        dprintk("NFS:      nfs_updatepage returns %d (isize %Ld)\n",
+	dprintk("NFS:       nfs_updatepage returns %d (isize %Ld)\n",
 			status, (long long)i_size_read(inode));
 	if (status < 0)
 		nfs_set_pageerror(page);
@@ -974,7 +974,8 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)
 	struct nfs_page		*req = data->req;
 	struct page		*page = req->wb_page;
 
-	dprintk("NFS: write (%s/%Ld %d@%Ld)",
+	dprintk("NFS: %5u write(%s/%Ld %d@%Ld)",
+		task->tk_pid,
 		req->wb_context->path.dentry->d_inode->i_sb->s_id,
 		(long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
 		req->wb_bytes,
@@ -1040,7 +1041,8 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata)
 		nfs_list_remove_request(req);
 		page = req->wb_page;
 
-		dprintk("NFS: write (%s/%Ld %d@%Ld)",
+		dprintk("NFS: %5u write (%s/%Ld %d@%Ld)",
+			task->tk_pid,
 			req->wb_context->path.dentry->d_inode->i_sb->s_id,
 			(long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
 			req->wb_bytes,
@@ -1114,7 +1116,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
 		static unsigned long    complain;
 
 		if (time_before(complain, jiffies)) {
-			dprintk("NFS: faulty NFS server %s:"
+			dprintk("NFS:       faulty NFS server %s:"
 				" (committed = %d) != (stable = %d)\n",
 				NFS_SERVER(data->inode)->nfs_client->cl_hostname,
 				resp->verf->committed, argp->stable);
@@ -1272,7 +1274,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
 		dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
 				BDI_RECLAIMABLE);
 
-		dprintk("NFS: commit (%s/%Ld %d@%Ld)",
+		dprintk("NFS:       commit (%s/%Ld %d@%Ld)",
 			req->wb_context->path.dentry->d_inode->i_sb->s_id,
 			(long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
 			req->wb_bytes,


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 03/24] SUNRPC: RPC server still uses 2.4 method for disabling TCP Nagle
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
  2008-04-14 16:26   ` [PATCH 01/24] NFS: Use NFSDBG_FILE for all fops Chuck Lever
  2008-04-14 16:26   ` [PATCH 02/24] NFS: Fix trace debugging nits in write.c Chuck Lever
@ 2008-04-14 16:27   ` Chuck Lever
       [not found]     ` <20080414162701.12741.10868.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
  2008-04-14 16:27   ` [PATCH 04/24] SUNRPC: Address potential buffer length overflow in svc_sendto Chuck Lever
                     ` (21 subsequent siblings)
  24 siblings, 1 reply; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:27 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Use the 2.6 method for disabling TCP Nagle in the kernel's RPC server.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 net/sunrpc/svcsock.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index c475977..6d4162b 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -38,6 +38,7 @@
 #include <net/checksum.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
+#include <net/tcp.h>
 #include <net/tcp_states.h>
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
@@ -1045,7 +1046,6 @@ void svc_cleanup_xprt_sock(void)
 static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
 {
 	struct sock	*sk = svsk->sk_sk;
-	struct tcp_sock *tp = tcp_sk(sk);
 
 	svc_xprt_init(&svc_tcp_class, &svsk->sk_xprt, serv);
 	set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
@@ -1063,7 +1063,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
 		svsk->sk_reclen = 0;
 		svsk->sk_tcplen = 0;
 
-		tp->nonagle = 1;        /* disable Nagle's algorithm */
+		tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
 
 		/* initialise setting must have enough space to
 		 * receive and respond to one request.


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 04/24] SUNRPC: Address potential buffer length overflow in svc_sendto
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (2 preceding siblings ...)
  2008-04-14 16:27   ` [PATCH 03/24] SUNRPC: RPC server still uses 2.4 method for disabling TCP Nagle Chuck Lever
@ 2008-04-14 16:27   ` Chuck Lever
       [not found]     ` <20080414162708.12741.71691.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
  2008-04-14 16:27   ` [PATCH 05/24] SUNRPC: Address potential buffer length overflow in svc_tcp_sendto Chuck Lever
                     ` (20 subsequent siblings)
  24 siblings, 1 reply; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:27 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Paranoia: Ensure a negative error value return from kernel_sendpage never
matches a large buffer length.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 net/sunrpc/svcsock.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 6d4162b..a8ae279 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -200,7 +200,7 @@ static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
 		flags = 0;
 	len = kernel_sendpage(sock, rqstp->rq_respages[0], 0,
 				  xdr->head[0].iov_len, flags);
-	if (len != xdr->head[0].iov_len)
+	if (len < 0 || len != xdr->head[0].iov_len)
 		goto out;
 	slen -= xdr->head[0].iov_len;
 	if (slen == 0)


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 05/24] SUNRPC: Address potential buffer length overflow in svc_tcp_sendto
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (3 preceding siblings ...)
  2008-04-14 16:27   ` [PATCH 04/24] SUNRPC: Address potential buffer length overflow in svc_sendto Chuck Lever
@ 2008-04-14 16:27   ` Chuck Lever
  2008-04-14 16:27   ` [PATCH 06/24] SUNRPC: Sanity check incoming UDP datagram lengths properly Chuck Lever
                     ` (19 subsequent siblings)
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:27 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Paranoia: Ensure a negative error value returned from svc_sendto()
doesn't match a large buffer length.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 net/sunrpc/svcsock.c |   24 ++++++++++++------------
 1 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index a8ae279..d077071 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -956,18 +956,18 @@ static int svc_tcp_sendto(struct svc_rqst *rqstp)
 		return -ENOTCONN;
 
 	sent = svc_sendto(rqstp, &rqstp->rq_res);
-	if (sent != xbufp->len) {
-		printk(KERN_NOTICE
-		       "rpc-srv/tcp: %s: %s %d when sending %d bytes "
-		       "- shutting down socket\n",
-		       rqstp->rq_xprt->xpt_server->sv_name,
-		       (sent<0)?"got error":"sent only",
-		       sent, xbufp->len);
-		set_bit(XPT_CLOSE, &rqstp->rq_xprt->xpt_flags);
-		svc_xprt_enqueue(rqstp->rq_xprt);
-		sent = -EAGAIN;
-	}
-	return sent;
+	if (sent > 0 && sent == xbufp->len)
+		return sent;
+
+	printk(KERN_NOTICE "%s: %s %d when sending %u bytes "
+		"- shutting down TCP socket\n",
+			rqstp->rq_xprt->xpt_server->sv_name,
+			(sent < 0) ? "got error" : "sent only",
+			sent, xbufp->len);
+
+	set_bit(XPT_CLOSE, &rqstp->rq_xprt->xpt_flags);
+	svc_xprt_enqueue(rqstp->rq_xprt);
+	return -EAGAIN;
 }
 
 /*


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 06/24] SUNRPC: Sanity check incoming UDP datagram lengths properly
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (4 preceding siblings ...)
  2008-04-14 16:27   ` [PATCH 05/24] SUNRPC: Address potential buffer length overflow in svc_tcp_sendto Chuck Lever
@ 2008-04-14 16:27   ` Chuck Lever
       [not found]     ` <20080414162723.12741.35500.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
  2008-04-14 16:27   ` [PATCH 07/24] SUNRPC: Update RPC server's TCP record marker decoder Chuck Lever
                     ` (18 subsequent siblings)
  24 siblings, 1 reply; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:27 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Clean up: ensure svc_udp_recvfrom() is getting at least a full UDP header
to avoid potential negative intermediate values.

A similar sanity check is already used in the RPC client.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 net/sunrpc/svcsock.c |   20 +++++++++++++-------
 1 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index d077071..de29e7f 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -431,6 +431,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
 	} buffer;
 	struct cmsghdr *cmh = &buffer.hdr;
 	int		err, len;
+	unsigned int	bytes;
 	struct msghdr msg = {
 		.msg_name = svc_addr(rqstp),
 		.msg_control = cmh,
@@ -484,8 +485,13 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
 	 */
 	svc_xprt_received(&svsk->sk_xprt);
 
-	len  = skb->len - sizeof(struct udphdr);
-	rqstp->rq_arg.len = len;
+	if (skb->len < sizeof(struct udphdr)) {
+		dprintk("svc: bad UDP datagram length: %u\n", skb->len);
+		skb_free_datagram(svsk->sk_sk, skb);
+		return 0;
+	}
+	bytes = skb->len - sizeof(struct udphdr);
+	rqstp->rq_arg.len = bytes;
 
 	rqstp->rq_prot = IPPROTO_UDP;
 
@@ -515,7 +521,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
 		/* we can use it in-place */
 		rqstp->rq_arg.head[0].iov_base = skb->data +
 			sizeof(struct udphdr);
-		rqstp->rq_arg.head[0].iov_len = len;
+		rqstp->rq_arg.head[0].iov_len = bytes;
 		if (skb_checksum_complete(skb)) {
 			skb_free_datagram(svsk->sk_sk, skb);
 			return 0;
@@ -524,12 +530,12 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
 	}
 
 	rqstp->rq_arg.page_base = 0;
-	if (len <= rqstp->rq_arg.head[0].iov_len) {
-		rqstp->rq_arg.head[0].iov_len = len;
+	if (bytes <= rqstp->rq_arg.head[0].iov_len) {
+		rqstp->rq_arg.head[0].iov_len = bytes;
 		rqstp->rq_arg.page_len = 0;
 		rqstp->rq_respages = rqstp->rq_pages+1;
 	} else {
-		rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
+		rqstp->rq_arg.page_len = bytes - rqstp->rq_arg.head[0].iov_len;
 		rqstp->rq_respages = rqstp->rq_pages + 1 +
 			DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE);
 	}
@@ -537,7 +543,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
 	if (serv->sv_stats)
 		serv->sv_stats->netudpcnt++;
 
-	return len;
+	return bytes;
 }
 
 static int


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 07/24] SUNRPC:  Update RPC server's TCP record marker decoder
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (5 preceding siblings ...)
  2008-04-14 16:27   ` [PATCH 06/24] SUNRPC: Sanity check incoming UDP datagram lengths properly Chuck Lever
@ 2008-04-14 16:27   ` Chuck Lever
       [not found]     ` <20080414162730.12741.97124.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
  2008-04-14 16:27   ` [PATCH 08/24] SUNRPC: Use unsigned index when looping over arrays Chuck Lever
                     ` (17 subsequent siblings)
  24 siblings, 1 reply; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:27 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Clean up: Update the RPC server's TCP record marker decoder to match the
constructs used by the RPC client's TCP socket transport.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 include/linux/sunrpc/svcsock.h |    4 ++--
 net/sunrpc/svcsock.c           |   24 ++++++++++++------------
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 206f092..8cff696 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -26,8 +26,8 @@ struct svc_sock {
 	void			(*sk_owspace)(struct sock *);
 
 	/* private TCP part */
-	int			sk_reclen;	/* length of record */
-	int			sk_tcplen;	/* current read length */
+	u32			sk_reclen;	/* length of record */
+	u32			sk_tcplen;	/* current read length */
 };
 
 /*
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index de29e7f..51357a3 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -46,6 +46,7 @@
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/msg_prot.h>
 #include <linux/sunrpc/svcsock.h>
 #include <linux/sunrpc/stats.h>
 
@@ -829,8 +830,8 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
 	 * the next four bytes. Otherwise try to gobble up as much as
 	 * possible up to the complete record length.
 	 */
-	if (svsk->sk_tcplen < 4) {
-		unsigned long	want = 4 - svsk->sk_tcplen;
+	if (svsk->sk_tcplen < sizeof(rpc_fraghdr)) {
+		int		want = sizeof(rpc_fraghdr) - svsk->sk_tcplen;
 		struct kvec	iov;
 
 		iov.iov_base = ((char *) &svsk->sk_reclen) + svsk->sk_tcplen;
@@ -840,32 +841,31 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
 		svsk->sk_tcplen += len;
 
 		if (len < want) {
-			dprintk("svc: short recvfrom while reading record length (%d of %lu)\n",
-				len, want);
+			dprintk("svc: short recvfrom while reading record "
+				"length (%d of %d)\n", len, want);
 			svc_xprt_received(&svsk->sk_xprt);
 			return -EAGAIN; /* record header not complete */
 		}
 
 		svsk->sk_reclen = ntohl(svsk->sk_reclen);
-		if (!(svsk->sk_reclen & 0x80000000)) {
+		if (!(svsk->sk_reclen & RPC_LAST_STREAM_FRAGMENT)) {
 			/* FIXME: technically, a record can be fragmented,
 			 *  and non-terminal fragments will not have the top
 			 *  bit set in the fragment length header.
 			 *  But apparently no known nfs clients send fragmented
 			 *  records. */
 			if (net_ratelimit())
-				printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx"
-				       " (non-terminal)\n",
-				       (unsigned long) svsk->sk_reclen);
+				printk(KERN_NOTICE "RPC: multiple fragments "
+					"per record not supported\n");
 			goto err_delete;
 		}
-		svsk->sk_reclen &= 0x7fffffff;
+		svsk->sk_reclen &= RPC_FRAGMENT_SIZE_MASK;
 		dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen);
 		if (svsk->sk_reclen > serv->sv_max_mesg) {
 			if (net_ratelimit())
-				printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx"
-				       " (large)\n",
-				       (unsigned long) svsk->sk_reclen);
+				printk(KERN_NOTICE "RPC: "
+					"fragment too large: 0x%08lx\n",
+					(unsigned long)svsk->sk_reclen);
 			goto err_delete;
 		}
 	}


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 08/24] SUNRPC: Use unsigned index when looping over arrays
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (6 preceding siblings ...)
  2008-04-14 16:27   ` [PATCH 07/24] SUNRPC: Update RPC server's TCP record marker decoder Chuck Lever
@ 2008-04-14 16:27   ` Chuck Lever
  2008-04-14 16:27   ` [PATCH 09/24] " Chuck Lever
                     ` (16 subsequent siblings)
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:27 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Clean up: Suppress a handful of harmless compiler warnings in the RPC
client related to array indices.

ARRAY_SIZE() returns a size_t, so use unsigned type for a loop index when
looping over arrays.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 net/sunrpc/rpc_pipe.c |    2 +-
 net/sunrpc/sched.c    |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 1b395a4..5209444 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -529,7 +529,7 @@ static void rpc_depopulate(struct dentry *parent,
 	struct inode *dir = parent->d_inode;
 	struct list_head *pos, *next;
 	struct dentry *dentry, *dvec[10];
-	int n = 0;
+	unsigned int n = 0;
 
 	mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD);
 repeat:
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 63fe132..01fc7b8 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -222,7 +222,7 @@ static inline void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue)
 
 static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, unsigned char nr_queues)
 {
-	int i;
+	unsigned int i;
 
 	spin_lock_init(&queue->lock);
 	for (i = 0; i < ARRAY_SIZE(queue->tasks); i++)


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 09/24] SUNRPC: Use unsigned index when looping over arrays
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (7 preceding siblings ...)
  2008-04-14 16:27   ` [PATCH 08/24] SUNRPC: Use unsigned index when looping over arrays Chuck Lever
@ 2008-04-14 16:27   ` Chuck Lever
       [not found]     ` <20080414162745.12741.37176.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
  2008-04-14 16:27   ` [PATCH 10/24] SUNRPC: Use unsigned loop and array index in svc_init_buffer() Chuck Lever
                     ` (15 subsequent siblings)
  24 siblings, 1 reply; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:27 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Clean up: Suppress a harmless compiler warning in the RPC server related
to array indices.

ARRAY_SIZE() returns a size_t, so use unsigned type for a loop index when
looping over arrays.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 net/sunrpc/svc.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index a290e15..c1e763b 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -528,8 +528,9 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
 static void
 svc_release_buffer(struct svc_rqst *rqstp)
 {
-	int i;
-	for (i=0; i<ARRAY_SIZE(rqstp->rq_pages); i++)
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++)
 		if (rqstp->rq_pages[i])
 			put_page(rqstp->rq_pages[i]);
 }


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 10/24] SUNRPC: Use unsigned loop and array index in svc_init_buffer()
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (8 preceding siblings ...)
  2008-04-14 16:27   ` [PATCH 09/24] " Chuck Lever
@ 2008-04-14 16:27   ` Chuck Lever
       [not found]     ` <20080414162752.12741.15628.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
  2008-04-14 16:28   ` [PATCH 11/24] SUNRPC: Remove obsolete messages during transport connect Chuck Lever
                     ` (14 subsequent siblings)
  24 siblings, 1 reply; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:27 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Clean up: Suppress a harmless compiler warning.

Index rq_pages[] with an unsigned type.  Make "pages" unsigned as well,
as it never represents a value less than zero.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 net/sunrpc/svc.c |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index c1e763b..86a5b56 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -504,8 +504,7 @@ EXPORT_SYMBOL(svc_destroy);
 static int
 svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
 {
-	int pages;
-	int arghi;
+	unsigned int pages, arghi;
 
 	pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply.
 				       * We assume one is at most one page
@@ -519,7 +518,7 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
 		rqstp->rq_pages[arghi++] = p;
 		pages--;
 	}
-	return ! pages;
+	return pages == 0;
 }
 
 /*


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 11/24] SUNRPC: Remove obsolete messages during transport connect
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (9 preceding siblings ...)
  2008-04-14 16:27   ` [PATCH 10/24] SUNRPC: Use unsigned loop and array index in svc_init_buffer() Chuck Lever
@ 2008-04-14 16:28   ` Chuck Lever
  2008-04-14 16:28   ` [PATCH 12/24] SUNRPC: More useful debugging output for rpcb client Chuck Lever
                     ` (13 subsequent siblings)
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:28 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Recent changes to the RPC client's transport connect logic make connect
status values ECONNREFUSED and ECONNRESET impossible.

Clean up xprt_connect_status() to account for these changes.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 net/sunrpc/xprt.c |    8 +-------
 1 files changed, 1 insertions(+), 7 deletions(-)

diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index d5553b8..4b1dca0 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -664,7 +664,7 @@ static void xprt_connect_status(struct rpc_task *task)
 {
 	struct rpc_xprt	*xprt = task->tk_xprt;
 
-	if (task->tk_status >= 0) {
+	if (task->tk_status == 0) {
 		xprt->stat.connect_count++;
 		xprt->stat.connect_time += (long)jiffies - xprt->stat.connect_start;
 		dprintk("RPC: %5u xprt_connect_status: connection established\n",
@@ -673,12 +673,6 @@ static void xprt_connect_status(struct rpc_task *task)
 	}
 
 	switch (task->tk_status) {
-	case -ECONNREFUSED:
-	case -ECONNRESET:
-		dprintk("RPC: %5u xprt_connect_status: server %s refused "
-				"connection\n", task->tk_pid,
-				task->tk_client->cl_server);
-		break;
 	case -ENOTCONN:
 		dprintk("RPC: %5u xprt_connect_status: connection broken\n",
 				task->tk_pid);


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 12/24] SUNRPC: More useful debugging output for rpcb client
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (10 preceding siblings ...)
  2008-04-14 16:28   ` [PATCH 11/24] SUNRPC: Remove obsolete messages during transport connect Chuck Lever
@ 2008-04-14 16:28   ` Chuck Lever
  2008-04-14 16:28   ` [PATCH 13/24] SUNRPC: Document some naked integers in rpcbind client Chuck Lever
                     ` (12 subsequent siblings)
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:28 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Clean up dprintk's in rpcb client's XDR decoder functions.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 net/sunrpc/rpcb_clnt.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 3164a08..904b1f5 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -439,7 +439,7 @@ static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p,
 			       unsigned short *portp)
 {
 	*portp = (unsigned short) ntohl(*p++);
-	dprintk("RPC:      rpcb_decode_getport result %u\n",
+	dprintk("RPC:       rpcb_decode_getport result %u\n",
 			*portp);
 	return 0;
 }
@@ -448,8 +448,8 @@ static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
 			   unsigned int *boolp)
 {
 	*boolp = (unsigned int) ntohl(*p++);
-	dprintk("RPC:      rpcb_decode_set result %u\n",
-			*boolp);
+	dprintk("RPC:       rpcb_decode_set: call %s\n",
+			(*boolp ? "succeeded" : "failed"));
 	return 0;
 }
 


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 13/24] SUNRPC: Document some naked integers in rpcbind client
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (11 preceding siblings ...)
  2008-04-14 16:28   ` [PATCH 12/24] SUNRPC: More useful debugging output for rpcb client Chuck Lever
@ 2008-04-14 16:28   ` Chuck Lever
  2008-04-14 16:28   ` [PATCH 14/24] SUNRPC: Use correct XDR encoding procedure for rpcbind SET/UNSET Chuck Lever
                     ` (11 subsequent siblings)
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:28 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Clean up: Replace naked integers that represent rpcbind protocol versions.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 net/sunrpc/rpcb_clnt.c |   49 +++++++++++++++++++++++++++++++++++-------------
 1 files changed, 36 insertions(+), 13 deletions(-)

diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 904b1f5..d852b2e 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -32,6 +32,10 @@
 #define RPCBIND_PROGRAM		(100000u)
 #define RPCBIND_PORT		(111u)
 
+#define RPCBVERS_2		(2u)
+#define RPCBVERS_3		(3u)
+#define RPCBVERS_4		(4u)
+
 enum {
 	RPCBPROC_NULL,
 	RPCBPROC_SET,
@@ -82,7 +86,7 @@ static struct rpc_procinfo rpcb_procedures2[];
 static struct rpc_procinfo rpcb_procedures3[];
 
 struct rpcb_info {
-	int			rpc_vers;
+	u32			rpc_vers;
 	struct rpc_procinfo *	rpc_proc;
 };
 
@@ -177,7 +181,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
 			prog, vers, prot, port);
 
 	rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin,
-				sizeof(sin), XPRT_TRANSPORT_UDP, 2, 1);
+				sizeof(sin), XPRT_TRANSPORT_UDP, RPCBVERS_2, 1);
 	if (IS_ERR(rpcb_clnt))
 		return PTR_ERR(rpcb_clnt);
 
@@ -227,7 +231,7 @@ int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot)
 		__FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
 
 	rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
-				sizeof(*sin), prot, 2, 0);
+				sizeof(*sin), prot, RPCBVERS_2, 0);
 	if (IS_ERR(rpcb_clnt))
 		return PTR_ERR(rpcb_clnt);
 
@@ -589,35 +593,54 @@ static struct rpc_procinfo rpcb_procedures4[] = {
 
 static struct rpcb_info rpcb_next_version[] = {
 #ifdef CONFIG_SUNRPC_BIND34
-	{ 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] },
-	{ 3, &rpcb_procedures3[RPCBPROC_GETADDR] },
+	{
+		.rpc_vers	= RPCBVERS_4,
+		.rpc_proc	= &rpcb_procedures4[RPCBPROC_GETVERSADDR],
+	},
+	{
+		.rpc_vers	= RPCBVERS_3,
+		.rpc_proc	= &rpcb_procedures3[RPCBPROC_GETADDR],
+	},
 #endif
-	{ 2, &rpcb_procedures2[RPCBPROC_GETPORT] },
-	{ 0, NULL },
+	{
+		.rpc_vers	= RPCBVERS_2,
+		.rpc_proc	= &rpcb_procedures2[RPCBPROC_GETPORT],
+	},
+	{
+		.rpc_proc	= NULL,
+	},
 };
 
 static struct rpcb_info rpcb_next_version6[] = {
 #ifdef CONFIG_SUNRPC_BIND34
-	{ 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] },
-	{ 3, &rpcb_procedures3[RPCBPROC_GETADDR] },
+	{
+		.rpc_vers	= RPCBVERS_4,
+		.rpc_proc	= &rpcb_procedures4[RPCBPROC_GETVERSADDR],
+	},
+	{
+		.rpc_vers	= RPCBVERS_3,
+		.rpc_proc	= &rpcb_procedures3[RPCBPROC_GETADDR],
+	},
 #endif
-	{ 0, NULL },
+	{
+		.rpc_proc	= NULL,
+	},
 };
 
 static struct rpc_version rpcb_version2 = {
-	.number		= 2,
+	.number		= RPCBVERS_2,
 	.nrprocs	= RPCB_HIGHPROC_2,
 	.procs		= rpcb_procedures2
 };
 
 static struct rpc_version rpcb_version3 = {
-	.number		= 3,
+	.number		= RPCBVERS_3,
 	.nrprocs	= RPCB_HIGHPROC_3,
 	.procs		= rpcb_procedures3
 };
 
 static struct rpc_version rpcb_version4 = {
-	.number		= 4,
+	.number		= RPCBVERS_4,
 	.nrprocs	= RPCB_HIGHPROC_4,
 	.procs		= rpcb_procedures4
 };


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 14/24] SUNRPC: Use correct XDR encoding procedure for rpcbind SET/UNSET
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (12 preceding siblings ...)
  2008-04-14 16:28   ` [PATCH 13/24] SUNRPC: Document some naked integers in rpcbind client Chuck Lever
@ 2008-04-14 16:28   ` Chuck Lever
  2008-04-14 16:28   ` [PATCH 15/24] SUNRPC: Introduce a specific rpcb_create for contacting localhost Chuck Lever
                     ` (10 subsequent siblings)
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:28 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

The rpcbind versions 3 and 4 SET and UNSET procedures use the same
arguments as the GETADDR procedure.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 net/sunrpc/rpcb_clnt.c |   12 ++++++++----
 1 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index d852b2e..18e677c 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -425,6 +425,10 @@ static void rpcb_getport_done(struct rpc_task *child, void *data)
 	rpcb_wake_rpcbind_waiters(xprt, status);
 }
 
+/*
+ * XDR functions for rpcbind
+ */
+
 static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p,
 			       struct rpcbind_args *rpcb)
 {
@@ -580,14 +584,14 @@ static struct rpc_procinfo rpcb_procedures2[] = {
 };
 
 static struct rpc_procinfo rpcb_procedures3[] = {
-	PROC(SET,		mapping,	set),
-	PROC(UNSET,		mapping,	set),
+	PROC(SET,		getaddr,	set),
+	PROC(UNSET,		getaddr,	set),
 	PROC(GETADDR,		getaddr,	getaddr),
 };
 
 static struct rpc_procinfo rpcb_procedures4[] = {
-	PROC(SET,		mapping,	set),
-	PROC(UNSET,		mapping,	set),
+	PROC(SET,		getaddr,	set),
+	PROC(UNSET,		getaddr,	set),
 	PROC(GETVERSADDR,	getaddr,	getaddr),
 };
 


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 15/24] SUNRPC: Introduce a specific rpcb_create for contacting localhost
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (13 preceding siblings ...)
  2008-04-14 16:28   ` [PATCH 14/24] SUNRPC: Use correct XDR encoding procedure for rpcbind SET/UNSET Chuck Lever
@ 2008-04-14 16:28   ` Chuck Lever
  2008-04-14 16:28   ` [PATCH 16/24] SUNRPC: None of rpcb_create's callers wants a privileged ephemeral port Chuck Lever
                     ` (9 subsequent siblings)
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:28 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Add rpcb_create_local() for use by rpcb_register() and upcoming IPv6
registration functions.  Ensure any errors encountered by
rpcb_create_local() are properly reported.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 net/sunrpc/rpcb_clnt.c |   42 +++++++++++++++++++++++++++++++-----------
 1 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 18e677c..9a92baa 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -112,6 +112,29 @@ static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status)
 	rpc_wake_up_status(&xprt->binding, status);
 }
 
+static const struct sockaddr_in rpcb_inaddr_loopback = {
+	.sin_family		= AF_INET,
+	.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),
+	.sin_port		= htons(RPCBIND_PORT),
+};
+
+static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr,
+					  size_t addrlen, u32 version)
+{
+	struct rpc_create_args args = {
+		.protocol	= XPRT_TRANSPORT_UDP,
+		.address	= addr,
+		.addrsize	= addrlen,
+		.servername	= "localhost",
+		.program	= &rpcb_program,
+		.version	= version,
+		.authflavor	= RPC_AUTH_UNIX,
+		.flags		= RPC_CLNT_CREATE_NOPING,
+	};
+
+	return rpc_create(&args);
+}
+
 static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
 				    size_t salen, int proto, u32 version,
 				    int privileged)
@@ -157,10 +180,6 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
  */
 int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
 {
-	struct sockaddr_in sin = {
-		.sin_family		= AF_INET,
-		.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),
-	};
 	struct rpcbind_args map = {
 		.r_prog		= prog,
 		.r_vers		= vers,
@@ -180,14 +199,15 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
 			"rpcbind\n", (port ? "" : "un"),
 			prog, vers, prot, port);
 
-	rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin,
-				sizeof(sin), XPRT_TRANSPORT_UDP, RPCBVERS_2, 1);
-	if (IS_ERR(rpcb_clnt))
-		return PTR_ERR(rpcb_clnt);
+	rpcb_clnt = rpcb_create_local((struct sockaddr *)&rpcb_inaddr_loopback,
+					sizeof(rpcb_inaddr_loopback),
+					RPCBVERS_2);
+	if (!IS_ERR(rpcb_clnt)) {
+		error = rpc_call_sync(rpcb_clnt, &msg, 0);
+		rpc_shutdown_client(rpcb_clnt);
+	} else
+		error = PTR_ERR(rpcb_clnt);
 
-	error = rpc_call_sync(rpcb_clnt, &msg, 0);
-
-	rpc_shutdown_client(rpcb_clnt);
 	if (error < 0)
 		printk(KERN_WARNING "RPC: failed to contact local rpcbind "
 				"server (errno %d).\n", -error);


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 16/24] SUNRPC: None of rpcb_create's callers wants a privileged ephemeral port
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (14 preceding siblings ...)
  2008-04-14 16:28   ` [PATCH 15/24] SUNRPC: Introduce a specific rpcb_create for contacting localhost Chuck Lever
@ 2008-04-14 16:28   ` Chuck Lever
  2008-04-14 16:28   ` [PATCH 17/24] SUNRPC: Refactor rpcb_register to make rpcbindv4 support easier Chuck Lever
                     ` (8 subsequent siblings)
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:28 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Clean up: Now that rpcb_register has it's own rpcb_create routine, none
of rpcb_create's current callers needs a privileged ephemeral port.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 net/sunrpc/rpcb_clnt.c |   12 +++++-------
 1 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 9a92baa..8590f4a 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -136,8 +136,7 @@ static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr,
 }
 
 static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
-				    size_t salen, int proto, u32 version,
-				    int privileged)
+				    size_t salen, int proto, u32 version)
 {
 	struct rpc_create_args args = {
 		.protocol	= proto,
@@ -147,7 +146,8 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
 		.program	= &rpcb_program,
 		.version	= version,
 		.authflavor	= RPC_AUTH_UNIX,
-		.flags		= RPC_CLNT_CREATE_NOPING,
+		.flags		= (RPC_CLNT_CREATE_NOPING |
+					RPC_CLNT_CREATE_NONPRIVPORT),
 	};
 
 	switch (srvaddr->sa_family) {
@@ -161,8 +161,6 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
 		return NULL;
 	}
 
-	if (!privileged)
-		args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
 	return rpc_create(&args);
 }
 
@@ -251,7 +249,7 @@ int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot)
 		__FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
 
 	rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
-				sizeof(*sin), prot, RPCBVERS_2, 0);
+				sizeof(*sin), prot, RPCBVERS_2);
 	if (IS_ERR(rpcb_clnt))
 		return PTR_ERR(rpcb_clnt);
 
@@ -361,7 +359,7 @@ void rpcb_getport_async(struct rpc_task *task)
 		task->tk_pid, __FUNCTION__, bind_version);
 
 	rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot,
-				bind_version, 0);
+				bind_version);
 	if (IS_ERR(rpcb_clnt)) {
 		status = PTR_ERR(rpcb_clnt);
 		dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 17/24] SUNRPC: Refactor rpcb_register to make rpcbindv4 support easier
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (15 preceding siblings ...)
  2008-04-14 16:28   ` [PATCH 16/24] SUNRPC: None of rpcb_create's callers wants a privileged ephemeral port Chuck Lever
@ 2008-04-14 16:28   ` Chuck Lever
  2008-04-14 16:28   ` [PATCH 18/24] SUNRPC: introduce new task flag that fails requests on xprt disconnect Chuck Lever
                     ` (7 subsequent siblings)
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:28 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

rpcbindv4 registration will reuse part of rpcb_register, so just split it out
into a separate function now.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 net/sunrpc/rpcb_clnt.c |   48 ++++++++++++++++++++++++++++++------------------
 1 files changed, 30 insertions(+), 18 deletions(-)

diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 8590f4a..eb2bffe 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -164,6 +164,30 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
 	return rpc_create(&args);
 }
 
+static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
+			      u32 version, struct rpc_message *msg,
+			      int *result)
+{
+	struct rpc_clnt *rpcb_clnt;
+	int error = 0;
+
+	*result = 0;
+
+	rpcb_clnt = rpcb_create_local(addr, addrlen, version);
+	if (!IS_ERR(rpcb_clnt)) {
+		error = rpc_call_sync(rpcb_clnt, msg, 0);
+		rpc_shutdown_client(rpcb_clnt);
+	} else
+		error = PTR_ERR(rpcb_clnt);
+
+	if (error < 0)
+		printk(KERN_WARNING "RPC: failed to contact local rpcbind "
+				"server (errno %d).\n", -error);
+	dprintk("RPC:       registration status %d/%d\n", error, *result);
+
+	return error;
+}
+
 /**
  * rpcb_register - set or unset a port registration with the local rpcbind svc
  * @prog: RPC program number to bind
@@ -185,33 +209,21 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
 		.r_port		= port,
 	};
 	struct rpc_message msg = {
-		.rpc_proc	= &rpcb_procedures2[port ?
-					RPCBPROC_SET : RPCBPROC_UNSET],
 		.rpc_argp	= &map,
 		.rpc_resp	= okay,
 	};
-	struct rpc_clnt *rpcb_clnt;
-	int error = 0;
 
 	dprintk("RPC:       %sregistering (%u, %u, %d, %u) with local "
 			"rpcbind\n", (port ? "" : "un"),
 			prog, vers, prot, port);
 
-	rpcb_clnt = rpcb_create_local((struct sockaddr *)&rpcb_inaddr_loopback,
-					sizeof(rpcb_inaddr_loopback),
-					RPCBVERS_2);
-	if (!IS_ERR(rpcb_clnt)) {
-		error = rpc_call_sync(rpcb_clnt, &msg, 0);
-		rpc_shutdown_client(rpcb_clnt);
-	} else
-		error = PTR_ERR(rpcb_clnt);
+	msg.rpc_proc = &rpcb_procedures2[RPCBPROC_UNSET];
+	if (port)
+		msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET];
 
-	if (error < 0)
-		printk(KERN_WARNING "RPC: failed to contact local rpcbind "
-				"server (errno %d).\n", -error);
-	dprintk("RPC:       registration status %d/%d\n", error, *okay);
-
-	return error;
+	return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
+					sizeof(rpcb_inaddr_loopback),
+					RPCBVERS_2, &msg, okay);
 }
 
 /**


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 18/24] SUNRPC: introduce new task flag that fails requests on xprt disconnect
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (16 preceding siblings ...)
  2008-04-14 16:28   ` [PATCH 17/24] SUNRPC: Refactor rpcb_register to make rpcbindv4 support easier Chuck Lever
@ 2008-04-14 16:28   ` Chuck Lever
  2008-04-14 16:28   ` [PATCH 19/24] SUNRPC: Quickly detect missing portmapper during RPC service registration Chuck Lever
                     ` (6 subsequent siblings)
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:28 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Introduce a new RPC client capability that allows RPC consumers to specify
that if a connection cannot be established to the remote RPC service, a
submitted request should fail immediately.

Useful for in-kernel RPC applications that want to connect and do just one
or a handful of idempotent requests, but don't want any long waits if the
remote service is not available.

No, Tom, I'm not going to call it "squishy."  :-)

Note that because the UDP transport uses an unconnected socket, this new
flag is a no-op.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 include/linux/sunrpc/sched.h |    2 ++
 net/sunrpc/clnt.c            |    2 ++
 2 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index 7190d7a..54d0f3e 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -137,6 +137,7 @@ struct rpc_task_setup {
 #define RPC_TASK_DYNAMIC	0x0080		/* task was kmalloc'ed */
 #define RPC_TASK_KILLED		0x0100		/* task was killed */
 #define RPC_TASK_SOFT		0x0200		/* Use soft timeouts */
+#define RPC_TASK_ONESHOT	0x0400		/* fail if can't connect */
 
 #define RPC_IS_ASYNC(t)		((t)->tk_flags & RPC_TASK_ASYNC)
 #define RPC_IS_SWAPPER(t)	((t)->tk_flags & RPC_TASK_SWAPPER)
@@ -144,6 +145,7 @@ struct rpc_task_setup {
 #define RPC_ASSASSINATED(t)	((t)->tk_flags & RPC_TASK_KILLED)
 #define RPC_DO_CALLBACK(t)	((t)->tk_callback != NULL)
 #define RPC_IS_SOFT(t)		((t)->tk_flags & RPC_TASK_SOFT)
+#define RPC_IS_ONESHOT(t)	((t)->tk_flags & RPC_TASK_ONESHOT)
 
 #define RPC_TASK_RUNNING	0
 #define RPC_TASK_QUEUED		1
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index dd39a39..a8bb701 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -1016,6 +1016,8 @@ call_connect_status(struct rpc_task *task)
 
 	switch (status) {
 	case -ENOTCONN:
+		if (RPC_IS_ONESHOT(task))
+			break;
 	case -EAGAIN:
 		task->tk_action = call_bind;
 		if (!RPC_IS_SOFT(task))


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 19/24] SUNRPC: Quickly detect missing portmapper during RPC service registration
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (17 preceding siblings ...)
  2008-04-14 16:28   ` [PATCH 18/24] SUNRPC: introduce new task flag that fails requests on xprt disconnect Chuck Lever
@ 2008-04-14 16:28   ` Chuck Lever
  2008-04-14 16:29   ` [PATCH 20/24] SUNRPC: Support registering IPv6 interfaces with local rpcbind daemon Chuck Lever
                     ` (5 subsequent siblings)
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:28 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Currently the in-kernel RPC server uses an unconnected UDP socket to
contact the local user-space portmapper daemon because UDP is less
overhead than TCP.  However, attempting to register or unregister a
local RPC service with a portmapper that isn't listening for requests
results in a long timeout wait (35 seconds per request, by my
calculations).

Using TCP, the absence of a listener results in an immediate ECONNREFUSED.
Setting the ONESHOT flag causes the RPC client to fail RPC requests as soon
as this occurs.

Therefore, this patch changes rpcb_register() to use TCP to contact the
local portmapper.  Starting up in-kernel RPC services should no longer
hang if there is no local portmapper listening for requests.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 net/sunrpc/rpcb_clnt.c |   22 ++++++++++++++++++++--
 1 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index eb2bffe..4a85bf5 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -67,6 +67,12 @@ enum {
 #define RPCB_OWNER_STRING	"rpcb"
 #define RPCB_MAXOWNERLEN	sizeof(RPCB_OWNER_STRING)
 
+/*
+ * Number of seconds before timing out a registration request
+ * to our local user space rpcbind daemon.
+ */
+#define RPCB_REGISTER_TO_SECS	(10UL)
+
 static void			rpcb_getport_done(struct rpc_task *, void *);
 static struct rpc_program	rpcb_program;
 
@@ -118,14 +124,26 @@ static const struct sockaddr_in rpcb_inaddr_loopback = {
 	.sin_port		= htons(RPCBIND_PORT),
 };
 
+/*
+ * TCP is always used to contact the local rpcbind daemon because we
+ * get an immediate indication of whether there is a remote listener
+ * when a connection is attempted.
+ */
+static const struct rpc_timeout rpcb_local_tcp_timeout = {
+	.to_initval		= RPCB_REGISTER_TO_SECS * HZ,
+	.to_maxval		= RPCB_REGISTER_TO_SECS * HZ,
+	.to_retries		= 0,
+};
+
 static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr,
 					  size_t addrlen, u32 version)
 {
 	struct rpc_create_args args = {
-		.protocol	= XPRT_TRANSPORT_UDP,
+		.protocol	= XPRT_TRANSPORT_TCP,
 		.address	= addr,
 		.addrsize	= addrlen,
 		.servername	= "localhost",
+		.timeout	= &rpcb_local_tcp_timeout,
 		.program	= &rpcb_program,
 		.version	= version,
 		.authflavor	= RPC_AUTH_UNIX,
@@ -175,7 +193,7 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
 
 	rpcb_clnt = rpcb_create_local(addr, addrlen, version);
 	if (!IS_ERR(rpcb_clnt)) {
-		error = rpc_call_sync(rpcb_clnt, msg, 0);
+		error = rpc_call_sync(rpcb_clnt, msg, RPC_TASK_ONESHOT);
 		rpc_shutdown_client(rpcb_clnt);
 	} else
 		error = PTR_ERR(rpcb_clnt);


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 20/24] SUNRPC: Support registering IPv6 interfaces with local rpcbind daemon
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (18 preceding siblings ...)
  2008-04-14 16:28   ` [PATCH 19/24] SUNRPC: Quickly detect missing portmapper during RPC service registration Chuck Lever
@ 2008-04-14 16:29   ` Chuck Lever
  2008-04-14 16:29   ` [PATCH 21/24] SUNRPC: Split portmap unregister API into separate function Chuck Lever
                     ` (4 subsequent siblings)
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:29 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Introduce a new API to register RPC services on IPv6 interfaces to allow
the NFS server and lockd to advertise on IPv6 networks.

Unlike rpcb_register(), the new rpcb_v4_register() function uses rpcbind
protocol version 4 to contact the local rpcbind daemon.  The version 4
SET/UNSET procedures allow services to register address families besides
AF_INET, register at specific network interfaces, and register transport
protocols besides UDP and TCP.  All of this functionality is exposed via
the new rpcb_v4_register() kernel API.

A user-space rpcbind daemon implementation that supports version 4 of the
rpcbind protocol is required in order to make use of this new API.

Note that rpcbind version 3 is sufficient to support the new rpcbind
facilities listed above, but most extant implementations use version 4.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 include/linux/sunrpc/clnt.h |    3 +
 net/sunrpc/rpcb_clnt.c      |  136 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 139 insertions(+), 0 deletions(-)

diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 129a86e..919b1ea 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -123,6 +123,9 @@ void		rpc_shutdown_client(struct rpc_clnt *);
 void		rpc_release_client(struct rpc_clnt *);
 
 int		rpcb_register(u32, u32, int, unsigned short, int *);
+int		rpcb_v4_register(const u32 program, const u32 version,
+				 const struct sockaddr *address,
+				 const char *netid, int *result);
 int		rpcb_getport_sync(struct sockaddr_in *, u32, u32, int);
 void		rpcb_getport_async(struct rpc_task *);
 
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 4a85bf5..849b4f7 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -90,6 +90,7 @@ struct rpcbind_args {
 
 static struct rpc_procinfo rpcb_procedures2[];
 static struct rpc_procinfo rpcb_procedures3[];
+static struct rpc_procinfo rpcb_procedures4[];
 
 struct rpcb_info {
 	u32			rpc_vers;
@@ -124,6 +125,12 @@ static const struct sockaddr_in rpcb_inaddr_loopback = {
 	.sin_port		= htons(RPCBIND_PORT),
 };
 
+static const struct sockaddr_in6 rpcb_in6addr_loopback = {
+	.sin6_family		= AF_INET6,
+	.sin6_addr		= IN6ADDR_LOOPBACK_INIT,
+	.sin6_port		= htons(RPCBIND_PORT),
+};
+
 /*
  * TCP is always used to contact the local rpcbind daemon because we
  * get an immediate indication of whether there is a remote listener
@@ -244,6 +251,135 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
 					RPCBVERS_2, &msg, okay);
 }
 
+/*
+ * Fill in AF_INET family-specific arguments to register
+ */
+static int rpcb_register_netid4(struct sockaddr_in *address_to_register,
+				struct rpc_message *msg)
+{
+	struct rpcbind_args *map = msg->rpc_argp;
+	unsigned short port = ntohs(address_to_register->sin_port);
+	char buf[32];
+
+	/* Construct AF_INET universal address */
+	snprintf(buf, sizeof(buf),
+			NIPQUAD_FMT".%u.%u",
+			NIPQUAD(address_to_register->sin_addr.s_addr),
+			port >> 8, port & 0xff);
+	map->r_addr = buf;
+
+	dprintk("RPC:       %sregistering [%u, %u, %s, '%s'] with "
+		"local rpcbind\n", (port ? "" : "un"),
+			map->r_prog, map->r_vers,
+			map->r_addr, map->r_netid);
+
+	msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
+	if (port)
+		msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
+
+	return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
+					sizeof(rpcb_inaddr_loopback),
+					RPCBVERS_4, msg, msg->rpc_resp);
+}
+
+/*
+ * Fill in AF_INET6 family-specific arguments to register
+ */
+static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
+				struct rpc_message *msg)
+{
+	struct rpcbind_args *map = msg->rpc_argp;
+	unsigned short port = ntohs(address_to_register->sin6_port);
+	char buf[64];
+
+	/* Construct AF_INET6 universal address */
+	snprintf(buf, sizeof(buf),
+			NIP6_FMT".%u.%u",
+			NIP6(address_to_register->sin6_addr),
+			port >> 8, port & 0xff);
+	map->r_addr = buf;
+
+	dprintk("RPC:       %sregistering [%u, %u, %s, '%s'] with "
+		"local rpcbind\n", (port ? "" : "un"),
+			map->r_prog, map->r_vers,
+			map->r_addr, map->r_netid);
+
+	msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
+	if (port)
+		msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
+
+	return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback,
+					sizeof(rpcb_in6addr_loopback),
+					RPCBVERS_4, msg, msg->rpc_resp);
+}
+
+/**
+ * rpcb_v4_register - set or unset a port registration with the local rpcbind
+ * @program: RPC program number of service to (un)register
+ * @version: RPC version number of service to (un)register
+ * @address: family, IP address, and port to (un)register
+ * @netid: netid of transport protocol to (un)register
+ * @result: result code from rpcbind RPC call
+ *
+ * Called by server-side RPC consumers to advertise an RPC-based service
+ * via the system's rpcbind daemon.  Callers must call this routine once for
+ * each [program, version, address, netid] tuple they wish to advertise.
+ * A unique address family counts as a separate address, thus a service must
+ * register AF_INET and AF_INET6 service addresses separately.
+ *
+ * Callers may also unregister their RPC services by setting the port
+ * number in the passed-in address to zero.  Callers can pass "" for
+ * @netid to unregister all transport netids associated with [program,
+ * version, address].
+ *
+ * Returns zero if the registration request was dispatched successfully.
+ * The rpcbind daemon's result code is stored in *result.
+ *
+ * Returns an errno value and sets *result to zero if there was some
+ * problem that prevented the rpcbind request from being dispatched.
+ *
+ * This function uses rpcbind protocol version 4 to contact the local
+ * rpcbind daemon.  The local rpcbind daemon must support version 4 of the
+ * rpcbind protocol in order for these functions to return success.
+ *
+ * Version 4 SET/UNSET procedures allow services to register address
+ * families besides AF_INET, register at specific network interfaces, and
+ * register transport protocols besides UDP and TCP.
+ *
+ * The contents of @address determine the address family and the port to be
+ * registered.  The usual practice is to pass in INADDR_ANY as the raw
+ * address, but specifying a non-zero address is supported by this API if
+ * the caller wishes to advertise a service on a specific network interface.
+ */
+int rpcb_v4_register(const u32 program, const u32 version,
+		     const struct sockaddr *address, const char *netid,
+		     int *result)
+{
+	struct rpcbind_args map = {
+		.r_prog		= program,
+		.r_vers		= version,
+		.r_netid	= netid,
+		.r_owner	= RPCB_OWNER_STRING,
+	};
+	struct rpc_message msg = {
+		.rpc_argp	= &map,
+		.rpc_resp	= result,
+	};
+
+	*result = 0;
+
+	switch (address->sa_family) {
+	case AF_INET:
+		return rpcb_register_netid4((struct sockaddr_in *)address,
+					    &msg);
+	case AF_INET6:
+		return rpcb_register_netid6((struct sockaddr_in6 *)address,
+					    &msg);
+	}
+
+	return -EAFNOSUPPORT;
+}
+
 /**
  * rpcb_getport_sync - obtain the port for an RPC service on a given host
  * @sin: address of remote peer


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 21/24] SUNRPC: Split portmap unregister API into separate function
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (19 preceding siblings ...)
  2008-04-14 16:29   ` [PATCH 20/24] SUNRPC: Support registering IPv6 interfaces with local rpcbind daemon Chuck Lever
@ 2008-04-14 16:29   ` Chuck Lever
  2008-04-14 16:29   ` [PATCH 22/24] SUNRPC: Use the new rpcb_v4_register() API in svc_unregister() Chuck Lever
                     ` (3 subsequent siblings)
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:29 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Registering RPC services with the local portmapper is sufficiently
different from unregistering them that providing a separate API for each
makes sense.

The mechanics of and API for registering and unregistering RPC services
will diverge further as support for IPv6 is added.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 include/linux/sunrpc/svc.h |    1 +
 net/sunrpc/svc.c           |   66 +++++++++++++++++++++++++++++++++-----------
 2 files changed, 51 insertions(+), 16 deletions(-)

diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 64c9755..48ad59c 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -395,6 +395,7 @@ int		   svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
 void		   svc_destroy(struct svc_serv *);
 int		   svc_process(struct svc_rqst *);
 int		   svc_register(struct svc_serv *, int, unsigned short);
+void		   svc_unregister(const struct svc_serv *serv);
 void		   svc_wake_up(struct svc_serv *);
 void		   svc_reserve(struct svc_rqst *rqstp, int space);
 struct svc_pool *  svc_pool_for_cpu(struct svc_serv *serv, int cpu);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 86a5b56..576efa7 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -420,9 +420,8 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
 		spin_lock_init(&pool->sp_lock);
 	}
 
-
 	/* Remove any stale portmap registrations */
-	svc_register(serv, 0, 0);
+	svc_unregister(serv);
 
 	return serv;
 }
@@ -490,8 +489,7 @@ svc_destroy(struct svc_serv *serv)
 	if (svc_serv_is_pooled(serv))
 		svc_pool_map_put();
 
-	/* Unregister service with the portmapper */
-	svc_register(serv, 0, 0);
+	svc_unregister(serv);
 	kfree(serv->sv_pools);
 	kfree(serv);
 }
@@ -753,21 +751,21 @@ svc_exit_thread(struct svc_rqst *rqstp)
 }
 EXPORT_SYMBOL(svc_exit_thread);
 
-/*
- * Register an RPC service with the local portmapper.
- * To unregister a service, call this routine with
- * proto and port == 0.
+/**
+ * svc_register - register an RPC service with the local portmapper
+ * @serv: svc_serv struct for the service to register
+ * @protocol: transport protocol number to advertise
+ * @port: port to advertise
+ *
  */
 int
 svc_register(struct svc_serv *serv, int proto, unsigned short port)
 {
 	struct svc_program	*progp;
-	unsigned long		flags;
 	unsigned int		i;
 	int			error = 0, dummy;
 
-	if (!port)
-		clear_thread_flag(TIF_SIGPENDING);
+	BUG_ON(proto == 0 && port == 0);
 
 	for (progp = serv->sv_program; progp; progp = progp->pg_next) {
 		for (i = 0; i < progp->pg_nvers; i++) {
@@ -795,13 +793,49 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
 		}
 	}
 
-	if (!port) {
-		spin_lock_irqsave(&current->sighand->siglock, flags);
-		recalc_sigpending();
-		spin_unlock_irqrestore(&current->sighand->siglock, flags);
+	return error;
+}
+
+static void __svc_unregister(struct svc_program *program, u32 version)
+{
+	int error, boolean = 0;
+
+	error = rpcb_register(program->pg_prog, version, 0, 0, &boolean);
+	dprintk("svc: svc_unregister(%sv%u), error %d, %s\n",
+			program->pg_name, version, error,
+			(boolean ? "succeeded" : "failed"));
+}
+
+/**
+ * svc_unregister - remove an RPC server from the local rpcbind database
+ * @serv: svc_serv struct for the service to register
+ *
+ * All transport protocols and ports for this service are removed from
+ * the local rpcbind database.  The result of unregistration is reported
+ * via dprintk for those who want verification of the result, but is
+ * otherwise not important.
+ */
+void svc_unregister(const struct svc_serv *serv)
+{
+	struct svc_program *program;
+	unsigned long flags;
+	u32 version;
+
+	clear_thread_flag(TIF_SIGPENDING);
+
+	for (program = serv->sv_program; program; program = program->pg_next) {
+		for (version = 0; version < program->pg_nvers; version++) {
+			if (program->pg_vers[version] == NULL)
+				continue;
+			if (program->pg_vers[version]->vs_hidden)
+				continue;
+			__svc_unregister(program, version);
+		}
 	}
 
-	return error;
+	spin_lock_irqsave(&current->sighand->siglock, flags);
+	recalc_sigpending();
+	spin_unlock_irqrestore(&current->sighand->siglock, flags);
 }
 
 /*


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 22/24] SUNRPC: Use the new rpcb_v4_register() API in svc_unregister()
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (20 preceding siblings ...)
  2008-04-14 16:29   ` [PATCH 21/24] SUNRPC: Split portmap unregister API into separate function Chuck Lever
@ 2008-04-14 16:29   ` Chuck Lever
  2008-04-14 16:29   ` [PATCH 23/24] SUNRPC: Use new rpcb_v4_register() interface in svc_register() Chuck Lever
                     ` (2 subsequent siblings)
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:29 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Unregister both AF_INET and AF_INET6 capabilities for a service advertised
in the local rpcbind database.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 net/sunrpc/svc.c |   37 +++++++++++++++++++++++++++++++++----
 1 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 576efa7..42f83b4 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -28,6 +28,18 @@
 
 #define RPCDBG_FACILITY	RPCDBG_SVCDSP
 
+#ifdef CONFIG_SUNRPC_REGISTER_V4
+static const struct sockaddr_in svc_inaddr_any = {
+	.sin_family		= AF_INET,
+	.sin_addr.s_addr	= htonl(INADDR_ANY),
+};
+
+static const struct sockaddr_in6 svc_in6addr_any = {
+	.sin6_family		= AF_INET6,
+	.sin6_addr		= IN6ADDR_ANY_INIT,
+};
+#endif
+
 #define svc_serv_is_pooled(serv)    ((serv)->sv_function)
 
 /*
@@ -800,20 +812,37 @@ static void __svc_unregister(struct svc_program *program, u32 version)
 {
 	int error, boolean = 0;
 
+#ifdef CONFIG_SUNRPC_REGISTER_V4
+	error = rpcb_v4_register(program->pg_prog, version,
+				 (struct sockaddr *)&svc_inaddr_any,
+				 "", &boolean);
+	dprintk("svc: svc_unregister(%sv%u, AF_INET), error %d, %s\n",
+			program->pg_name, version, error,
+			(boolean ? "succeeded" : "failed"));
+
+	boolean = 0;
+	error = rpcb_v4_register(program->pg_prog, version,
+				 (struct sockaddr *)&svc_in6addr_any,
+				 "", &boolean);
+	dprintk("svc: svc_unregister(%sv%u, AF_INET6), error %d, %s\n",
+			program->pg_name, version, error,
+			(boolean ? "succeeded" : "failed"));
+#else
 	error = rpcb_register(program->pg_prog, version, 0, 0, &boolean);
 	dprintk("svc: svc_unregister(%sv%u), error %d, %s\n",
 			program->pg_name, version, error,
 			(boolean ? "succeeded" : "failed"));
+#endif
 }
 
 /**
  * svc_unregister - remove an RPC server from the local rpcbind database
  * @serv: svc_serv struct for the service to register
  *
- * All transport protocols and ports for this service are removed from
- * the local rpcbind database.  The result of unregistration is reported
- * via dprintk for those who want verification of the result, but is
- * otherwise not important.
+ * All address families, transport protocols, and ports for this service
+ * are removed from the local rpcbind database.  The result of unregis-
+ * tration is reported via dprintk for those who want verification of the
+ * result, but is otherwise not important.
  */
 void svc_unregister(const struct svc_serv *serv)
 {


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 23/24] SUNRPC: Use new rpcb_v4_register() interface in svc_register()
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (21 preceding siblings ...)
  2008-04-14 16:29   ` [PATCH 22/24] SUNRPC: Use the new rpcb_v4_register() API in svc_unregister() Chuck Lever
@ 2008-04-14 16:29   ` Chuck Lever
  2008-04-14 16:29   ` [PATCH 24/24] SUNRPC: Add kernel build option to disable server-side use of rpcbind v3/v4 Chuck Lever
  2008-04-14 19:14   ` [PATCH 00/24] RPC server support rpcbind v4 plus additional clean ups J. Bruce Fields
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:29 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

In order to advertise NFS-related services on IPv6 interfaces via
rpcbind, the Linux RPC server implementation must use
rpcb_v4_register() instead of rpcb_register().

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 include/linux/sunrpc/svc.h |    5 ++-
 net/sunrpc/svc.c           |   86 +++++++++++++++++++++++++++++++++++---------
 net/sunrpc/svcsock.c       |    3 +-
 3 files changed, 73 insertions(+), 21 deletions(-)

diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 48ad59c..9cf11ea 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -394,7 +394,10 @@ struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
 int		   svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
 void		   svc_destroy(struct svc_serv *);
 int		   svc_process(struct svc_rqst *);
-int		   svc_register(struct svc_serv *, int, unsigned short);
+int		   svc_register(const struct svc_serv *serv,
+				const unsigned short family,
+				const unsigned short protocol,
+				const unsigned short port);
 void		   svc_unregister(const struct svc_serv *serv);
 void		   svc_wake_up(struct svc_serv *);
 void		   svc_reserve(struct svc_rqst *rqstp, int space);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 42f83b4..d31f0ff 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -763,45 +763,95 @@ svc_exit_thread(struct svc_rqst *rqstp)
 }
 EXPORT_SYMBOL(svc_exit_thread);
 
+static int __svc_register(const u32 program, const u32 version,
+			  const unsigned short family,
+			  const unsigned short protocol,
+			  const unsigned short port)
+{
+	int error, result;
+
+#ifdef CONFIG_SUNRPC_REGISTER_V4
+	struct sockaddr_storage any_addr;
+	char *netid;
+
+	switch (family) {
+	case AF_INET: {
+		struct sockaddr_in *sin = (struct sockaddr_in *)&any_addr;
+		memcpy(sin, &svc_inaddr_any, sizeof(svc_inaddr_any));
+		sin->sin_port = htons(port);
+
+		if (protocol == IPPROTO_UDP)
+			netid = RPCBIND_NETID_UDP;
+		else
+			netid = RPCBIND_NETID_TCP;
+		break;
+	}
+	case AF_INET6: {
+		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&any_addr;
+		memcpy(sin6, &svc_in6addr_any, sizeof(svc_in6addr_any));
+		sin6->sin6_port = htons(port);
+
+		if (protocol == IPPROTO_UDP)
+			netid = RPCBIND_NETID_UDP6;
+		else
+			netid = RPCBIND_NETID_TCP6;
+		break;
+	}
+	default:
+		return -EAFNOSUPPORT;
+	}
+
+	error = rpcb_v4_register(program, version,
+					(struct sockaddr *)&any_addr,
+					netid, &result);
+#else
+	error = rpcb_register(program, version, protocol, port, &result);
+#endif
+
+	if (!result)
+		error = -EACCES;
+
+	return error;
+}
+
 /**
  * svc_register - register an RPC service with the local portmapper
  * @serv: svc_serv struct for the service to register
+ * @family: address family to register
  * @protocol: transport protocol number to advertise
  * @port: port to advertise
  *
+ * Service is registered for any address in given address family
  */
-int
-svc_register(struct svc_serv *serv, int proto, unsigned short port)
+int svc_register(const struct svc_serv *serv, const unsigned short family,
+		 const unsigned short protocol, const unsigned short port)
 {
-	struct svc_program	*progp;
-	unsigned int		i;
-	int			error = 0, dummy;
+	struct svc_program *progp;
+	u32 version;
+	int error = 0;
 
-	BUG_ON(proto == 0 && port == 0);
+	BUG_ON(protocol == 0 && port == 0);
 
 	for (progp = serv->sv_program; progp; progp = progp->pg_next) {
-		for (i = 0; i < progp->pg_nvers; i++) {
-			if (progp->pg_vers[i] == NULL)
+		for (version = 0; version < progp->pg_nvers; version++) {
+			if (progp->pg_vers[version] == NULL)
 				continue;
 
-			dprintk("svc: svc_register(%s, %s, %d, %d)%s\n",
+			dprintk("svc: svc_register(%s, %u, %s, %u)%s\n",
 					progp->pg_name,
-					proto == IPPROTO_UDP?  "udp" : "tcp",
+					version,
+					protocol == IPPROTO_UDP?  "udp" : "tcp",
 					port,
-					i,
-					progp->pg_vers[i]->vs_hidden?
+					progp->pg_vers[version]->vs_hidden?
 						" (but not telling portmap)" : "");
 
-			if (progp->pg_vers[i]->vs_hidden)
+			if (progp->pg_vers[version]->vs_hidden)
 				continue;
 
-			error = rpcb_register(progp->pg_prog, i, proto, port, &dummy);
+			error = __svc_register(progp->pg_prog, version,
+					       family, protocol, port);
 			if (error < 0)
 				break;
-			if (port && !dummy) {
-				error = -EACCES;
-				break;
-			}
 		}
 	}
 
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 51357a3..54a829a 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1128,9 +1128,8 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
 
 	inet = sock->sk;
 
-	/* Register socket with portmapper */
 	if (*errp >= 0 && pmap_register)
-		*errp = svc_register(serv, inet->sk_protocol,
+		*errp = svc_register(serv, inet->sk_family, inet->sk_protocol,
 				     ntohs(inet_sk(inet)->sport));
 
 	if (*errp < 0) {


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [PATCH 24/24] SUNRPC: Add kernel build option to disable server-side use of rpcbind v3/v4
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (22 preceding siblings ...)
  2008-04-14 16:29   ` [PATCH 23/24] SUNRPC: Use new rpcb_v4_register() interface in svc_register() Chuck Lever
@ 2008-04-14 16:29   ` Chuck Lever
  2008-04-14 19:14   ` [PATCH 00/24] RPC server support rpcbind v4 plus additional clean ups J. Bruce Fields
  24 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 16:29 UTC (permalink / raw)
  To: bfields, trond.myklebust; +Cc: linux-nfs

Allow distributions to use the legacy behavior until they integrate an
appropriate user-space rpcbind daemon that can support IPv6 RPC services.

I tried adding some logic to fall back if (un)registering with a v4
protocol request failed, but there are too many corner cases.  So I just
made it a compile-time switch that distributions can throw when they've
replaced portmapper with rpcbind.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 fs/Kconfig |   30 ++++++++++++++++++++++++++++--
 1 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/fs/Kconfig b/fs/Kconfig
index f1bc33f..56e6fa5 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1772,7 +1772,7 @@ config SUNRPC_XPRT_RDMA
 	  If unsure, say N.
 
 config SUNRPC_BIND34
-	bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)"
+	bool "Support for rpcbind v3 & v4 queries (EXPERIMENTAL)"
 	depends on SUNRPC && EXPERIMENTAL
 	default n
 	help
@@ -1785,13 +1785,39 @@ config SUNRPC_BIND34
 	  querying rpcbind servers via versions 3 and 4 of the rpcbind
 	  protocol.  The kernel automatically falls back to version 2
 	  if a remote rpcbind service does not support versions 3 or 4.
+
 	  By themselves, these new versions do not provide support for
 	  RPC over IPv6, but the new protocol versions are necessary to
-	  support it.
+	  support it.  Enabling this option is required to support
+	  mounting NFS servers over IPv6 networks.
 
 	  If unsure, say N to get traditional behavior (version 2 rpcbind
 	  requests only).
 
+config SUNRPC_REGISTER_V4
+	bool "Register local RPC services via rpcbind v4 (EXPERIMENTAL)"
+	depends on SUNRPC && EXPERIMENTAL
+	default n
+	help 
+	  RPC requests over IPv6 networks require support for larger
+	  addresses when performing an RPC bind.  Sun added support for
+	  registering RPC services at an IPv6 address by creating two
+	  new versions of the rpcbind protocol (RFC 1833).
+
+	  This option enables support in the kernel RPC server for
+	  registering local RPC services via version 4 of the rpcbind
+	  protocol.  If you enable this option, you must run a user
+	  space portmapper daemon capable of understanding rpcbind
+	  protocol version 4.
+
+	  If unsure, say N to get traditional behavior (register local
+	  services using only rpcbind version 2).
+
+	  Enabling this option and using a portmapper capable of
+	  responding to rpcbind version 4 requests is required to support
+	  serving NFS requests over IPv6 networks.  Distributions using
+	  the legacy Linux portmapper daemon must say N here.
+
 config RPCSEC_GSS_KRB5
 	tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
 	depends on SUNRPC && EXPERIMENTAL


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [PATCH 03/24] SUNRPC: RPC server still uses 2.4 method for disabling TCP Nagle
       [not found]     ` <20080414162701.12741.10868.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
@ 2008-04-14 17:38       ` J. Bruce Fields
  0 siblings, 0 replies; 38+ messages in thread
From: J. Bruce Fields @ 2008-04-14 17:38 UTC (permalink / raw)
  To: Chuck Lever; +Cc: trond.myklebust, linux-nfs

On Mon, Apr 14, 2008 at 12:27:01PM -0400, Chuck Lever wrote:
> Use the 2.6 method for disabling TCP Nagle in the kernel's RPC server.

OK.--b.

> 
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> ---
> 
>  net/sunrpc/svcsock.c |    4 ++--
>  1 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
> index c475977..6d4162b 100644
> --- a/net/sunrpc/svcsock.c
> +++ b/net/sunrpc/svcsock.c
> @@ -38,6 +38,7 @@
>  #include <net/checksum.h>
>  #include <net/ip.h>
>  #include <net/ipv6.h>
> +#include <net/tcp.h>
>  #include <net/tcp_states.h>
>  #include <asm/uaccess.h>
>  #include <asm/ioctls.h>
> @@ -1045,7 +1046,6 @@ void svc_cleanup_xprt_sock(void)
>  static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
>  {
>  	struct sock	*sk = svsk->sk_sk;
> -	struct tcp_sock *tp = tcp_sk(sk);
>  
>  	svc_xprt_init(&svc_tcp_class, &svsk->sk_xprt, serv);
>  	set_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
> @@ -1063,7 +1063,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
>  		svsk->sk_reclen = 0;
>  		svsk->sk_tcplen = 0;
>  
> -		tp->nonagle = 1;        /* disable Nagle's algorithm */
> +		tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
>  
>  		/* initialise setting must have enough space to
>  		 * receive and respond to one request.
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 04/24] SUNRPC: Address potential buffer length overflow in svc_sendto
       [not found]     ` <20080414162708.12741.71691.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
@ 2008-04-14 17:48       ` J. Bruce Fields
  2008-04-14 19:43         ` Chuck Lever
  0 siblings, 1 reply; 38+ messages in thread
From: J. Bruce Fields @ 2008-04-14 17:48 UTC (permalink / raw)
  To: Chuck Lever; +Cc: trond.myklebust, linux-nfs

On Mon, Apr 14, 2008 at 12:27:08PM -0400, Chuck Lever wrote:
> Paranoia: Ensure a negative error value return from kernel_sendpage never
> matches a large buffer length.

That is a little paranoid.  Absent an argument for exactly what sort of
bug could allow us to reach this point with the head iov_len in at least
the gigabytes, I'm inclined to leave this alone for simplicity's
sake....

--b.

> 
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> ---
> 
>  net/sunrpc/svcsock.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
> index 6d4162b..a8ae279 100644
> --- a/net/sunrpc/svcsock.c
> +++ b/net/sunrpc/svcsock.c
> @@ -200,7 +200,7 @@ static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
>  		flags = 0;
>  	len = kernel_sendpage(sock, rqstp->rq_respages[0], 0,
>  				  xdr->head[0].iov_len, flags);
> -	if (len != xdr->head[0].iov_len)
> +	if (len < 0 || len != xdr->head[0].iov_len)
>  		goto out;
>  	slen -= xdr->head[0].iov_len;
>  	if (slen == 0)
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 06/24] SUNRPC: Sanity check incoming UDP datagram lengths properly
       [not found]     ` <20080414162723.12741.35500.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
@ 2008-04-14 18:38       ` J. Bruce Fields
  2008-04-14 19:55         ` Chuck Lever
  0 siblings, 1 reply; 38+ messages in thread
From: J. Bruce Fields @ 2008-04-14 18:38 UTC (permalink / raw)
  To: Chuck Lever; +Cc: trond.myklebust, linux-nfs

On Mon, Apr 14, 2008 at 12:27:23PM -0400, Chuck Lever wrote:
> Clean up: ensure svc_udp_recvfrom() is getting at least a full UDP header
> to avoid potential negative intermediate values.

Is it legal in this case for skb_recv_datagram() to return an skb
without at least that minimum length?  (And if not, should this be a
BUG()?)

> A similar sanity check is already used in the RPC client.

This one?:

	repsize = skb->len - sizeof(struct udphdr);
	if (repsize < 4) {
		dprintk("RPC:       impossible RPC reply size %d!\n", repsize);
		goto dropit;
	}

I assumed it was needed because of the rpc-level check (for the 4 bytes worth
of xid), not because it needed udp-level checking.

--b.

> 
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> ---
> 
>  net/sunrpc/svcsock.c |   20 +++++++++++++-------
>  1 files changed, 13 insertions(+), 7 deletions(-)
> 
> diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
> index d077071..de29e7f 100644
> --- a/net/sunrpc/svcsock.c
> +++ b/net/sunrpc/svcsock.c
> @@ -431,6 +431,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
>  	} buffer;
>  	struct cmsghdr *cmh = &buffer.hdr;
>  	int		err, len;
> +	unsigned int	bytes;
>  	struct msghdr msg = {
>  		.msg_name = svc_addr(rqstp),
>  		.msg_control = cmh,
> @@ -484,8 +485,13 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
>  	 */
>  	svc_xprt_received(&svsk->sk_xprt);
>  
> -	len  = skb->len - sizeof(struct udphdr);
> -	rqstp->rq_arg.len = len;
> +	if (skb->len < sizeof(struct udphdr)) {
> +		dprintk("svc: bad UDP datagram length: %u\n", skb->len);
> +		skb_free_datagram(svsk->sk_sk, skb);
> +		return 0;
> +	}
> +	bytes = skb->len - sizeof(struct udphdr);
> +	rqstp->rq_arg.len = bytes;
>  
>  	rqstp->rq_prot = IPPROTO_UDP;
>  
> @@ -515,7 +521,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
>  		/* we can use it in-place */
>  		rqstp->rq_arg.head[0].iov_base = skb->data +
>  			sizeof(struct udphdr);
> -		rqstp->rq_arg.head[0].iov_len = len;
> +		rqstp->rq_arg.head[0].iov_len = bytes;
>  		if (skb_checksum_complete(skb)) {
>  			skb_free_datagram(svsk->sk_sk, skb);
>  			return 0;
> @@ -524,12 +530,12 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
>  	}
>  
>  	rqstp->rq_arg.page_base = 0;
> -	if (len <= rqstp->rq_arg.head[0].iov_len) {
> -		rqstp->rq_arg.head[0].iov_len = len;
> +	if (bytes <= rqstp->rq_arg.head[0].iov_len) {
> +		rqstp->rq_arg.head[0].iov_len = bytes;
>  		rqstp->rq_arg.page_len = 0;
>  		rqstp->rq_respages = rqstp->rq_pages+1;
>  	} else {
> -		rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
> +		rqstp->rq_arg.page_len = bytes - rqstp->rq_arg.head[0].iov_len;
>  		rqstp->rq_respages = rqstp->rq_pages + 1 +
>  			DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE);
>  	}
> @@ -537,7 +543,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
>  	if (serv->sv_stats)
>  		serv->sv_stats->netudpcnt++;
>  
> -	return len;
> +	return bytes;
>  }
>  
>  static int
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 07/24] SUNRPC:  Update RPC server's TCP record marker decoder
       [not found]     ` <20080414162730.12741.97124.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
@ 2008-04-14 18:49       ` J. Bruce Fields
  0 siblings, 0 replies; 38+ messages in thread
From: J. Bruce Fields @ 2008-04-14 18:49 UTC (permalink / raw)
  To: Chuck Lever; +Cc: trond.myklebust, linux-nfs

On Mon, Apr 14, 2008 at 12:27:30PM -0400, Chuck Lever wrote:
> Clean up: Update the RPC server's TCP record marker decoder to match the
> constructs used by the RPC client's TCP socket transport.

Looks good to me.

> 
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> ---
> 
>  include/linux/sunrpc/svcsock.h |    4 ++--
>  net/sunrpc/svcsock.c           |   24 ++++++++++++------------
>  2 files changed, 14 insertions(+), 14 deletions(-)
> 
> diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
> index 206f092..8cff696 100644
> --- a/include/linux/sunrpc/svcsock.h
> +++ b/include/linux/sunrpc/svcsock.h
> @@ -26,8 +26,8 @@ struct svc_sock {
>  	void			(*sk_owspace)(struct sock *);
>  
>  	/* private TCP part */
> -	int			sk_reclen;	/* length of record */
> -	int			sk_tcplen;	/* current read length */
> +	u32			sk_reclen;	/* length of record */
> +	u32			sk_tcplen;	/* current read length */
>  };
>  
>  /*
> diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
> index de29e7f..51357a3 100644
> --- a/net/sunrpc/svcsock.c
> +++ b/net/sunrpc/svcsock.c
> @@ -46,6 +46,7 @@
>  #include <linux/sunrpc/types.h>
>  #include <linux/sunrpc/clnt.h>
>  #include <linux/sunrpc/xdr.h>
> +#include <linux/sunrpc/msg_prot.h>
>  #include <linux/sunrpc/svcsock.h>
>  #include <linux/sunrpc/stats.h>
>  
> @@ -829,8 +830,8 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
>  	 * the next four bytes. Otherwise try to gobble up as much as
>  	 * possible up to the complete record length.
>  	 */
> -	if (svsk->sk_tcplen < 4) {
> -		unsigned long	want = 4 - svsk->sk_tcplen;
> +	if (svsk->sk_tcplen < sizeof(rpc_fraghdr)) {
> +		int		want = sizeof(rpc_fraghdr) - svsk->sk_tcplen;
>  		struct kvec	iov;
>  
>  		iov.iov_base = ((char *) &svsk->sk_reclen) + svsk->sk_tcplen;
> @@ -840,32 +841,31 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
>  		svsk->sk_tcplen += len;
>  
>  		if (len < want) {
> -			dprintk("svc: short recvfrom while reading record length (%d of %lu)\n",
> -				len, want);
> +			dprintk("svc: short recvfrom while reading record "
> +				"length (%d of %d)\n", len, want);
>  			svc_xprt_received(&svsk->sk_xprt);
>  			return -EAGAIN; /* record header not complete */
>  		}
>  
>  		svsk->sk_reclen = ntohl(svsk->sk_reclen);
> -		if (!(svsk->sk_reclen & 0x80000000)) {
> +		if (!(svsk->sk_reclen & RPC_LAST_STREAM_FRAGMENT)) {
>  			/* FIXME: technically, a record can be fragmented,
>  			 *  and non-terminal fragments will not have the top
>  			 *  bit set in the fragment length header.
>  			 *  But apparently no known nfs clients send fragmented
>  			 *  records. */
>  			if (net_ratelimit())
> -				printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx"
> -				       " (non-terminal)\n",
> -				       (unsigned long) svsk->sk_reclen);
> +				printk(KERN_NOTICE "RPC: multiple fragments "
> +					"per record not supported\n");

Yep, that's helpful documentation, thanks.--b.

>  			goto err_delete;
>  		}
> -		svsk->sk_reclen &= 0x7fffffff;
> +		svsk->sk_reclen &= RPC_FRAGMENT_SIZE_MASK;
>  		dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen);
>  		if (svsk->sk_reclen > serv->sv_max_mesg) {
>  			if (net_ratelimit())
> -				printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx"
> -				       " (large)\n",
> -				       (unsigned long) svsk->sk_reclen);
> +				printk(KERN_NOTICE "RPC: "
> +					"fragment too large: 0x%08lx\n",
> +					(unsigned long)svsk->sk_reclen);
>  			goto err_delete;
>  		}
>  	}
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 09/24] SUNRPC: Use unsigned index when looping over arrays
       [not found]     ` <20080414162745.12741.37176.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
@ 2008-04-14 18:51       ` J. Bruce Fields
  0 siblings, 0 replies; 38+ messages in thread
From: J. Bruce Fields @ 2008-04-14 18:51 UTC (permalink / raw)
  To: Chuck Lever; +Cc: trond.myklebust, linux-nfs

On Mon, Apr 14, 2008 at 12:27:45PM -0400, Chuck Lever wrote:
> Clean up: Suppress a harmless compiler warning in the RPC server related
> to array indices.
> 
> ARRAY_SIZE() returns a size_t, so use unsigned type for a loop index when
> looping over arrays.

OK (and thanks for the "harmless compiler warning clarification").--b.

> 
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> ---
> 
>  net/sunrpc/svc.c |    5 +++--
>  1 files changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
> index a290e15..c1e763b 100644
> --- a/net/sunrpc/svc.c
> +++ b/net/sunrpc/svc.c
> @@ -528,8 +528,9 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
>  static void
>  svc_release_buffer(struct svc_rqst *rqstp)
>  {
> -	int i;
> -	for (i=0; i<ARRAY_SIZE(rqstp->rq_pages); i++)
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++)
>  		if (rqstp->rq_pages[i])
>  			put_page(rqstp->rq_pages[i]);
>  }
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 10/24] SUNRPC: Use unsigned loop and array index in svc_init_buffer()
       [not found]     ` <20080414162752.12741.15628.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
@ 2008-04-14 18:51       ` J. Bruce Fields
  0 siblings, 0 replies; 38+ messages in thread
From: J. Bruce Fields @ 2008-04-14 18:51 UTC (permalink / raw)
  To: Chuck Lever; +Cc: trond.myklebust, linux-nfs

On Mon, Apr 14, 2008 at 12:27:52PM -0400, Chuck Lever wrote:
> Clean up: Suppress a harmless compiler warning.
> 
> Index rq_pages[] with an unsigned type.  Make "pages" unsigned as well,
> as it never represents a value less than zero.

OK.--b.

> 
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> ---
> 
>  net/sunrpc/svc.c |    5 ++---
>  1 files changed, 2 insertions(+), 3 deletions(-)
> 
> diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
> index c1e763b..86a5b56 100644
> --- a/net/sunrpc/svc.c
> +++ b/net/sunrpc/svc.c
> @@ -504,8 +504,7 @@ EXPORT_SYMBOL(svc_destroy);
>  static int
>  svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
>  {
> -	int pages;
> -	int arghi;
> +	unsigned int pages, arghi;
>  
>  	pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply.
>  				       * We assume one is at most one page
> @@ -519,7 +518,7 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
>  		rqstp->rq_pages[arghi++] = p;
>  		pages--;
>  	}
> -	return ! pages;
> +	return pages == 0;
>  }
>  
>  /*
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 00/24] RPC server support rpcbind v4 plus additional clean ups
       [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
                     ` (23 preceding siblings ...)
  2008-04-14 16:29   ` [PATCH 24/24] SUNRPC: Add kernel build option to disable server-side use of rpcbind v3/v4 Chuck Lever
@ 2008-04-14 19:14   ` J. Bruce Fields
  2008-04-14 20:05     ` Chuck Lever
  24 siblings, 1 reply; 38+ messages in thread
From: J. Bruce Fields @ 2008-04-14 19:14 UTC (permalink / raw)
  To: Chuck Lever; +Cc: trond.myklebust, linux-nfs

On Mon, Apr 14, 2008 at 12:26:38PM -0400, Chuck Lever wrote:
> Hi Bruce, Trond -
> 
> This patch series provides some minor clean ups, and finishes with an
> implementation of support for rpcbind version 4 registration.  Version 4
> support can be entirely disabled in favor of legacy behavior with a kernel
> build option, and the default is to use rpcbind version 2 when registering
> kernel RPC services.
> 
> There are 24 patches in this series, but only a few are more than trivial and
> hopefully fewer yet are controversial.  I've tried to split these so that
> server side and client side changes are in separate patches.
> 
> It would be helpful for me if they could be considered for 2.6.26.

Thanks.  I've applied 3, 7, 9, and 10, and I'm mostly assuming the
others are Somebody Else's Problem for now.  Please feel free to correct
that idea.

--b.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 04/24] SUNRPC: Address potential buffer length overflow in svc_sendto
  2008-04-14 17:48       ` J. Bruce Fields
@ 2008-04-14 19:43         ` Chuck Lever
  2008-04-14 20:35           ` J. Bruce Fields
  0 siblings, 1 reply; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 19:43 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: trond.myklebust, linux-nfs

On Apr 14, 2008, at 1:48 PM, J. Bruce Fields wrote:
> On Mon, Apr 14, 2008 at 12:27:08PM -0400, Chuck Lever wrote:
>> Paranoia: Ensure a negative error value return from kernel_sendpage  
>> never
>> matches a large buffer length.
>
> That is a little paranoid.  Absent an argument for exactly what sort  
> of
> bug could allow us to reach this point with the head iov_len in at  
> least
> the gigabytes, I'm inclined to leave this alone for simplicity's
> sake....

I would like to document that we have noticed the mixed sign  
comparison there, and that it has been made entirely safe.  In certain  
cases, the code as it stands does not do what it looks like it does.

I'm not recommending these changes to be pedantic, nor am I doing this  
for my own health.  When we leave checks like this out, what we have  
is "clever" nondeterministic code rather than safe code.  This is  
simply good software engineering, but every one of these I've proposed  
has been argued over and often rejected.

We know that humans write this code, and that humans make mistakes.   
We should be doing everything we can to make this code less vulnerable  
to coding mistakes.  This is not about _fixing_ bugs, it's about  
_preventing_ them.

>> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
>> ---
>>
>> net/sunrpc/svcsock.c |    2 +-
>> 1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
>> index 6d4162b..a8ae279 100644
>> --- a/net/sunrpc/svcsock.c
>> +++ b/net/sunrpc/svcsock.c
>> @@ -200,7 +200,7 @@ static int svc_sendto(struct svc_rqst *rqstp,  
>> struct xdr_buf *xdr)
>> 		flags = 0;
>> 	len = kernel_sendpage(sock, rqstp->rq_respages[0], 0,
>> 				  xdr->head[0].iov_len, flags);
>> -	if (len != xdr->head[0].iov_len)
>> +	if (len < 0 || len != xdr->head[0].iov_len)
>> 		goto out;
>> 	slen -= xdr->head[0].iov_len;
>> 	if (slen == 0)
>>

--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com




^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 06/24] SUNRPC: Sanity check incoming UDP datagram lengths properly
  2008-04-14 18:38       ` J. Bruce Fields
@ 2008-04-14 19:55         ` Chuck Lever
  2008-04-14 20:54           ` J. Bruce Fields
  0 siblings, 1 reply; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 19:55 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: trond.myklebust, linux-nfs

On Apr 14, 2008, at 2:38 PM, J. Bruce Fields wrote:
> On Mon, Apr 14, 2008 at 12:27:23PM -0400, Chuck Lever wrote:
>> Clean up: ensure svc_udp_recvfrom() is getting at least a full UDP  
>> header
>> to avoid potential negative intermediate values.
>
> Is it legal in this case for skb_recv_datagram() to return an skb
> without at least that minimum length?  (And if not, should this be a
> BUG()?)
>
>
>> A similar sanity check is already used in the RPC client.
>
> This one?:
>
> 	repsize = skb->len - sizeof(struct udphdr);
> 	if (repsize < 4) {
> 		dprintk("RPC:       impossible RPC reply size %d!\n", repsize);
> 		goto dropit;
> 	}
>
> I assumed it was needed because of the rpc-level check (for the 4  
> bytes worth
> of xid), not because it needed udp-level checking.

The server side check programmatically guarantees we get a non- 
negative number when we compute "bytes."  Thus we can use an unsigned  
variable and eliminate a mixed sign comparison later on.

We can add a "+ sizeof(u32)" to the check if you like.

>> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
>> ---
>>
>> net/sunrpc/svcsock.c |   20 +++++++++++++-------
>> 1 files changed, 13 insertions(+), 7 deletions(-)
>>
>> diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
>> index d077071..de29e7f 100644
>> --- a/net/sunrpc/svcsock.c
>> +++ b/net/sunrpc/svcsock.c
>> @@ -431,6 +431,7 @@ static int svc_udp_recvfrom(struct svc_rqst  
>> *rqstp)
>> 	} buffer;
>> 	struct cmsghdr *cmh = &buffer.hdr;
>> 	int		err, len;
>> +	unsigned int	bytes;
>> 	struct msghdr msg = {
>> 		.msg_name = svc_addr(rqstp),
>> 		.msg_control = cmh,
>> @@ -484,8 +485,13 @@ static int svc_udp_recvfrom(struct svc_rqst  
>> *rqstp)
>> 	 */
>> 	svc_xprt_received(&svsk->sk_xprt);
>>
>> -	len  = skb->len - sizeof(struct udphdr);
>> -	rqstp->rq_arg.len = len;
>> +	if (skb->len < sizeof(struct udphdr)) {
>> +		dprintk("svc: bad UDP datagram length: %u\n", skb->len);
>> +		skb_free_datagram(svsk->sk_sk, skb);
>> +		return 0;
>> +	}
>> +	bytes = skb->len - sizeof(struct udphdr);
>> +	rqstp->rq_arg.len = bytes;
>>
>> 	rqstp->rq_prot = IPPROTO_UDP;
>>
>> @@ -515,7 +521,7 @@ static int svc_udp_recvfrom(struct svc_rqst  
>> *rqstp)
>> 		/* we can use it in-place */
>> 		rqstp->rq_arg.head[0].iov_base = skb->data +
>> 			sizeof(struct udphdr);
>> -		rqstp->rq_arg.head[0].iov_len = len;
>> +		rqstp->rq_arg.head[0].iov_len = bytes;
>> 		if (skb_checksum_complete(skb)) {
>> 			skb_free_datagram(svsk->sk_sk, skb);
>> 			return 0;
>> @@ -524,12 +530,12 @@ static int svc_udp_recvfrom(struct svc_rqst  
>> *rqstp)
>> 	}
>>
>> 	rqstp->rq_arg.page_base = 0;
>> -	if (len <= rqstp->rq_arg.head[0].iov_len) {
>> -		rqstp->rq_arg.head[0].iov_len = len;
>> +	if (bytes <= rqstp->rq_arg.head[0].iov_len) {
>> +		rqstp->rq_arg.head[0].iov_len = bytes;
>> 		rqstp->rq_arg.page_len = 0;
>> 		rqstp->rq_respages = rqstp->rq_pages+1;
>> 	} else {
>> -		rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
>> +		rqstp->rq_arg.page_len = bytes - rqstp->rq_arg.head[0].iov_len;
>> 		rqstp->rq_respages = rqstp->rq_pages + 1 +
>> 			DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE);
>> 	}
>> @@ -537,7 +543,7 @@ static int svc_udp_recvfrom(struct svc_rqst  
>> *rqstp)
>> 	if (serv->sv_stats)
>> 		serv->sv_stats->netudpcnt++;
>>
>> -	return len;
>> +	return bytes;
>> }
>>
>> static int
>>

--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com




^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 00/24] RPC server support rpcbind v4 plus additional clean ups
  2008-04-14 19:14   ` [PATCH 00/24] RPC server support rpcbind v4 plus additional clean ups J. Bruce Fields
@ 2008-04-14 20:05     ` Chuck Lever
  0 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 20:05 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: trond.myklebust, linux-nfs

On Apr 14, 2008, at 3:14 PM, J. Bruce Fields wrote:
> On Mon, Apr 14, 2008 at 12:26:38PM -0400, Chuck Lever wrote:
>> Hi Bruce, Trond -
>>
>> This patch series provides some minor clean ups, and finishes with an
>> implementation of support for rpcbind version 4 registration.   
>> Version 4
>> support can be entirely disabled in favor of legacy behavior with a  
>> kernel
>> build option, and the default is to use rpcbind version 2 when  
>> registering
>> kernel RPC services.
>>
>> There are 24 patches in this series, but only a few are more than  
>> trivial and
>> hopefully fewer yet are controversial.  I've tried to split these  
>> so that
>> server side and client side changes are in separate patches.
>>
>> It would be helpful for me if they could be considered for 2.6.26.
>
> Thanks.  I've applied 3, 7, 9, and 10, and I'm mostly assuming the
> others are Somebody Else's Problem for now.  Please feel free to  
> correct
> that idea.

At least for now, review of the last 4 patches in the series would be  
useful.  Those go against net/sunrpc/svc.c, which I assume is your  
bailiwick.

Naturally they don't make any sense to apply if the preceding patches  
against net/sunrpc/rpcb_clnt.c aren't accepted.

--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 04/24] SUNRPC: Address potential buffer length overflow in svc_sendto
  2008-04-14 19:43         ` Chuck Lever
@ 2008-04-14 20:35           ` J. Bruce Fields
  0 siblings, 0 replies; 38+ messages in thread
From: J. Bruce Fields @ 2008-04-14 20:35 UTC (permalink / raw)
  To: Chuck Lever; +Cc: trond.myklebust, linux-nfs

On Mon, Apr 14, 2008 at 03:43:12PM -0400, Chuck Lever wrote:
> On Apr 14, 2008, at 1:48 PM, J. Bruce Fields wrote:
>> On Mon, Apr 14, 2008 at 12:27:08PM -0400, Chuck Lever wrote:
>>> Paranoia: Ensure a negative error value return from kernel_sendpage  
>>> never
>>> matches a large buffer length.
>>
>> That is a little paranoid.  Absent an argument for exactly what sort  
>> of
>> bug could allow us to reach this point with the head iov_len in at  
>> least
>> the gigabytes, I'm inclined to leave this alone for simplicity's
>> sake....
>
> I would like to document that we have noticed the mixed sign comparison 
> there, and that it has been made entirely safe.  In certain cases, the 
> code as it stands does not do what it looks like it does.
>
> I'm not recommending these changes to be pedantic, nor am I doing this  
> for my own health.  When we leave checks like this out, what we have is 
> "clever" nondeterministic code rather than safe code.

OK, I can buy the argument that it's a little clever and non-idiomatic
to skip the explicit check for the error case.

> This is simply 
> good software engineering, but every one of these I've proposed has been 
> argued over and often rejected.
>
> We know that humans write this code, and that humans make mistakes.  We 
> should be doing everything we can to make this code less vulnerable to 
> coding mistakes.  This is not about _fixing_ bugs, it's about  
> _preventing_ them.

I understand that, but for me there's a problem of documentation.  It
helps me, as I read the code, if I can distinguish between failures that
our code is designed to handle (a buggy or malicious nfs client, a
failed disk, whatever) from failures that it's not designed to handle
(memory corruption).  So for the latter, my knee-jerk reaction is "why
isn't that a BUG_ON (or at least a WARN_ON)?"

But admittedly in this particular case, that's not really a problem--I
can't really see thinking "hey, is this code suggesting that it's
possible for iov_len to be greater than 2^31 at this point?".

--b.

>
>>> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
>>> ---
>>>
>>> net/sunrpc/svcsock.c |    2 +-
>>> 1 files changed, 1 insertions(+), 1 deletions(-)
>>>
>>> diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
>>> index 6d4162b..a8ae279 100644
>>> --- a/net/sunrpc/svcsock.c
>>> +++ b/net/sunrpc/svcsock.c
>>> @@ -200,7 +200,7 @@ static int svc_sendto(struct svc_rqst *rqstp,  
>>> struct xdr_buf *xdr)
>>> 		flags = 0;
>>> 	len = kernel_sendpage(sock, rqstp->rq_respages[0], 0,
>>> 				  xdr->head[0].iov_len, flags);
>>> -	if (len != xdr->head[0].iov_len)
>>> +	if (len < 0 || len != xdr->head[0].iov_len)
>>> 		goto out;
>>> 	slen -= xdr->head[0].iov_len;
>>> 	if (slen == 0)
>>>
>
> --
> Chuck Lever
> chuck[dot]lever[at]oracle[dot]com
>
>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 06/24] SUNRPC: Sanity check incoming UDP datagram lengths properly
  2008-04-14 19:55         ` Chuck Lever
@ 2008-04-14 20:54           ` J. Bruce Fields
  2008-04-14 21:38             ` Chuck Lever
  0 siblings, 1 reply; 38+ messages in thread
From: J. Bruce Fields @ 2008-04-14 20:54 UTC (permalink / raw)
  To: Chuck Lever; +Cc: trond.myklebust, linux-nfs

On Mon, Apr 14, 2008 at 03:55:16PM -0400, Chuck Lever wrote:
> On Apr 14, 2008, at 2:38 PM, J. Bruce Fields wrote:
>> On Mon, Apr 14, 2008 at 12:27:23PM -0400, Chuck Lever wrote:
>>> Clean up: ensure svc_udp_recvfrom() is getting at least a full UDP  
>>> header
>>> to avoid potential negative intermediate values.
>>
>> Is it legal in this case for skb_recv_datagram() to return an skb
>> without at least that minimum length? (And if not, should this be a
>> BUG()?)
>>
>>
>>> A similar sanity check is already used in the RPC client.
>>
>> This one?:
>>
>> 	repsize = skb->len - sizeof(struct udphdr);
>> 	if (repsize < 4) {
>> 		dprintk("RPC:       impossible RPC reply size %d!\n", repsize);
>> 		goto dropit;
>> 	}
>>
>> I assumed it was needed because of the rpc-level check (for the 4  
>> bytes worth
>> of xid), not because it needed udp-level checking.
>
> The server side check programmatically guarantees we get a non-negative 
> number when we compute "bytes."

Would a BUG() accomplish the same thing?

--b.

> Thus we can use an unsigned variable and 
> eliminate a mixed sign comparison later on.
>
> We can add a "+ sizeof(u32)" to the check if you like.
>
>>> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
>>> ---
>>>
>>> net/sunrpc/svcsock.c |   20 +++++++++++++-------
>>> 1 files changed, 13 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
>>> index d077071..de29e7f 100644
>>> --- a/net/sunrpc/svcsock.c
>>> +++ b/net/sunrpc/svcsock.c
>>> @@ -431,6 +431,7 @@ static int svc_udp_recvfrom(struct svc_rqst  
>>> *rqstp)
>>> 	} buffer;
>>> 	struct cmsghdr *cmh = &buffer.hdr;
>>> 	int		err, len;
>>> +	unsigned int	bytes;
>>> 	struct msghdr msg = {
>>> 		.msg_name = svc_addr(rqstp),
>>> 		.msg_control = cmh,
>>> @@ -484,8 +485,13 @@ static int svc_udp_recvfrom(struct svc_rqst  
>>> *rqstp)
>>> 	 */
>>> 	svc_xprt_received(&svsk->sk_xprt);
>>>
>>> -	len  = skb->len - sizeof(struct udphdr);
>>> -	rqstp->rq_arg.len = len;
>>> +	if (skb->len < sizeof(struct udphdr)) {
>>> +		dprintk("svc: bad UDP datagram length: %u\n", skb->len);
>>> +		skb_free_datagram(svsk->sk_sk, skb);
>>> +		return 0;
>>> +	}
>>> +	bytes = skb->len - sizeof(struct udphdr);
>>> +	rqstp->rq_arg.len = bytes;
>>>
>>> 	rqstp->rq_prot = IPPROTO_UDP;
>>>
>>> @@ -515,7 +521,7 @@ static int svc_udp_recvfrom(struct svc_rqst  
>>> *rqstp)
>>> 		/* we can use it in-place */
>>> 		rqstp->rq_arg.head[0].iov_base = skb->data +
>>> 			sizeof(struct udphdr);
>>> -		rqstp->rq_arg.head[0].iov_len = len;
>>> +		rqstp->rq_arg.head[0].iov_len = bytes;
>>> 		if (skb_checksum_complete(skb)) {
>>> 			skb_free_datagram(svsk->sk_sk, skb);
>>> 			return 0;
>>> @@ -524,12 +530,12 @@ static int svc_udp_recvfrom(struct svc_rqst  
>>> *rqstp)
>>> 	}
>>>
>>> 	rqstp->rq_arg.page_base = 0;
>>> -	if (len <= rqstp->rq_arg.head[0].iov_len) {
>>> -		rqstp->rq_arg.head[0].iov_len = len;
>>> +	if (bytes <= rqstp->rq_arg.head[0].iov_len) {
>>> +		rqstp->rq_arg.head[0].iov_len = bytes;
>>> 		rqstp->rq_arg.page_len = 0;
>>> 		rqstp->rq_respages = rqstp->rq_pages+1;
>>> 	} else {
>>> -		rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
>>> +		rqstp->rq_arg.page_len = bytes - rqstp->rq_arg.head[0].iov_len;
>>> 		rqstp->rq_respages = rqstp->rq_pages + 1 +
>>> 			DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE);
>>> 	}
>>> @@ -537,7 +543,7 @@ static int svc_udp_recvfrom(struct svc_rqst  
>>> *rqstp)
>>> 	if (serv->sv_stats)
>>> 		serv->sv_stats->netudpcnt++;
>>>
>>> -	return len;
>>> +	return bytes;
>>> }
>>>
>>> static int
>>>
>
> --
> Chuck Lever
> chuck[dot]lever[at]oracle[dot]com
>
>
>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 06/24] SUNRPC: Sanity check incoming UDP datagram lengths properly
  2008-04-14 20:54           ` J. Bruce Fields
@ 2008-04-14 21:38             ` Chuck Lever
  0 siblings, 0 replies; 38+ messages in thread
From: Chuck Lever @ 2008-04-14 21:38 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: trond.myklebust, linux-nfs

On Apr 14, 2008, at 4:54 PM, J. Bruce Fields wrote:
> On Mon, Apr 14, 2008 at 03:55:16PM -0400, Chuck Lever wrote:
>> On Apr 14, 2008, at 2:38 PM, J. Bruce Fields wrote:
>>> On Mon, Apr 14, 2008 at 12:27:23PM -0400, Chuck Lever wrote:
>>>> Clean up: ensure svc_udp_recvfrom() is getting at least a full UDP
>>>> header
>>>> to avoid potential negative intermediate values.
>>>
>>> Is it legal in this case for skb_recv_datagram() to return an skb
>>> without at least that minimum length? (And if not, should this be a
>>> BUG()?)
>>>
>>>
>>>> A similar sanity check is already used in the RPC client.
>>>
>>> This one?:
>>>
>>> 	repsize = skb->len - sizeof(struct udphdr);
>>> 	if (repsize < 4) {
>>> 		dprintk("RPC:       impossible RPC reply size %d!\n", repsize);
>>> 		goto dropit;
>>> 	}
>>>
>>> I assumed it was needed because of the rpc-level check (for the 4
>>> bytes worth
>>> of xid), not because it needed udp-level checking.
>>
>> The server side check programmatically guarantees we get a non- 
>> negative
>> number when we compute "bytes."
>
> Would a BUG() accomplish the same thing?

udp_recvfrom doesn't check for underflow at all; it just stores the  
difference into an unsigned variable with aplomb.  I'll submit a  
replacement patch that removes the check and clarifies the description.

>> Thus we can use an unsigned variable and
>> eliminate a mixed sign comparison later on.
>>
>> We can add a "+ sizeof(u32)" to the check if you like.
>>
>>>> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
>>>> ---
>>>>
>>>> net/sunrpc/svcsock.c |   20 +++++++++++++-------
>>>> 1 files changed, 13 insertions(+), 7 deletions(-)
>>>>
>>>> diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
>>>> index d077071..de29e7f 100644
>>>> --- a/net/sunrpc/svcsock.c
>>>> +++ b/net/sunrpc/svcsock.c
>>>> @@ -431,6 +431,7 @@ static int svc_udp_recvfrom(struct svc_rqst
>>>> *rqstp)
>>>> 	} buffer;
>>>> 	struct cmsghdr *cmh = &buffer.hdr;
>>>> 	int		err, len;
>>>> +	unsigned int	bytes;
>>>> 	struct msghdr msg = {
>>>> 		.msg_name = svc_addr(rqstp),
>>>> 		.msg_control = cmh,
>>>> @@ -484,8 +485,13 @@ static int svc_udp_recvfrom(struct svc_rqst
>>>> *rqstp)
>>>> 	 */
>>>> 	svc_xprt_received(&svsk->sk_xprt);
>>>>
>>>> -	len  = skb->len - sizeof(struct udphdr);
>>>> -	rqstp->rq_arg.len = len;
>>>> +	if (skb->len < sizeof(struct udphdr)) {
>>>> +		dprintk("svc: bad UDP datagram length: %u\n", skb->len);
>>>> +		skb_free_datagram(svsk->sk_sk, skb);
>>>> +		return 0;
>>>> +	}
>>>> +	bytes = skb->len - sizeof(struct udphdr);
>>>> +	rqstp->rq_arg.len = bytes;
>>>>
>>>> 	rqstp->rq_prot = IPPROTO_UDP;
>>>>
>>>> @@ -515,7 +521,7 @@ static int svc_udp_recvfrom(struct svc_rqst
>>>> *rqstp)
>>>> 		/* we can use it in-place */
>>>> 		rqstp->rq_arg.head[0].iov_base = skb->data +
>>>> 			sizeof(struct udphdr);
>>>> -		rqstp->rq_arg.head[0].iov_len = len;
>>>> +		rqstp->rq_arg.head[0].iov_len = bytes;
>>>> 		if (skb_checksum_complete(skb)) {
>>>> 			skb_free_datagram(svsk->sk_sk, skb);
>>>> 			return 0;
>>>> @@ -524,12 +530,12 @@ static int svc_udp_recvfrom(struct svc_rqst
>>>> *rqstp)
>>>> 	}
>>>>
>>>> 	rqstp->rq_arg.page_base = 0;
>>>> -	if (len <= rqstp->rq_arg.head[0].iov_len) {
>>>> -		rqstp->rq_arg.head[0].iov_len = len;
>>>> +	if (bytes <= rqstp->rq_arg.head[0].iov_len) {
>>>> +		rqstp->rq_arg.head[0].iov_len = bytes;
>>>> 		rqstp->rq_arg.page_len = 0;
>>>> 		rqstp->rq_respages = rqstp->rq_pages+1;
>>>> 	} else {
>>>> -		rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
>>>> +		rqstp->rq_arg.page_len = bytes - rqstp->rq_arg.head[0].iov_len;
>>>> 		rqstp->rq_respages = rqstp->rq_pages + 1 +
>>>> 			DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE);
>>>> 	}
>>>> @@ -537,7 +543,7 @@ static int svc_udp_recvfrom(struct svc_rqst
>>>> *rqstp)
>>>> 	if (serv->sv_stats)
>>>> 		serv->sv_stats->netudpcnt++;
>>>>
>>>> -	return len;
>>>> +	return bytes;
>>>> }
>>>>
>>>> static int
>>>>
>>
>> --
>> Chuck Lever
>> chuck[dot]lever[at]oracle[dot]com
>>
>>
>>

--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com




^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2008-04-14 21:40 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-04-14 16:26 [PATCH 00/24] RPC server support rpcbind v4 plus additional clean ups Chuck Lever
     [not found] ` <20080414162108.12741.73233.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2008-04-14 16:26   ` [PATCH 01/24] NFS: Use NFSDBG_FILE for all fops Chuck Lever
2008-04-14 16:26   ` [PATCH 02/24] NFS: Fix trace debugging nits in write.c Chuck Lever
2008-04-14 16:27   ` [PATCH 03/24] SUNRPC: RPC server still uses 2.4 method for disabling TCP Nagle Chuck Lever
     [not found]     ` <20080414162701.12741.10868.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2008-04-14 17:38       ` J. Bruce Fields
2008-04-14 16:27   ` [PATCH 04/24] SUNRPC: Address potential buffer length overflow in svc_sendto Chuck Lever
     [not found]     ` <20080414162708.12741.71691.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2008-04-14 17:48       ` J. Bruce Fields
2008-04-14 19:43         ` Chuck Lever
2008-04-14 20:35           ` J. Bruce Fields
2008-04-14 16:27   ` [PATCH 05/24] SUNRPC: Address potential buffer length overflow in svc_tcp_sendto Chuck Lever
2008-04-14 16:27   ` [PATCH 06/24] SUNRPC: Sanity check incoming UDP datagram lengths properly Chuck Lever
     [not found]     ` <20080414162723.12741.35500.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2008-04-14 18:38       ` J. Bruce Fields
2008-04-14 19:55         ` Chuck Lever
2008-04-14 20:54           ` J. Bruce Fields
2008-04-14 21:38             ` Chuck Lever
2008-04-14 16:27   ` [PATCH 07/24] SUNRPC: Update RPC server's TCP record marker decoder Chuck Lever
     [not found]     ` <20080414162730.12741.97124.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2008-04-14 18:49       ` J. Bruce Fields
2008-04-14 16:27   ` [PATCH 08/24] SUNRPC: Use unsigned index when looping over arrays Chuck Lever
2008-04-14 16:27   ` [PATCH 09/24] " Chuck Lever
     [not found]     ` <20080414162745.12741.37176.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2008-04-14 18:51       ` J. Bruce Fields
2008-04-14 16:27   ` [PATCH 10/24] SUNRPC: Use unsigned loop and array index in svc_init_buffer() Chuck Lever
     [not found]     ` <20080414162752.12741.15628.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2008-04-14 18:51       ` J. Bruce Fields
2008-04-14 16:28   ` [PATCH 11/24] SUNRPC: Remove obsolete messages during transport connect Chuck Lever
2008-04-14 16:28   ` [PATCH 12/24] SUNRPC: More useful debugging output for rpcb client Chuck Lever
2008-04-14 16:28   ` [PATCH 13/24] SUNRPC: Document some naked integers in rpcbind client Chuck Lever
2008-04-14 16:28   ` [PATCH 14/24] SUNRPC: Use correct XDR encoding procedure for rpcbind SET/UNSET Chuck Lever
2008-04-14 16:28   ` [PATCH 15/24] SUNRPC: Introduce a specific rpcb_create for contacting localhost Chuck Lever
2008-04-14 16:28   ` [PATCH 16/24] SUNRPC: None of rpcb_create's callers wants a privileged ephemeral port Chuck Lever
2008-04-14 16:28   ` [PATCH 17/24] SUNRPC: Refactor rpcb_register to make rpcbindv4 support easier Chuck Lever
2008-04-14 16:28   ` [PATCH 18/24] SUNRPC: introduce new task flag that fails requests on xprt disconnect Chuck Lever
2008-04-14 16:28   ` [PATCH 19/24] SUNRPC: Quickly detect missing portmapper during RPC service registration Chuck Lever
2008-04-14 16:29   ` [PATCH 20/24] SUNRPC: Support registering IPv6 interfaces with local rpcbind daemon Chuck Lever
2008-04-14 16:29   ` [PATCH 21/24] SUNRPC: Split portmap unregister API into separate function Chuck Lever
2008-04-14 16:29   ` [PATCH 22/24] SUNRPC: Use the new rpcb_v4_register() API in svc_unregister() Chuck Lever
2008-04-14 16:29   ` [PATCH 23/24] SUNRPC: Use new rpcb_v4_register() interface in svc_register() Chuck Lever
2008-04-14 16:29   ` [PATCH 24/24] SUNRPC: Add kernel build option to disable server-side use of rpcbind v3/v4 Chuck Lever
2008-04-14 19:14   ` [PATCH 00/24] RPC server support rpcbind v4 plus additional clean ups J. Bruce Fields
2008-04-14 20:05     ` Chuck Lever

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox