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 22/24] NFS: Decode NFSv2 readdir reply using an xdr_stream
Date: Sun, 16 May 2010 22:48:51 -0400	[thread overview]
Message-ID: <20100517024851.20258.44548.stgit@localhost.localdomain> (raw)
In-Reply-To: <20100517023905.20258.86631.stgit-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>

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

 fs/nfs/nfs2xdr.c |  173 +++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 152 insertions(+), 21 deletions(-)

diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 565a5c6..1d65103 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -834,27 +834,6 @@ err_unmap:
 	goto out;
 }
 
-__be32 *
-nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
-{
-	if (!*p++) {
-		if (!*p)
-			return ERR_PTR(-EAGAIN);
-		entry->eof = 1;
-		return ERR_PTR(-EBADCOOKIE);
-	}
-
-	entry->ino	  = ntohl(*p++);
-	entry->len	  = ntohl(*p++);
-	entry->name	  = (const char *) p;
-	p		 += XDR_QUADLEN(entry->len);
-	entry->prev_cookie	  = entry->cookie;
-	entry->cookie	  = ntohl(*p++);
-	entry->eof	  = !p[0] && p[1];
-
-	return p;
-}
-
 /*
  * NFS XDR decode functions
  */
@@ -1110,6 +1089,158 @@ static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, __be32 *p,
 }
 
 /*
+ * 2.2.17.  entry
+ *
+ * struct entry {
+ *	unsigned fileid;
+ *	filename name;
+ *	nfscookie cookie;
+ *	entry *nextentry;
+ * };
+ *
+ * The type (size) of nfscookie isn't defined in RFC 1094.
+ * The "nextentry" field is not used; instead, each entry
+ * is preceded by a boolean "entry follows" field.
+ *
+ * The Linux implementation is limited to receiving not more
+ * than a single page of entries at a time.
+ *
+ * Here, the XDR buffer is checked for correct syntax.  The
+ * actual decoding is done by nfs_decode_entry() during
+ * subsequent nfs_readdir() calls.
+ */
+static int decode_readdirok(struct xdr_stream *xdr)
+{
+	struct xdr_buf *rcvbuf = xdr->buf;
+	struct page **page = rcvbuf->pages;
+	__be32 *p, *end, *entry, *kaddr;
+	unsigned int nr, pglen, recvd;
+	size_t hdrlen;
+
+	pglen = rcvbuf->page_len;
+	hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
+	recvd = rcvbuf->len - hdrlen;
+	if (pglen > recvd)
+		pglen = recvd;
+	xdr_read_pages(xdr, pglen);
+	kaddr = p = kmap_atomic(*page, KM_USER0);
+	end = (__be32 *)((char *)p + pglen);
+	entry = p;
+
+	/* Make sure the packet actually has a value_follows and EOF entry */
+	if ((entry + 1) > end)
+		goto short_pkt;
+
+	nr = 0;
+	for (; *p++; nr++) {
+		u32 len;
+
+		if (p + 2 > end)
+			goto short_pkt;
+		p++;	/* fileid */
+		len = be32_to_cpup(p++);
+		if (len > NFS2_MAXNAMLEN) {
+			dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
+					len);
+			goto err_unmap;
+		}
+		p += XDR_QUADLEN(len) + 1;	/* name plus cookie */
+		if (p + 2 > end)
+			goto short_pkt;
+		entry = p;
+	}
+
+	/*
+	 * Apparently some server sends responses that are a valid size, but
+	 * contain no entries, and have value_follows==0 and EOF==0. For
+	 * those, just set the EOF marker.
+	 */
+	if (!nr && entry[1] == 0) {
+		dprintk("NFS: readdir reply truncated!\n");
+		entry[1] = 1;
+	}
+out:
+	kunmap_atomic(kaddr, KM_USER0);
+	return nr;
+short_pkt:
+	/*
+	 * When we get a short packet there are 2 possibilities. We can
+	 * return an error, or fix up the response to look like a valid
+	 * response and return what we have so far. If there are no
+	 * entries and the packet was short, then return -EIO. If there
+	 * are valid entries in the response, return them and pretend that
+	 * the call was successful, but incomplete. The caller can retry the
+	 * readdir starting at the last cookie.
+	 */
+	dprintk("%s: short packet at entry %d\n", __func__, nr);
+	entry[0] = entry[1] = 0;
+	if (nr)
+		goto out;
+err_unmap:
+	kunmap_atomic(kaddr, KM_USER0);
+	return -EIO;
+}
+
+/*
+ * 2.2.17.  readdirres
+ *
+ *	union readdirres switch (stat status) {
+ *	case NFS_OK:
+ *		struct {
+ *			entry *entries;
+ *			bool eof;
+ *		} readdirok;
+ *	default:
+ *		void;
+ *	};
+ */
+static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req, __be32 *p,
+				   void *__unused)
+{
+	struct xdr_stream xdr;
+	enum nfs_stat status;
+
+	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
+	if (decode_stat(&xdr, &status) != 0)
+		return -EIO;
+	if (status != NFS_OK)
+		return nfs_stat_to_errno(status);
+	return decode_readdirok(&xdr);
+}
+
+/**
+ * nfs_decode_dirent - Decode a single NFSv2 directory entry stored in
+ *                     the local page cache.
+ * @p: pointer to buffer where entry resides
+ * @entry: entry struct to fill out with data
+ * @plus: boolean indicating whether this should be a readdirplus entry
+ *
+ * Returns the position of the next item in the buffer, or an ERR_PTR.
+ *
+ * This function is not invoked during READDIR reply processing, but
+ * rather whenever an application invokes the getdents(2) system call.
+ */
+__be32 *nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
+{
+	if (!*p++) {
+		if (!*p)
+			return ERR_PTR(-EAGAIN);
+		entry->eof = 1;
+		return ERR_PTR(-EBADCOOKIE);
+	}
+
+	entry->ino = be32_to_cpup(p++);
+	entry->len = be32_to_cpup(p++);
+	entry->name = (const char *)p;
+	p += XDR_QUADLEN(entry->len);
+	entry->prev_cookie = entry->cookie;
+	entry->cookie = be32_to_cpup(p++);
+
+	entry->eof = !p[0] && p[1];
+	return p;
+}
+
+/*
  * Decode STATFS reply
  */
 static int


  parent reply	other threads:[~2010-05-17  2:48 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   ` [PATCH 02/24] NFS: Introduce XDR helpers for basic NFSv2 data types Chuck Lever
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   ` Chuck Lever [this message]
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=20100517024851.20258.44548.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).