From: "J. Bruce Fields" <bfields@redhat.com>
To: linux-nfs@vger.kernel.org
Cc: "J. Bruce Fields" <bfields@redhat.com>
Subject: [PATCH 7/7] nfsd4: readdir encoding
Date: Wed, 23 Jan 2013 17:55:38 -0500 [thread overview]
Message-ID: <1358981738-5649-8-git-send-email-bfields@redhat.com> (raw)
In-Reply-To: <1358981738-5649-1-git-send-email-bfields@redhat.com>
From: "J. Bruce Fields" <bfields@redhat.com>
Rewrite readdir encoding using the new xdr primitives. This allows us
to return more than 4k of data in a readdir reply, improving performance
on large directories.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfs4xdr.c | 157 +++++++++++++++++++++++++++++-------------------------
fs/nfsd/xdr4.h | 5 +-
2 files changed, 85 insertions(+), 77 deletions(-)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index a378435..84ad067 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1870,6 +1870,11 @@ static void write64(struct svcxdr_ptr *ptr, u64 n)
writemem(ptr, i, sizeof(i));
}
+static void write_nfserr(struct svcxdr_ptr *ptr, __be32 err)
+{
+ writemem(ptr, &err, sizeof(err));
+}
+
static bool write_opaque(struct svcxdr_stream *xdr, const void *data, int len)
{
struct svcxdr_ptr ptr;
@@ -2672,7 +2677,7 @@ static inline int attributes_need_mount(u32 *bmval)
static __be32
nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
- const char *name, int namlen, __be32 **p, int buflen)
+ const char *name, int namlen, struct svcxdr_stream *xdr)
{
struct svc_export *exp = cd->rd_fhp->fh_export;
struct dentry *dentry;
@@ -2724,7 +2729,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
}
out_encode:
- nfserr = nfsd4_encode_fattr_to_buffer(p, buflen, NULL, exp, dentry, cd->rd_bmval,
+ nfserr = nfsd4_encode_fattr(xdr, NULL, exp, dentry, cd->rd_bmval,
cd->rd_rqstp, ignore_crossmnt);
out_put:
dput(dentry);
@@ -2732,18 +2737,20 @@ out_put:
return nfserr;
}
-static __be32 *
-nfsd4_encode_rdattr_error(__be32 *p, int buflen, __be32 nfserr)
+static bool
+nfsd4_encode_rdattr_error(struct svcxdr_stream *xdr, __be32 nfserr)
{
- if (buflen < 6)
- return NULL;
- *p++ = htonl(2);
- *p++ = htonl(FATTR4_WORD0_RDATTR_ERROR); /* bmval0 */
- *p++ = htonl(0); /* bmval1 */
+ struct svcxdr_ptr ptr;
- *p++ = htonl(4); /* attribute length */
- *p++ = nfserr; /* no htonl */
- return p;
+ if (!svcxdr_reserve_space(xdr, &ptr, 5*4))
+ return false;
+ write32(&ptr, 2);
+ write32(&ptr, FATTR4_WORD0_RDATTR_ERROR); /* bmval0 */
+ write32(&ptr, 0); /* bmval1 */
+
+ write32(&ptr, 4); /* attribute length */
+ write_nfserr(&ptr, nfserr);
+ return true;
}
static int
@@ -2752,9 +2759,10 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
{
struct readdir_cd *ccd = ccdv;
struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common);
- int buflen;
- __be32 *p = cd->buffer;
- __be32 *cookiep;
+ struct svcxdr_stream *xdr = cd->xdr;
+ struct svcxdr_ptr start = xdr->ptr;
+ struct svcxdr_ptr cookiep;
+ struct svcxdr_ptr ptr;
__be32 nfserr = nfserr_toosmall;
/* In nfsv4, "." and ".." never make it onto the wire.. */
@@ -2763,27 +2771,30 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
return 0;
}
- if (cd->offset)
- xdr_encode_hyper(cd->offset, (u64) offset);
+ if (cd->offset.p) {
+ ptr = cd->offset;
+ write64(&ptr, (u64)offset);
+ }
- buflen = cd->buflen - 4 - XDR_QUADLEN(namlen);
- if (buflen < 0)
+ if (!svcxdr_reserve_space(xdr, &ptr, 3*4))
goto fail;
+ write32(&ptr, 1); /* mark entry present */
+ cookiep = ptr;
+ write64(&ptr, NFS_OFFSET_MAX); /* offset of next entry */
- *p++ = xdr_one; /* mark entry present */
- cookiep = p;
- p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */
- p = xdr_encode_array(p, name, namlen); /* name length & name */
+ if (!write_opaque(xdr, name, namlen))
+ goto fail;
- nfserr = nfsd4_encode_dirent_fattr(cd, name, namlen, &p, buflen);
+ nfserr = nfsd4_encode_dirent_fattr(cd, name, namlen, xdr);
switch (nfserr) {
case nfs_ok:
break;
case nfserr_resource:
nfserr = nfserr_toosmall;
goto fail;
- case nfserr_noent:
- goto skip_entry;
+ case nfserr_noent: /* skip entry: */
+ svcxdr_reset(xdr, &start);
+ goto out;
default:
/*
* If the client requested the RDATTR_ERROR attribute,
@@ -2794,19 +2805,17 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
*/
if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR))
goto fail;
- p = nfsd4_encode_rdattr_error(p, buflen, nfserr);
- if (p == NULL) {
+ if (!nfsd4_encode_rdattr_error(xdr, nfserr)) {
nfserr = nfserr_toosmall;
goto fail;
}
}
- cd->buflen -= (p - cd->buffer);
- cd->buffer = p;
cd->offset = cookiep;
-skip_entry:
+out:
cd->common.err = nfs_ok;
return 0;
fail:
+ svcxdr_reset(xdr, &start);
cd->common.err = nfserr;
return -EINVAL;
}
@@ -3231,46 +3240,45 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
{
int maxcount;
loff_t offset;
- __be32 *page, *savep, *tailbase;
- __be32 *p;
+ struct svcxdr_stream xdr;
+ struct svcxdr_ptr p;
+ struct svcxdr_ptr savep;
if (nfserr)
return nfserr;
- if (resp->xbuf->page_len)
- return nfserr_resource;
if (!*resp->rqstp->rq_next_page)
return nfserr_resource;
- RESERVE_SPACE(NFS4_VERIFIER_SIZE);
- savep = p;
-
- /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */
- WRITE32(0);
- WRITE32(0);
- ADJUST_ARGS();
- resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base;
- tailbase = p;
-
- maxcount = PAGE_SIZE;
+ nfserr = svcxdr_stream_init_from_resp(&xdr, resp);
+ if (nfserr)
+ return nfserr;
+ maxcount = svc_max_payload(resp->rqstp);
if (maxcount > readdir->rd_maxcount)
maxcount = readdir->rd_maxcount;
-
/*
- * Convert from bytes to words, account for the two words already
- * written, make sure to leave two words at the end for the next
- * pointer and eof field.
+ * Allow space for the two words (entry follows, eof) at the
+ * end. Note we generally assume rd_maxcount is at fault.
+ * Which is the most likely case. If someone sent a readdir at
+ * the end of an extremely long compound this might result in us
+ * returning the wrong error:
*/
- maxcount = (maxcount >> 2) - 4;
- if (maxcount < 0) {
- nfserr = nfserr_toosmall;
+ maxcount -= 8;
+ nfserr = nfserr_toosmall;
+ if (maxcount < 0)
goto err_no_verf;
- }
- page = page_address(*(resp->rqstp->rq_next_page++));
+ xdr.maxbytes = maxcount;
+ if (!svcxdr_reserve_space(&xdr, &p, 8))
+ goto err_no_verf;
+ savep = p;
+
+ /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */
+ write32(&p, 0);
+ write32(&p, 0);
+
+ readdir->xdr = &xdr;
readdir->common.err = 0;
- readdir->buflen = maxcount;
- readdir->buffer = page;
- readdir->offset = NULL;
+ readdir->offset.p = NULL;
offset = readdir->rd_cookie;
nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp,
@@ -3278,30 +3286,31 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
&readdir->common, nfsd4_encode_dirent);
if (nfserr == nfs_ok &&
readdir->common.err == nfserr_toosmall &&
- readdir->buffer == page)
+ xdr.ptr.p == xdr.last_commit.p + 2) /* We made no progress at all */
nfserr = nfserr_toosmall;
if (nfserr)
goto err_no_verf;
- if (readdir->offset)
- xdr_encode_hyper(readdir->offset, offset);
-
- p = readdir->buffer;
- *p++ = 0; /* no more entries */
- *p++ = htonl(readdir->common.err == nfserr_eof);
- resp->xbuf->page_len = ((char*)p) -
- (char*)page_address(*(resp->rqstp->rq_next_page-1));
+ if (readdir->offset.p) {
+ p = readdir->offset;
+ write64(&p, offset);
+ }
+ xdr.maxbytes += 8;
+ if (!svcxdr_reserve_space(&xdr, &p, 8)) {
+ WARN_ON_ONCE(1);
+ goto err_no_verf;
+ }
+ write32(&p, 0); /* no more entries */
+ write32(&p, readdir->common.err == nfserr_eof);
- /* Use rest of head for padding and remaining ops: */
- resp->xbuf->tail[0].iov_base = tailbase;
- resp->xbuf->tail[0].iov_len = 0;
- resp->p = resp->xbuf->tail[0].iov_base;
- resp->end = resp->p + (PAGE_SIZE - resp->xbuf->head[0].iov_len)/4;
+ svcxdr_stream_update_resp(&xdr, resp);
return 0;
err_no_verf:
- p = savep;
- ADJUST_ARGS();
+ /*
+ * returning without svcxdr_stream_update_resp will leave
+ * xdr_buf unchanged, as if we'd encoded nothing:
+ */
return nfserr;
}
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 36b8c2c..9c58f05 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -299,9 +299,8 @@ struct nfsd4_readdir {
struct svc_fh * rd_fhp; /* response */
struct readdir_cd common;
- __be32 * buffer;
- int buflen;
- __be32 * offset;
+ struct svcxdr_stream *xdr;
+ struct svcxdr_ptr offset;
};
struct nfsd4_release_lockowner {
--
1.7.11.7
prev parent reply other threads:[~2013-01-23 22:55 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-01-23 22:55 draft server xdr rewrite J. Bruce Fields
2013-01-23 22:55 ` [PATCH 1/7] nfsd4: reserve space for integrity/privacy J. Bruce Fields
2013-01-23 22:55 ` [PATCH 2/7] nfsd4: simplify nfsd4_encode_fattr interface slightly J. Bruce Fields
2013-01-23 22:55 ` [PATCH 3/7] nfsd4: nfsd4_encode_fattr cleanup J. Bruce Fields
2013-01-23 22:55 ` [PATCH 4/7] nfsd4: encode_rdattr_error cleanup J. Bruce Fields
2013-01-23 22:55 ` [PATCH 5/7] nfsd4: rewrite xdr encoding of attributes J. Bruce Fields
2013-01-24 5:22 ` Myklebust, Trond
2013-01-24 14:58 ` J. Bruce Fields
2013-01-24 15:06 ` Myklebust, Trond
2013-01-24 16:14 ` J. Bruce Fields
2013-01-24 17:03 ` Myklebust, Trond
2013-01-24 20:45 ` J. Bruce Fields
2013-01-23 22:55 ` [PATCH 6/7] nfsd4: track maximum bytes J. Bruce Fields
2013-01-23 22:55 ` J. Bruce Fields [this message]
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=1358981738-5649-8-git-send-email-bfields@redhat.com \
--to=bfields@redhat.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.