Commit 335c5fc7 authored by Neil Brown's avatar Neil Brown Committed by Linus Torvalds

[PATCH] kNFSd: nfsd_readdir changes.

nfsd_readdir - the common readdir code for all version of nfsd,
contains a number of version-specific things with appropriate checks,
and also does some xdr-encoding which rightly belongs elsewhere.

This patch simplifies nfsd_readdir to do just the core stuff, and moves
the version specifics into version specific files, and the xdr encoding
into xdr encoding files.
parent f319e5fa
...@@ -457,11 +457,18 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, ...@@ -457,11 +457,18 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
/* Read directory and encode entries on the fly */ /* Read directory and encode entries on the fly */
fh_copy(&resp->fh, &argp->fh); fh_copy(&resp->fh, &argp->fh);
nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t) argp->cookie,
nfs3svc_encode_entry, resp->buflen = count;
buffer, &count, argp->verf, NULL); resp->common.err = nfs_ok;
resp->buffer = buffer;
resp->offset = NULL;
resp->rqstp = rqstp;
nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie,
&resp->common, nfs3svc_encode_entry);
memcpy(resp->verf, argp->verf, 8); memcpy(resp->verf, argp->verf, 8);
resp->count = count; resp->count = resp->buffer - buffer;
if (resp->offset)
xdr_encode_hyper(resp->offset, argp->cookie);
RETURN_STATUS(nfserr); RETURN_STATUS(nfserr);
} }
...@@ -476,6 +483,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, ...@@ -476,6 +483,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
{ {
u32 * buffer; u32 * buffer;
int nfserr, count, want; int nfserr, count, want;
loff_t offset;
dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n", dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
SVCFH_fmt(&argp->fh), SVCFH_fmt(&argp->fh),
...@@ -492,11 +500,18 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp, ...@@ -492,11 +500,18 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
/* Read directory and encode entries on the fly */ /* Read directory and encode entries on the fly */
fh_copy(&resp->fh, &argp->fh); fh_copy(&resp->fh, &argp->fh);
nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t) argp->cookie,
nfs3svc_encode_entry_plus, resp->buflen = count;
buffer, &count, argp->verf, NULL); resp->common.err = nfs_ok;
resp->buffer = buffer;
resp->rqstp = rqstp;
offset = argp->cookie;
nfserr = nfsd_readdir(rqstp, &resp->fh, &offset,
&resp->common, nfs3svc_encode_entry_plus);
memcpy(resp->verf, argp->verf, 8); memcpy(resp->verf, argp->verf, 8);
resp->count = count; resp->count = resp->buffer - buffer;
if (resp->offset)
xdr_encode_hyper(resp->offset, offset);
RETURN_STATUS(nfserr); RETURN_STATUS(nfserr);
} }
......
...@@ -644,10 +644,13 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p, ...@@ -644,10 +644,13 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
struct nfsd3_readdirres *resp) struct nfsd3_readdirres *resp)
{ {
p = encode_post_op_attr(rqstp, p, &resp->fh); p = encode_post_op_attr(rqstp, p, &resp->fh);
if (resp->status == 0) { if (resp->status == 0) {
/* stupid readdir cookie */ /* stupid readdir cookie */
memcpy(p, resp->verf, 8); p += 2; memcpy(p, resp->verf, 8); p += 2;
p += XDR_QUADLEN(resp->count); p = resp->buffer;
*p++ = 0; /* no more entries */
*p++ = htonl(resp->common.err == nfserr_eof);
} }
return xdr_ressize_check(rqstp, p); return xdr_ressize_check(rqstp, p);
...@@ -666,20 +669,16 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p, ...@@ -666,20 +669,16 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
#define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1) #define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1)
#define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2)) #define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
static int static int
encode_entry(struct readdir_cd *cd, const char *name, encode_entry(struct readdir_cd *ccd, const char *name,
int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus) int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus)
{ {
struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres, common);
u32 *p = cd->buffer; u32 *p = cd->buffer;
int buflen, slen, elen; int buflen, slen, elen;
if (cd->offset) if (cd->offset)
xdr_encode_hyper(cd->offset, (u64) offset); xdr_encode_hyper(cd->offset, (u64) offset);
/* nfsd_readdir calls us with name == 0 when it wants us to
* set the last offset entry. */
if (name == 0)
return 0;
/* /*
dprintk("encode_entry(%.*s @%ld%s)\n", dprintk("encode_entry(%.*s @%ld%s)\n",
namlen, name, (long) offset, plus? " plus" : ""); namlen, name, (long) offset, plus? " plus" : "");
...@@ -693,7 +692,7 @@ encode_entry(struct readdir_cd *cd, const char *name, ...@@ -693,7 +692,7 @@ encode_entry(struct readdir_cd *cd, const char *name,
elen = slen + NFS3_ENTRY_BAGGAGE elen = slen + NFS3_ENTRY_BAGGAGE
+ (plus? NFS3_ENTRYPLUS_BAGGAGE : 0); + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
if ((buflen = cd->buflen - elen) < 0) { if ((buflen = cd->buflen - elen) < 0) {
cd->eob = 1; cd->common.err = nfserr_readdir_nospc;
return -EINVAL; return -EINVAL;
} }
*p++ = xdr_one; /* mark entry present */ *p++ = xdr_one; /* mark entry present */
...@@ -709,8 +708,8 @@ encode_entry(struct readdir_cd *cd, const char *name, ...@@ -709,8 +708,8 @@ encode_entry(struct readdir_cd *cd, const char *name,
struct svc_export *exp; struct svc_export *exp;
struct dentry *dparent, *dchild; struct dentry *dparent, *dchild;
dparent = cd->dirfh->fh_dentry; dparent = cd->fh.fh_dentry;
exp = cd->dirfh->fh_export; exp = cd->fh.fh_export;
fh_init(&fh, NFS3_FHSIZE); fh_init(&fh, NFS3_FHSIZE);
if (isdotent(name, namlen)) { if (isdotent(name, namlen)) {
...@@ -724,7 +723,7 @@ encode_entry(struct readdir_cd *cd, const char *name, ...@@ -724,7 +723,7 @@ encode_entry(struct readdir_cd *cd, const char *name,
dchild = lookup_one_len(name, dparent,namlen); dchild = lookup_one_len(name, dparent,namlen);
if (IS_ERR(dchild)) if (IS_ERR(dchild))
goto noexec; goto noexec;
if (fh_compose(&fh, exp, dchild, cd->dirfh) != 0 || !dchild->d_inode) if (fh_compose(&fh, exp, dchild, &cd->fh) != 0 || !dchild->d_inode)
goto noexec; goto noexec;
p = encode_post_op_attr(cd->rqstp, p, &fh); p = encode_post_op_attr(cd->rqstp, p, &fh);
*p++ = xdr_one; /* yes, a file handle follows */ *p++ = xdr_one; /* yes, a file handle follows */
...@@ -735,6 +734,7 @@ encode_entry(struct readdir_cd *cd, const char *name, ...@@ -735,6 +734,7 @@ encode_entry(struct readdir_cd *cd, const char *name,
out: out:
cd->buflen = buflen; cd->buflen = buflen;
cd->buffer = p; cd->buffer = p;
cd->common.err = nfs_ok;
return 0; return 0;
noexec: noexec:
......
...@@ -1313,9 +1313,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, ...@@ -1313,9 +1313,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
} }
static int static int
nfsd4_encode_dirent(struct readdir_cd *cd, const char *name, int namlen, nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen,
loff_t offset, ino_t ino, unsigned int d_type) loff_t offset, ino_t ino, unsigned int d_type)
{ {
struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common);
int buflen; int buflen;
u32 *p = cd->buffer; u32 *p = cd->buffer;
u32 *attrlenp; u32 *attrlenp;
...@@ -1324,17 +1325,14 @@ nfsd4_encode_dirent(struct readdir_cd *cd, const char *name, int namlen, ...@@ -1324,17 +1325,14 @@ nfsd4_encode_dirent(struct readdir_cd *cd, const char *name, int namlen,
int nfserr = 0; int nfserr = 0;
/* In nfsv4, "." and ".." never make it onto the wire.. */ /* In nfsv4, "." and ".." never make it onto the wire.. */
if (name && isdotent(name, namlen)) if (name && isdotent(name, namlen)) {
cd->common.err = nfs_ok;
return 0; return 0;
}
if (cd->offset) if (cd->offset)
xdr_encode_hyper(cd->offset, (u64) offset); xdr_encode_hyper(cd->offset, (u64) offset);
/* nfsd_readdir calls us with name == 0 when it wants us to
* set the last offset entry. */
if (name == 0)
return 0;
buflen = cd->buflen - 4 - XDR_QUADLEN(namlen); buflen = cd->buflen - 4 - XDR_QUADLEN(namlen);
if (buflen < 0) if (buflen < 0)
goto nospc; goto nospc;
...@@ -1347,8 +1345,8 @@ nfsd4_encode_dirent(struct readdir_cd *cd, const char *name, int namlen, ...@@ -1347,8 +1345,8 @@ nfsd4_encode_dirent(struct readdir_cd *cd, const char *name, int namlen,
/* /*
* Now we come to the ugly part: writing the fattr for this entry. * Now we come to the ugly part: writing the fattr for this entry.
*/ */
bmval0 = cd->bmval[0]; bmval0 = cd->rd_bmval[0];
bmval1 = cd->bmval[1]; bmval1 = cd->rd_bmval[1];
if ((bmval0 & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_FILEID)) || bmval1) { if ((bmval0 & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_FILEID)) || bmval1) {
/* /*
* "Heavyweight" case: we have no choice except to * "Heavyweight" case: we have no choice except to
...@@ -1356,14 +1354,14 @@ nfsd4_encode_dirent(struct readdir_cd *cd, const char *name, int namlen, ...@@ -1356,14 +1354,14 @@ nfsd4_encode_dirent(struct readdir_cd *cd, const char *name, int namlen,
* only Windows clients will trigger this code * only Windows clients will trigger this code
* path. * path.
*/ */
dentry = lookup_one_len(name, cd->dirfh->fh_dentry, namlen); dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
if (IS_ERR(dentry)) { if (IS_ERR(dentry)) {
nfserr = nfserrno(PTR_ERR(dentry)); nfserr = nfserrno(PTR_ERR(dentry));
goto error; goto error;
} }
nfserr = nfsd4_encode_fattr(NULL, cd->dirfh->fh_export, nfserr = nfsd4_encode_fattr(NULL, cd->rd_fhp->fh_export,
dentry, p, &buflen, cd->bmval); dentry, p, &buflen, cd->rd_bmval);
dput(dentry); dput(dentry);
if (!nfserr) { if (!nfserr) {
...@@ -1384,7 +1382,7 @@ nfsd4_encode_dirent(struct readdir_cd *cd, const char *name, int namlen, ...@@ -1384,7 +1382,7 @@ nfsd4_encode_dirent(struct readdir_cd *cd, const char *name, int namlen,
* entire READDIR operation(!) * entire READDIR operation(!)
*/ */
if (!(bmval0 & FATTR4_WORD0_RDATTR_ERROR)) { if (!(bmval0 & FATTR4_WORD0_RDATTR_ERROR)) {
cd->nfserr = nfserr; cd->common.err = nfserr;
return -EINVAL; return -EINVAL;
} }
...@@ -1414,10 +1412,11 @@ nfsd4_encode_dirent(struct readdir_cd *cd, const char *name, int namlen, ...@@ -1414,10 +1412,11 @@ nfsd4_encode_dirent(struct readdir_cd *cd, const char *name, int namlen,
out: out:
cd->buflen -= (p - cd->buffer); cd->buflen -= (p - cd->buffer);
cd->buffer = p; cd->buffer = p;
cd->common.err = nfs_ok;
return 0; return 0;
nospc: nospc:
cd->eob = 1; cd->common.err = nfserr_readdir_nospc;
return -EINVAL; return -EINVAL;
} }
...@@ -1643,6 +1642,7 @@ static int ...@@ -1643,6 +1642,7 @@ static int
nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_readdir *readdir) nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_readdir *readdir)
{ {
int maxcount; int maxcount;
loff_t offset;
ENCODE_HEAD; ENCODE_HEAD;
if (nfserr) if (nfserr)
...@@ -1667,17 +1667,26 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re ...@@ -1667,17 +1667,26 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re
WRITE32(0); WRITE32(0);
WRITE32(0); WRITE32(0);
readdir->common.err = 0;
readdir->buflen = maxcount;
readdir->buffer = p;
readdir->offset = NULL;
offset = readdir->rd_cookie;
nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp, nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp,
readdir->rd_cookie, nfsd4_encode_dirent, &offset,
p, &maxcount, NULL, readdir->rd_bmval); &readdir->common, nfsd4_encode_dirent);
if (nfserr == nfs_ok &&
readdir->common.err == nfserr_readdir_nospc &&
readdir->buffer == p)
nfserr = nfserr_readdir_nospc;
if (!nfserr) { if (!nfserr) {
/* if (readdir->offset)
* nfsd_readdir() expects 'maxcount' to be a count of xdr_encode_hyper(readdir->offset, offset);
* words, but fills it in with a count of bytes at the
* end! p = readdir->buffer;
*/ *p++ = 0; /* no more entries */
BUG_ON(maxcount & 3); *p++ = htonl(readdir->common.err == nfserr_eof);
p += (maxcount >> 2);
ADJUST_ARGS(); ADJUST_ARGS();
} }
return nfserr; return nfserr;
......
...@@ -471,6 +471,7 @@ nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp, ...@@ -471,6 +471,7 @@ nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
{ {
u32 * buffer; u32 * buffer;
int nfserr, count; int nfserr, count;
loff_t offset;
dprintk("nfsd: READDIR %s %d bytes at %d\n", dprintk("nfsd: READDIR %s %d bytes at %d\n",
SVCFH_fmt(&argp->fh), SVCFH_fmt(&argp->fh),
...@@ -488,11 +489,18 @@ nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp, ...@@ -488,11 +489,18 @@ nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
if (count < 0) if (count < 0)
count = 0; count = 0;
resp->buffer = buffer;
resp->offset = NULL;
resp->buflen = count;
resp->common.err = nfs_ok;
/* Read directory and encode entries on the fly */ /* Read directory and encode entries on the fly */
nfserr = nfsd_readdir(rqstp, &argp->fh, (loff_t) argp->cookie, offset = argp->cookie;
nfssvc_encode_entry, nfserr = nfsd_readdir(rqstp, &argp->fh, &offset,
buffer, &count, NULL, NULL); &resp->common, nfssvc_encode_entry);
resp->count = count;
resp->count = resp->buffer - buffer;
if (resp->offset)
*resp->offset = (u32)offset;
fh_put(&argp->fh); fh_put(&argp->fh);
return nfserr; return nfserr;
......
...@@ -380,7 +380,10 @@ int ...@@ -380,7 +380,10 @@ int
nfssvc_encode_readdirres(struct svc_rqst *rqstp, u32 *p, nfssvc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
struct nfsd_readdirres *resp) struct nfsd_readdirres *resp)
{ {
p += XDR_QUADLEN(resp->count); p = resp->buffer;
*p++ = 0; /* no more entries */
*p++ = htonl((resp->common.err == nfserr_eof));
return xdr_ressize_check(rqstp, p); return xdr_ressize_check(rqstp, p);
} }
...@@ -399,9 +402,10 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, u32 *p, ...@@ -399,9 +402,10 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, u32 *p,
} }
int int
nfssvc_encode_entry(struct readdir_cd *cd, const char *name, nfssvc_encode_entry(struct readdir_cd *ccd, const char *name,
int namlen, loff_t offset, ino_t ino, unsigned int d_type) int namlen, loff_t offset, ino_t ino, unsigned int d_type)
{ {
struct nfsd_readdirres *cd = container_of(ccd, struct nfsd_readdirres, common);
u32 *p = cd->buffer; u32 *p = cd->buffer;
int buflen, slen; int buflen, slen;
...@@ -410,8 +414,10 @@ nfssvc_encode_entry(struct readdir_cd *cd, const char *name, ...@@ -410,8 +414,10 @@ nfssvc_encode_entry(struct readdir_cd *cd, const char *name,
namlen, name, offset, ino); namlen, name, offset, ino);
*/ */
if (offset > ~((u32) 0)) if (offset > ~((u32) 0)) {
cd->common.err = nfserr_fbig;
return -EINVAL; return -EINVAL;
}
if (cd->offset) if (cd->offset)
*cd->offset = htonl(offset); *cd->offset = htonl(offset);
if (namlen > NFS2_MAXNAMLEN) if (namlen > NFS2_MAXNAMLEN)
...@@ -419,7 +425,7 @@ nfssvc_encode_entry(struct readdir_cd *cd, const char *name, ...@@ -419,7 +425,7 @@ nfssvc_encode_entry(struct readdir_cd *cd, const char *name,
slen = XDR_QUADLEN(namlen); slen = XDR_QUADLEN(namlen);
if ((buflen = cd->buflen - slen - 4) < 0) { if ((buflen = cd->buflen - slen - 4) < 0) {
cd->eob = 1; cd->common.err = nfserr_readdir_nospc;
return -EINVAL; return -EINVAL;
} }
*p++ = xdr_one; /* mark entry present */ *p++ = xdr_one; /* mark entry present */
...@@ -430,6 +436,7 @@ nfssvc_encode_entry(struct readdir_cd *cd, const char *name, ...@@ -430,6 +436,7 @@ nfssvc_encode_entry(struct readdir_cd *cd, const char *name,
cd->buflen = buflen; cd->buflen = buflen;
cd->buffer = p; cd->buffer = p;
cd->common.err = nfs_ok;
return 0; return 0;
} }
......
...@@ -1386,16 +1386,15 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, ...@@ -1386,16 +1386,15 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
/* /*
* Read entries from a directory. * Read entries from a directory.
* The verifier is an NFSv3 thing we ignore for now. * The NFSv3/4 verifier we ignore for now.
*/ */
int int
nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
encode_dent_fn func, u32 *buffer, int *countp, u32 *verf, u32 *bmval) struct readdir_cd *cdp, encode_dent_fn func)
{ {
u32 *p; int err;
int oldlen, eof, err;
struct file file; struct file file;
struct readdir_cd cd; loff_t offset = *offsetp;
err = nfsd_open(rqstp, fhp, S_IFDIR, MAY_READ, &file); err = nfsd_open(rqstp, fhp, S_IFDIR, MAY_READ, &file);
if (err) if (err)
...@@ -1405,17 +1404,6 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, ...@@ -1405,17 +1404,6 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
file.f_pos = offset; file.f_pos = offset;
/* Set up the readdir context */
memset(&cd, 0, sizeof(cd));
cd.rqstp = rqstp;
cd.buffer = buffer;
cd.buflen = *countp; /* count of words */
cd.dirfh = fhp;
if (bmval) {
cd.bmval[0] = bmval[0];
cd.bmval[1] = bmval[1];
}
/* /*
* Read the directory entries. This silly loop is necessary because * Read the directory entries. This silly loop is necessary because
* readdir() is not guaranteed to fill up the entire buffer, but * readdir() is not guaranteed to fill up the entire buffer, but
...@@ -1423,49 +1411,21 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, ...@@ -1423,49 +1411,21 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
*/ */
do { do {
oldlen = cd.buflen; cdp->err = nfserr_eof; /* will be cleared on successful read */
err = vfs_readdir(&file, (filldir_t) func, cdp);
err = vfs_readdir(&file, (filldir_t) func, &cd); } while (err >=0 && cdp->err == nfs_ok);
if (err < 0)
goto out_nfserr;
err = cd.nfserr;
if (err) if (err)
goto out_close; err = nfserrno(err);
} while (oldlen != cd.buflen && !cd.eob);
err = nfserr_readdir_nospc;
if (rqstp->rq_vers == 4 && cd.eob && cd.buffer == buffer)
goto out_close;
/* If we didn't fill the buffer completely, we're at EOF */
eof = !cd.eob;
if (cd.offset) {
if (rqstp->rq_vers > 2)
(void)xdr_encode_hyper(cd.offset, file.f_pos);
else else
*cd.offset = htonl(file.f_pos); err = cdp->err;
} *offsetp = file.f_pos;
p = cd.buffer;
*p++ = 0; /* no more entries */
*p++ = htonl(eof); /* end of directory */
*countp = (caddr_t) p - (caddr_t) buffer;
dprintk("nfsd: readdir result %d bytes, eof %d offset %d\n", if (err == nfserr_eof || err == nfserr_readdir_nospc)
*countp, eof, err = nfs_ok; /* can still be found in ->err */
cd.offset? ntohl(*cd.offset) : -1);
err = 0;
out_close: out_close:
nfsd_close(&file); nfsd_close(&file);
out: out:
return err; return err;
out_nfserr:
err = nfserrno(err);
goto out_close;
} }
/* /*
......
...@@ -48,16 +48,7 @@ ...@@ -48,16 +48,7 @@
* Callback function for readdir * Callback function for readdir
*/ */
struct readdir_cd { struct readdir_cd {
struct svc_rqst * rqstp; int err; /* 0, nfserr, or nfserr_eof */
struct svc_fh * dirfh;
u32 * buffer;
int buflen;
u32 * offset; /* previous dirent->d_next */
char plus; /* readdirplus */
char eob; /* end of buffer */
char dotonly;
int nfserr; /* v4 only */
u32 bmval[2]; /* v4 only */
}; };
typedef int (*encode_dent_fn)(struct readdir_cd *, const char *, typedef int (*encode_dent_fn)(struct readdir_cd *, const char *,
int, loff_t, ino_t, unsigned int); int, loff_t, ino_t, unsigned int);
...@@ -117,9 +108,7 @@ int nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type, ...@@ -117,9 +108,7 @@ int nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type,
int nfsd_truncate(struct svc_rqst *, struct svc_fh *, int nfsd_truncate(struct svc_rqst *, struct svc_fh *,
unsigned long size); unsigned long size);
int nfsd_readdir(struct svc_rqst *, struct svc_fh *, int nfsd_readdir(struct svc_rqst *, struct svc_fh *,
loff_t, encode_dent_fn, loff_t *, struct readdir_cd *, encode_dent_fn);
u32 *buffer, int *countp, u32 *verf,
u32 *bmval);
int nfsd_statfs(struct svc_rqst *, struct svc_fh *, int nfsd_statfs(struct svc_rqst *, struct svc_fh *,
struct statfs *); struct statfs *);
...@@ -180,10 +169,13 @@ void nfsd_lockd_shutdown(void); ...@@ -180,10 +169,13 @@ void nfsd_lockd_shutdown(void);
#define nfserr_readdir_nospc __constant_htonl(NFSERR_READDIR_NOSPC) #define nfserr_readdir_nospc __constant_htonl(NFSERR_READDIR_NOSPC)
#define nfserr_bad_xdr __constant_htonl(NFSERR_BAD_XDR) #define nfserr_bad_xdr __constant_htonl(NFSERR_BAD_XDR)
/* error code for internal use - if a request fails due to /* error codes for internal use */
* kmalloc failure, it gets dropped. Client should resend eventually /* if a request fails due to kmalloc failure, it gets dropped.
* Client should resend eventually
*/ */
#define nfserr_dropit __constant_htonl(30000) #define nfserr_dropit __constant_htonl(30000)
/* end-of-file indicator in readdir */
#define nfserr_eof __constant_htonl(30001)
/* Check for dir entries '.' and '..' */ /* Check for dir entries '.' and '..' */
#define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.')) #define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.'))
......
...@@ -98,6 +98,11 @@ struct nfsd_readres { ...@@ -98,6 +98,11 @@ struct nfsd_readres {
struct nfsd_readdirres { struct nfsd_readdirres {
int count; int count;
struct readdir_cd common;
u32 * buffer;
int buflen;
u32 * offset;
}; };
struct nfsd_statfsres { struct nfsd_statfsres {
......
...@@ -156,6 +156,13 @@ struct nfsd3_readdirres { ...@@ -156,6 +156,13 @@ struct nfsd3_readdirres {
struct svc_fh fh; struct svc_fh fh;
int count; int count;
__u32 verf[2]; __u32 verf[2];
struct readdir_cd common;
u32 * buffer;
int buflen;
u32 * offset;
struct svc_rqst * rqstp;
}; };
struct nfsd3_fsstatres { struct nfsd3_fsstatres {
......
...@@ -185,6 +185,11 @@ struct nfsd4_readdir { ...@@ -185,6 +185,11 @@ struct nfsd4_readdir {
u32 rd_bmval[2]; /* request */ u32 rd_bmval[2]; /* request */
struct svc_rqst *rd_rqstp; /* response */ struct svc_rqst *rd_rqstp; /* response */
struct svc_fh * rd_fhp; /* response */ struct svc_fh * rd_fhp; /* response */
struct readdir_cd common;
u32 * buffer;
int buflen;
u32 * offset;
}; };
struct nfsd4_readlink { struct nfsd4_readlink {
......
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