All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.