linux-nfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Chuck Lever <chuck.lever@oracle.com>
To: linux-nfs@vger.kernel.org
Subject: [PATCH 02/24] NFS: Introduce XDR helpers for basic NFSv2 data types
Date: Sun, 16 May 2010 22:45:55 -0400	[thread overview]
Message-ID: <20100517024554.20258.47010.stgit@localhost.localdomain> (raw)
In-Reply-To: <20100517023905.20258.86631.stgit-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>

Introduce a new set of XDR encoding/decoding functions for NFSv2 basic
types that operate on xdr_streams.  Use coding style similar to what's
in fs/nfs/nfs4xdr.c.

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

 fs/nfs/nfs2xdr.c |  342 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 342 insertions(+), 0 deletions(-)

diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 279883c..9d5159f 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -3,6 +3,11 @@
  *
  * XDR functions to encode/decode NFS RPC arguments and results.
  *
+ * NFSv2 argument and result types are defined in section 2.2 of
+ * RFC 1094: "NFS: Network File System Protocol Specification".
+ * Basic data types are defined in section 2.3 of RFC 1094.
+ *
+ *
  * Copyright (C) 1992, 1993, 1994  Rick Sladkey
  * Copyright (C) 1996 Olaf Kirch
  * 04 Aug 1998  Ion Badulescu <ionut-eQaUEPhvms7ENvBUuze7eA@public.gmane.org>
@@ -61,6 +66,343 @@
 #define NFS_readdirres_sz	(1)
 #define NFS_statfsres_sz	(1+NFS_info_sz)
 
+static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
+{
+	dprintk("NFS: %s: prematurely hit end of receive buffer. "
+		"Remaining buffer length is %tu workds.\n",
+		func, xdr->end - xdr->p);
+}
+
+/*
+ * Encode/decode NFSv2 basic data types
+ *
+ * Not all basic data types have their own encoding and decoding
+ * functions.  For run-time efficiency, some data types are encoded
+ * or decoded inline.
+ */
+
+/*
+ * 2.3.1.  stat
+ *
+ *	enum stat {
+ *		NFS_OK = 0,
+ *		...
+ *	}
+ */
+static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status)
+{
+	__be32 *p;
+
+	p = xdr_inline_decode(xdr, 4);
+	if (unlikely(p == NULL)) {
+		print_overflow_msg(__func__, xdr);
+		return -EIO;
+	}
+	*status = be32_to_cpup(p);
+	return 0;
+}
+
+/*
+ * 2.3.3.  fhandle
+ *
+ *	typedef opaque fhandle[FHSIZE];
+ */
+static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
+{
+	__be32 *p;
+
+	BUG_ON(unlikely(fh->size != NFS2_FHSIZE));
+	p = xdr_reserve_space(xdr, NFS2_FHSIZE);
+	BUG_ON(unlikely(p == NULL));
+	xdr_encode_opaque_fixed(p, &fh->data, NFS2_FHSIZE);
+}
+
+static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
+{
+	__be32 *p;
+
+	p = xdr_inline_decode(xdr, NFS2_FHSIZE);
+	if (unlikely(p == NULL)) {
+		print_overflow_msg(__func__, xdr);
+		return -EIO;
+	}
+	memcpy(&fh->data, p, NFS2_FHSIZE);
+	fh->size = NFS2_FHSIZE;
+	return 0;
+}
+
+/*
+ * 2.3.4.  timeval
+ *
+ *	struct timeval {
+ *		unsigned int seconds;
+ *		unsigned int useconds;
+ *	};
+ */
+static void encode_timeval(struct xdr_stream *xdr, const struct timespec *timep)
+{
+	__be32 *p;
+	u32 usec;
+
+	p = xdr_reserve_space(xdr, 8);
+	BUG_ON(unlikely(p == NULL));
+	usec = timep->tv_nsec ? (timep->tv_nsec / NSEC_PER_USEC) : 0;
+	*p++ = cpu_to_be32(timep->tv_sec);
+	*p = cpu_to_be32(usec);
+}
+
+/*
+ * Passing the invalid value useconds=1000000 is a Sun convention
+ * for "set to current server time".  It's needed to make
+ * permissions checks for the "touch" program across v2 mounts to
+ * Solaris and Irix servers work correctly.  Note that this is not
+ * discussed in RFC 1094; see description of sattr in section 6.1
+ * of "NFS Illustrated" by Brent Callaghan, Addison-Wesley,
+ * ISBN 0-201-32750-5
+ */
+static void encode_current_server_timeval(struct xdr_stream *xdr,
+					  const struct timespec *timep)
+{
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, 8);
+	BUG_ON(unlikely(p == NULL));
+	*p++ = cpu_to_be32(timep->tv_sec);
+	*p = cpu_to_be32(1000000);
+}
+
+/*
+ * 2.3.5.  fattr
+ *
+ *	struct fattr {
+ *		ftype		type;
+ *		unsigned int	mode;
+ *		unsigned int	nlink;
+ *		unsigned int	uid;
+ *		unsigned int	gid;
+ *		unsigned int	size;
+ *		unsigned int	blocksize;
+ *		unsigned int	rdev;
+ *		unsigned int	blocks;
+ *		unsigned int	fsid;
+ *		unsigned int	fileid;
+ *		timeval		atime;
+ *		timeval		mtime;
+ *		timeval		ctime;
+ *	};
+ *
+ */
+static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
+{
+	u32 rdev, type;
+	__be32 *p;
+
+	p = xdr_inline_decode(xdr, NFS_fattr_sz << 2);
+	if (unlikely(p == NULL)) {
+		print_overflow_msg(__func__, xdr);
+		return -EIO;
+	}
+
+	fattr->valid |= NFS_ATTR_FATTR;
+
+	type			= be32_to_cpup(p++);	/* 2.3.2. ftype */
+	if (unlikely(type > NF2FIFO))
+		type = NFBAD;
+
+	fattr->mode		= be32_to_cpup(p++);
+	fattr->nlink		= be32_to_cpup(p++);
+	fattr->uid		= be32_to_cpup(p++);
+	fattr->gid		= be32_to_cpup(p++);
+	fattr->size		= be32_to_cpup(p++);
+	fattr->du.nfs2.blocksize = be32_to_cpup(p++);
+	rdev			= be32_to_cpup(p++);
+	fattr->rdev		= new_decode_dev(rdev);
+	fattr->du.nfs2.blocks	= be32_to_cpup(p++);
+	fattr->fsid.major	= be32_to_cpup(p++);
+	fattr->fsid.minor	= 0;
+	fattr->fileid		= be32_to_cpup(p++);
+
+	/* 2.3.4. timeval */
+	fattr->atime.tv_sec	= be32_to_cpup(p++);
+	fattr->atime.tv_nsec	= be32_to_cpup(p++) * NSEC_PER_USEC;
+
+	/* 2.3.4. timeval */
+	fattr->mtime.tv_sec	= be32_to_cpup(p++);
+	fattr->mtime.tv_nsec	= be32_to_cpup(p++) * NSEC_PER_USEC;
+
+	/* 2.3.4. timeval */
+	fattr->ctime.tv_sec	= be32_to_cpup(p++);
+	fattr->ctime.tv_nsec	= be32_to_cpup(p++) * NSEC_PER_USEC;
+
+	/*
+	 * RFC 1094 section 2.3.2 suggests that NF2SOCK and NF2FIFO
+	 * are not supported by version 2 of the protocol.
+	 */
+	if (type == (u32)NFCHR && rdev == (u32)NFS2_FIFO_DEV) {
+		fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
+		fattr->rdev = 0;
+	}
+
+	return 0;
+}
+
+/*
+ * 2.3.6.  sattr
+ *
+ *	struct sattr {
+ *		unsigned int	mode;
+ *		unsigned int	uid;
+ *		unsigned int	gid;
+ *		unsigned int	size;
+ *		timeval		atime;
+ *		timeval		mtime;
+ *	};
+ */
+
+#define NFS2_SATTR_NOT_SET	(0xffffffff)
+
+static void encode_time_not_set(struct xdr_stream *xdr)
+{
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, 8);
+	BUG_ON(unlikely(p == NULL));
+	*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
+	*p = cpu_to_be32(NFS2_SATTR_NOT_SET);
+}
+
+static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr)
+{
+	unsigned int valid = attr->ia_valid;
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, 16);
+	BUG_ON(unlikely(p == NULL));
+	if (valid & ATTR_MODE)
+		*p++ = cpu_to_be32(attr->ia_mode);
+	else
+		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
+	if (valid & ATTR_UID)
+		*p++ = cpu_to_be32(attr->ia_uid);
+	else
+		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
+	if (valid & ATTR_GID)
+		*p++ = cpu_to_be32(attr->ia_gid);
+	else
+		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
+	if (valid & ATTR_SIZE)
+		*p++ = cpu_to_be32((u32)attr->ia_size);
+	else
+		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
+
+	if (valid & ATTR_ATIME_SET)
+		encode_timeval(xdr, &attr->ia_atime);
+	else if (valid & ATTR_ATIME)
+		encode_current_server_timeval(xdr, &attr->ia_atime);
+	else
+		encode_time_not_set(xdr);
+	if (valid & ATTR_MTIME_SET)
+		encode_timeval(xdr, &attr->ia_mtime);
+	else if (valid & ATTR_MTIME)
+		encode_current_server_timeval(xdr, &attr->ia_mtime);
+	else
+		encode_time_not_set(xdr);
+}
+
+/*
+ * 2.3.7.  filename
+ *
+ *	typedef string filename<MAXNAMLEN>;
+ */
+static void encode_filename(struct xdr_stream *xdr, const char *name, u32 count)
+{
+	__be32 *p;
+
+	BUG_ON(unlikely(count > NFS2_MAXNAMLEN));
+	p = xdr_reserve_space(xdr, 4 + count);
+	BUG_ON(unlikely(p == NULL));
+	*p++ = cpu_to_be32(count);
+	xdr_encode_opaque_fixed(p, name, count);
+}
+
+/*
+ * 2.3.8.  path
+ *
+ *	typedef string path<MAXPATHLEN>;
+ */
+static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 count)
+{
+	__be32 *p;
+
+	BUG_ON(count > NFS_MAXPATHLEN);
+	p = xdr_reserve_space(xdr, 4);
+	BUG_ON(unlikely(p == NULL));
+	*p = cpu_to_be32(count);
+	xdr_write_pages(xdr, pages, 0, count);
+}
+
+static int decode_path(struct xdr_stream *xdr)
+{
+	u32 recvd, count;
+	size_t hdrlen;
+	__be32 *p;
+
+	p = xdr_inline_decode(xdr, 4);
+	if (unlikely(p == NULL)) {
+		print_overflow_msg(__func__, xdr);
+		return -EIO;
+	}
+	count = be32_to_cpup(p);
+
+	if (count >= xdr->buf->page_len || count > NFS_MAXPATHLEN) {
+		dprintk("NFS: server returned giant pathname!\n");
+		return -ENAMETOOLONG;
+	}
+	hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
+	recvd = xdr->buf->len - hdrlen;
+	if (count > recvd) {
+		dprintk("NFS: server cheating in pathname result: "
+			"count %u > recvd %u\n", count, recvd);
+		return -EIO;
+	}
+
+	xdr_read_pages(xdr, count);
+	xdr_terminate_string(xdr->buf, count);
+	return 0;
+}
+
+/*
+ * 2.3.10.  diropargs
+ *
+ *	struct diropargs {
+ *		fhandle  dir;
+ *		filename name;
+ *	};
+ */
+static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh,
+			     const char *name, u32 count)
+{
+	encode_fhandle(xdr, fh);
+	encode_filename(xdr, name, count);
+}
+
+/*
+ * 2.3.11.  diropok
+ *
+ *	struct {
+ *		fhandle file;
+ *		fattr   attributes;
+ *	} diropok;
+ */
+static int decode_diropok(struct xdr_stream *xdr, struct nfs_fh *fh,
+			  struct nfs_fattr *fattr)
+{
+	if (decode_fhandle(xdr, fh) != 0)
+		return -EIO;
+	return decode_fattr(xdr, fattr);
+}
+
+
 /*
  * Common NFS XDR functions as inlines
  */


  parent reply	other threads:[~2010-05-17  2:45 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-05-17  2:45 [PATCH 00/24] Modernize NFSv2 XDR encoder/decoders Chuck Lever
     [not found] ` <20100517023905.20258.86631.stgit-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2010-05-17  2:45   ` [PATCH 01/24] SUNRPC: Refactor logic to NUL-terminate strings in pages Chuck Lever
2010-05-17  2:45   ` Chuck Lever [this message]
2010-05-17  2:46   ` [PATCH 03/24] NFS: Encode NFSv2 fhandle argument using an xdr_stream Chuck Lever
2010-05-17  2:46   ` [PATCH 04/24] NFS: Encode v2 setattr " Chuck Lever
2010-05-17  2:46   ` [PATCH 05/24] NFS: Encode dirop " Chuck Lever
2010-05-17  2:46   ` [PATCH 06/24] NFS: Encode NFSv2 readlink " Chuck Lever
2010-05-17  2:46   ` [PATCH 07/24] NFS: Encode NFSv2 read " Chuck Lever
2010-05-17  2:46   ` [PATCH 08/24] NFS: Encode NFSv2 write " Chuck Lever
2010-05-17  2:46   ` [PATCH 09/24] NFS: Encode NFSv2 create " Chuck Lever
2010-05-17  2:47   ` [PATCH 10/24] NFS: Encode NFSv2 rename " Chuck Lever
2010-05-17  2:47   ` [PATCH 11/24] NFS: Encode NFSv2 link " Chuck Lever
2010-05-17  2:47   ` [PATCH 12/24] NFS: Encode NFSv2 symlink " Chuck Lever
2010-05-17  2:47   ` [PATCH 13/24] NFS: Encode NFSv2 readdir " Chuck Lever
2010-05-17  2:47   ` [PATCH 14/24] NFS: Replace old NFSv2 encoder functions with xdr_stream-based ones Chuck Lever
2010-05-17  2:47   ` [PATCH 15/24] NFS: Use the "nfs_stat" enum for nfs_stat_to_errno() Chuck Lever
2010-05-17  2:47   ` [PATCH 16/24] NFS: Decode NFSv2 stat reply using an xdr_stream Chuck Lever
2010-05-17  2:48   ` [PATCH 17/24] NFS: Decode NFSv2 attrstat " Chuck Lever
2010-05-17  2:48   ` [PATCH 18/24] NFS: Decode NFSv2 dirop " Chuck Lever
2010-05-17  2:48   ` [PATCH 19/24] NFS: Decode NFSv2 readlink " Chuck Lever
2010-05-17  2:48   ` [PATCH 20/24] NFS: Decode NFSv2 read " Chuck Lever
2010-05-17  2:48   ` [PATCH 21/24] NFS: Decode NFSv2 write " Chuck Lever
2010-05-17  2:48   ` [PATCH 22/24] NFS: Decode NFSv2 readdir " Chuck Lever
2010-05-17  2:49   ` [PATCH 23/24] NFS: Decode NFSv2 statfs " Chuck Lever
2010-05-17  2:49   ` [PATCH 24/24] NFS: Replace old NFSv2 decoder functions with xdr_stream-based ones Chuck Lever
2010-05-17 20:57   ` [PATCH 00/24] Modernize NFSv2 XDR encoder/decoders Chuck Lever

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20100517024554.20258.47010.stgit@localhost.localdomain \
    --to=chuck.lever@oracle.com \
    --cc=linux-nfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).