Commit f5dcccd6 authored by Chuck Lever's avatar Chuck Lever

NFSD: Update the NFSv2 READDIR entry encoder to use struct xdr_stream

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 94c8f8c6
...@@ -559,14 +559,27 @@ static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp, ...@@ -559,14 +559,27 @@ static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp,
struct nfsd_readdirres *resp, struct nfsd_readdirres *resp,
int count) int count)
{ {
struct xdr_buf *buf = &resp->dirlist;
struct xdr_stream *xdr = &resp->xdr;
count = min_t(u32, count, PAGE_SIZE); count = min_t(u32, count, PAGE_SIZE);
/* Convert byte count to number of words (i.e. >> 2), memset(buf, 0, sizeof(*buf));
* and reserve room for the NULL ptr & eof flag (-2 words) */
resp->buflen = (count >> 2) - 2;
resp->buffer = page_address(*rqstp->rq_next_page); /* Reserve room for the NULL ptr & eof flag (-2 words) */
buf->buflen = count - sizeof(__be32) * 2;
buf->pages = rqstp->rq_next_page;
rqstp->rq_next_page++; rqstp->rq_next_page++;
/* This is xdr_init_encode(), but it assumes that
* the head kvec has already been consumed. */
xdr_set_scratch_buffer(xdr, NULL, 0);
xdr->buf = buf;
xdr->page_ptr = buf->pages;
xdr->iov = NULL;
xdr->p = page_address(*buf->pages);
xdr->end = xdr->p + (PAGE_SIZE >> 2);
xdr->rqst = NULL;
} }
/* /*
...@@ -585,12 +598,11 @@ nfsd_proc_readdir(struct svc_rqst *rqstp) ...@@ -585,12 +598,11 @@ nfsd_proc_readdir(struct svc_rqst *rqstp)
nfsd_init_dirlist_pages(rqstp, resp, argp->count); nfsd_init_dirlist_pages(rqstp, resp, argp->count);
resp->offset = NULL;
resp->common.err = nfs_ok; resp->common.err = nfs_ok;
/* Read directory and encode entries on the fly */ resp->cookie_offset = 0;
offset = argp->cookie; offset = argp->cookie;
resp->status = nfsd_readdir(rqstp, &argp->fh, &offset, resp->status = nfsd_readdir(rqstp, &argp->fh, &offset,
&resp->common, nfssvc_encode_entry); &resp->common, nfs2svc_encode_entry);
nfssvc_encode_nfscookie(resp, offset); nfssvc_encode_nfscookie(resp, offset);
fh_put(&argp->fh); fh_put(&argp->fh);
......
...@@ -576,12 +576,13 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) ...@@ -576,12 +576,13 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
{ {
struct xdr_stream *xdr = &rqstp->rq_res_stream; struct xdr_stream *xdr = &rqstp->rq_res_stream;
struct nfsd_readdirres *resp = rqstp->rq_resp; struct nfsd_readdirres *resp = rqstp->rq_resp;
struct xdr_buf *dirlist = &resp->dirlist;
if (!svcxdr_encode_stat(xdr, resp->status)) if (!svcxdr_encode_stat(xdr, resp->status))
return 0; return 0;
switch (resp->status) { switch (resp->status) {
case nfs_ok: case nfs_ok:
xdr_write_pages(xdr, &resp->page, 0, resp->count << 2); xdr_write_pages(xdr, dirlist->pages, 0, dirlist->len);
/* no more entries */ /* no more entries */
if (xdr_stream_encode_item_absent(xdr) < 0) if (xdr_stream_encode_item_absent(xdr) < 0)
return 0; return 0;
...@@ -623,14 +624,86 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p) ...@@ -623,14 +624,86 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p)
* @resp: readdir result context * @resp: readdir result context
* @offset: offset cookie to encode * @offset: offset cookie to encode
* *
* The buffer space for the offset cookie has already been reserved
* by svcxdr_encode_entry_common().
*/ */
void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset) void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset)
{ {
if (!resp->offset) __be32 cookie = cpu_to_be32(offset);
if (!resp->cookie_offset)
return; return;
*resp->offset = cpu_to_be32(offset); write_bytes_to_xdr_buf(&resp->dirlist, resp->cookie_offset, &cookie,
resp->offset = NULL; sizeof(cookie));
resp->cookie_offset = 0;
}
static bool
svcxdr_encode_entry_common(struct nfsd_readdirres *resp, const char *name,
int namlen, loff_t offset, u64 ino)
{
struct xdr_buf *dirlist = &resp->dirlist;
struct xdr_stream *xdr = &resp->xdr;
if (xdr_stream_encode_item_present(xdr) < 0)
return false;
/* fileid */
if (xdr_stream_encode_u32(xdr, (u32)ino) < 0)
return false;
/* name */
if (xdr_stream_encode_opaque(xdr, name, min(namlen, NFS2_MAXNAMLEN)) < 0)
return false;
/* cookie */
resp->cookie_offset = dirlist->len;
if (xdr_stream_encode_u32(xdr, ~0U) < 0)
return false;
return true;
}
/**
* nfs2svc_encode_entry - encode one NFSv2 READDIR entry
* @data: directory context
* @name: name of the object to be encoded
* @namlen: length of that name, in bytes
* @offset: the offset of the previous entry
* @ino: the fileid of this entry
* @d_type: unused
*
* Return values:
* %0: Entry was successfully encoded.
* %-EINVAL: An encoding problem occured, secondary status code in resp->common.err
*
* On exit, the following fields are updated:
* - resp->xdr
* - resp->common.err
* - resp->cookie_offset
*/
int nfs2svc_encode_entry(void *data, const char *name, int namlen,
loff_t offset, u64 ino, unsigned int d_type)
{
struct readdir_cd *ccd = data;
struct nfsd_readdirres *resp = container_of(ccd,
struct nfsd_readdirres,
common);
unsigned int starting_length = resp->dirlist.len;
/* The offset cookie for the previous entry */
nfssvc_encode_nfscookie(resp, offset);
if (!svcxdr_encode_entry_common(resp, name, namlen, offset, ino))
goto out_toosmall;
xdr_commit_encode(&resp->xdr);
resp->common.err = nfs_ok;
return 0;
out_toosmall:
resp->cookie_offset = 0;
resp->common.err = nfserr_toosmall;
resp->dirlist.len = starting_length;
return -EINVAL;
} }
int int
......
...@@ -106,15 +106,20 @@ struct nfsd_readres { ...@@ -106,15 +106,20 @@ struct nfsd_readres {
}; };
struct nfsd_readdirres { struct nfsd_readdirres {
/* Components of the reply */
__be32 status; __be32 status;
int count; int count;
/* Used to encode the reply's entry list */
struct xdr_stream xdr;
struct xdr_buf dirlist;
struct readdir_cd common; struct readdir_cd common;
__be32 * buffer; __be32 * buffer;
int buflen; int buflen;
__be32 * offset; __be32 * offset;
struct page *page; struct page *page;
unsigned int cookie_offset;
}; };
struct nfsd_statfsres { struct nfsd_statfsres {
...@@ -159,6 +164,8 @@ int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *); ...@@ -159,6 +164,8 @@ int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *);
int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *); int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *);
void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset); void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset);
int nfs2svc_encode_entry(void *data, const char *name, int namlen,
loff_t offset, u64 ino, unsigned int d_type);
int nfssvc_encode_entry(void *, const char *name, int nfssvc_encode_entry(void *, const char *name,
int namlen, loff_t offset, u64 ino, unsigned int); int namlen, loff_t offset, u64 ino, unsigned int);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment