Commit f0af2210 authored by Chuck Lever's avatar Chuck Lever Committed by J. Bruce Fields

NFSD: Call NFSv2 encoders on error returns

Remove special dispatcher logic for NFSv2 error responses. These are
rare to the point of becoming extinct, but all NFS responses have to
pay the cost of the extra conditional branches.

With this change, the NFSv2 error cases now get proper
xdr_ressize_check() calls.
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 1841b9b6
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include "vfs.h" #include "vfs.h"
#define NFSDDBG_FACILITY NFSDDBG_PROC #define NFSDDBG_FACILITY NFSDDBG_PROC
#define RETURN_STATUS(st) { resp->status = (st); return (st); }
/* /*
* NULL call. * NULL call.
...@@ -35,24 +34,25 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp) ...@@ -35,24 +34,25 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
struct posix_acl *acl; struct posix_acl *acl;
struct inode *inode; struct inode *inode;
svc_fh *fh; svc_fh *fh;
__be32 nfserr = 0;
dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
fh = fh_copy(&resp->fh, &argp->fh); fh = fh_copy(&resp->fh, &argp->fh);
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
if (nfserr) if (resp->status != nfs_ok)
RETURN_STATUS(nfserr); goto out;
inode = d_inode(fh->fh_dentry); inode = d_inode(fh->fh_dentry);
if (argp->mask & ~NFS_ACL_MASK) if (argp->mask & ~NFS_ACL_MASK) {
RETURN_STATUS(nfserr_inval); resp->status = nfserr_inval;
goto out;
}
resp->mask = argp->mask; resp->mask = argp->mask;
nfserr = fh_getattr(fh, &resp->stat); resp->status = fh_getattr(fh, &resp->stat);
if (nfserr) if (resp->status != nfs_ok)
RETURN_STATUS(nfserr); goto out;
if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
acl = get_acl(inode, ACL_TYPE_ACCESS); acl = get_acl(inode, ACL_TYPE_ACCESS);
...@@ -61,7 +61,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp) ...@@ -61,7 +61,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
} }
if (IS_ERR(acl)) { if (IS_ERR(acl)) {
nfserr = nfserrno(PTR_ERR(acl)); resp->status = nfserrno(PTR_ERR(acl));
goto fail; goto fail;
} }
resp->acl_access = acl; resp->acl_access = acl;
...@@ -71,19 +71,20 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp) ...@@ -71,19 +71,20 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
of a non-directory! */ of a non-directory! */
acl = get_acl(inode, ACL_TYPE_DEFAULT); acl = get_acl(inode, ACL_TYPE_DEFAULT);
if (IS_ERR(acl)) { if (IS_ERR(acl)) {
nfserr = nfserrno(PTR_ERR(acl)); resp->status = nfserrno(PTR_ERR(acl));
goto fail; goto fail;
} }
resp->acl_default = acl; resp->acl_default = acl;
} }
/* resp->acl_{access,default} are released in nfssvc_release_getacl. */ /* resp->acl_{access,default} are released in nfssvc_release_getacl. */
RETURN_STATUS(0); out:
return resp->status;
fail: fail:
posix_acl_release(resp->acl_access); posix_acl_release(resp->acl_access);
posix_acl_release(resp->acl_default); posix_acl_release(resp->acl_default);
RETURN_STATUS(nfserr); goto out;
} }
/* /*
...@@ -95,14 +96,13 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp) ...@@ -95,14 +96,13 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
struct nfsd_attrstat *resp = rqstp->rq_resp; struct nfsd_attrstat *resp = rqstp->rq_resp;
struct inode *inode; struct inode *inode;
svc_fh *fh; svc_fh *fh;
__be32 nfserr = 0;
int error; int error;
dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
fh = fh_copy(&resp->fh, &argp->fh); fh = fh_copy(&resp->fh, &argp->fh);
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
if (nfserr) if (resp->status != nfs_ok)
goto out; goto out;
inode = d_inode(fh->fh_dentry); inode = d_inode(fh->fh_dentry);
...@@ -124,19 +124,20 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp) ...@@ -124,19 +124,20 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
fh_drop_write(fh); fh_drop_write(fh);
nfserr = fh_getattr(fh, &resp->stat); resp->status = fh_getattr(fh, &resp->stat);
out: out:
/* argp->acl_{access,default} may have been allocated in /* argp->acl_{access,default} may have been allocated in
nfssvc_decode_setaclargs. */ nfssvc_decode_setaclargs. */
posix_acl_release(argp->acl_access); posix_acl_release(argp->acl_access);
posix_acl_release(argp->acl_default); posix_acl_release(argp->acl_default);
return nfserr; return resp->status;
out_drop_lock: out_drop_lock:
fh_unlock(fh); fh_unlock(fh);
fh_drop_write(fh); fh_drop_write(fh);
out_errno: out_errno:
nfserr = nfserrno(error); resp->status = nfserrno(error);
goto out; goto out;
} }
...@@ -147,15 +148,16 @@ static __be32 nfsacld_proc_getattr(struct svc_rqst *rqstp) ...@@ -147,15 +148,16 @@ static __be32 nfsacld_proc_getattr(struct svc_rqst *rqstp)
{ {
struct nfsd_fhandle *argp = rqstp->rq_argp; struct nfsd_fhandle *argp = rqstp->rq_argp;
struct nfsd_attrstat *resp = rqstp->rq_resp; struct nfsd_attrstat *resp = rqstp->rq_resp;
__be32 nfserr;
dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
fh_copy(&resp->fh, &argp->fh); fh_copy(&resp->fh, &argp->fh);
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
if (nfserr) if (resp->status != nfs_ok)
return nfserr; goto out;
nfserr = fh_getattr(&resp->fh, &resp->stat); resp->status = fh_getattr(&resp->fh, &resp->stat);
return nfserr; out:
return resp->status;
} }
/* /*
...@@ -165,7 +167,6 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp) ...@@ -165,7 +167,6 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp)
{ {
struct nfsd3_accessargs *argp = rqstp->rq_argp; struct nfsd3_accessargs *argp = rqstp->rq_argp;
struct nfsd3_accessres *resp = rqstp->rq_resp; struct nfsd3_accessres *resp = rqstp->rq_resp;
__be32 nfserr;
dprintk("nfsd: ACCESS(2acl) %s 0x%x\n", dprintk("nfsd: ACCESS(2acl) %s 0x%x\n",
SVCFH_fmt(&argp->fh), SVCFH_fmt(&argp->fh),
...@@ -173,11 +174,12 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp) ...@@ -173,11 +174,12 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp)
fh_copy(&resp->fh, &argp->fh); fh_copy(&resp->fh, &argp->fh);
resp->access = argp->access; resp->access = argp->access;
nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL); resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
if (nfserr) if (resp->status != nfs_ok)
return nfserr; goto out;
nfserr = fh_getattr(&resp->fh, &resp->stat); resp->status = fh_getattr(&resp->fh, &resp->stat);
return nfserr; out:
return resp->status;
} }
/* /*
...@@ -273,6 +275,9 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) ...@@ -273,6 +275,9 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
int n; int n;
int w; int w;
if (resp->status != nfs_ok)
return xdr_ressize_check(rqstp, p);
/* /*
* Since this is version 2, the check for nfserr in * Since this is version 2, the check for nfserr in
* nfsd_dispatch actually ensures the following cannot happen. * nfsd_dispatch actually ensures the following cannot happen.
...@@ -312,6 +317,9 @@ static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p) ...@@ -312,6 +317,9 @@ static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p)
{ {
struct nfsd_attrstat *resp = rqstp->rq_resp; struct nfsd_attrstat *resp = rqstp->rq_resp;
if (resp->status != nfs_ok)
return xdr_ressize_check(rqstp, p);
p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat); p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
return xdr_ressize_check(rqstp, p); return xdr_ressize_check(rqstp, p);
} }
...@@ -321,6 +329,9 @@ static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p) ...@@ -321,6 +329,9 @@ static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p)
{ {
struct nfsd3_accessres *resp = rqstp->rq_resp; struct nfsd3_accessres *resp = rqstp->rq_resp;
if (resp->status != nfs_ok)
return xdr_ressize_check(rqstp, p);
p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat); p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
*p++ = htonl(resp->access); *p++ = htonl(resp->access);
return xdr_ressize_check(rqstp, p); return xdr_ressize_check(rqstp, p);
......
...@@ -13,25 +13,12 @@ ...@@ -13,25 +13,12 @@
#define NFSDDBG_FACILITY NFSDDBG_PROC #define NFSDDBG_FACILITY NFSDDBG_PROC
static __be32 static __be32
nfsd_proc_null(struct svc_rqst *rqstp) nfsd_proc_null(struct svc_rqst *rqstp)
{ {
return nfs_ok; return nfs_ok;
} }
static __be32
nfsd_return_attrs(__be32 err, struct nfsd_attrstat *resp)
{
if (err) return err;
return fh_getattr(&resp->fh, &resp->stat);
}
static __be32
nfsd_return_dirop(__be32 err, struct nfsd_diropres *resp)
{
if (err) return err;
return fh_getattr(&resp->fh, &resp->stat);
}
/* /*
* Get a file's attributes * Get a file's attributes
* N.B. After this call resp->fh needs an fh_put * N.B. After this call resp->fh needs an fh_put
...@@ -41,13 +28,17 @@ nfsd_proc_getattr(struct svc_rqst *rqstp) ...@@ -41,13 +28,17 @@ nfsd_proc_getattr(struct svc_rqst *rqstp)
{ {
struct nfsd_fhandle *argp = rqstp->rq_argp; struct nfsd_fhandle *argp = rqstp->rq_argp;
struct nfsd_attrstat *resp = rqstp->rq_resp; struct nfsd_attrstat *resp = rqstp->rq_resp;
__be32 nfserr;
dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
fh_copy(&resp->fh, &argp->fh); fh_copy(&resp->fh, &argp->fh);
nfserr = fh_verify(rqstp, &resp->fh, 0, resp->status = fh_verify(rqstp, &resp->fh, 0,
NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT); NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
return nfsd_return_attrs(nfserr, resp); if (resp->status != nfs_ok)
goto out;
resp->status = fh_getattr(&resp->fh, &resp->stat);
out:
return resp->status;
} }
/* /*
...@@ -61,7 +52,6 @@ nfsd_proc_setattr(struct svc_rqst *rqstp) ...@@ -61,7 +52,6 @@ nfsd_proc_setattr(struct svc_rqst *rqstp)
struct nfsd_attrstat *resp = rqstp->rq_resp; struct nfsd_attrstat *resp = rqstp->rq_resp;
struct iattr *iap = &argp->attrs; struct iattr *iap = &argp->attrs;
struct svc_fh *fhp; struct svc_fh *fhp;
__be32 nfserr;
dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n", dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n",
SVCFH_fmt(&argp->fh), SVCFH_fmt(&argp->fh),
...@@ -93,9 +83,9 @@ nfsd_proc_setattr(struct svc_rqst *rqstp) ...@@ -93,9 +83,9 @@ nfsd_proc_setattr(struct svc_rqst *rqstp)
*/ */
time64_t delta = iap->ia_atime.tv_sec - ktime_get_real_seconds(); time64_t delta = iap->ia_atime.tv_sec - ktime_get_real_seconds();
nfserr = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP); resp->status = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
if (nfserr) if (resp->status != nfs_ok)
goto done; return resp->status;
if (delta < 0) if (delta < 0)
delta = -delta; delta = -delta;
...@@ -110,9 +100,13 @@ nfsd_proc_setattr(struct svc_rqst *rqstp) ...@@ -110,9 +100,13 @@ nfsd_proc_setattr(struct svc_rqst *rqstp)
} }
} }
nfserr = nfsd_setattr(rqstp, fhp, iap, 0, (time64_t)0); resp->status = nfsd_setattr(rqstp, fhp, iap, 0, (time64_t)0);
done: if (resp->status != nfs_ok)
return nfsd_return_attrs(nfserr, resp); goto out;
resp->status = fh_getattr(&resp->fh, &resp->stat);
out:
return resp->status;
} }
/* Obsolete, replaced by MNTPROC_MNT. */ /* Obsolete, replaced by MNTPROC_MNT. */
...@@ -133,17 +127,20 @@ nfsd_proc_lookup(struct svc_rqst *rqstp) ...@@ -133,17 +127,20 @@ nfsd_proc_lookup(struct svc_rqst *rqstp)
{ {
struct nfsd_diropargs *argp = rqstp->rq_argp; struct nfsd_diropargs *argp = rqstp->rq_argp;
struct nfsd_diropres *resp = rqstp->rq_resp; struct nfsd_diropres *resp = rqstp->rq_resp;
__be32 nfserr;
dprintk("nfsd: LOOKUP %s %.*s\n", dprintk("nfsd: LOOKUP %s %.*s\n",
SVCFH_fmt(&argp->fh), argp->len, argp->name); SVCFH_fmt(&argp->fh), argp->len, argp->name);
fh_init(&resp->fh, NFS_FHSIZE); fh_init(&resp->fh, NFS_FHSIZE);
nfserr = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len, resp->status = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
&resp->fh); &resp->fh);
fh_put(&argp->fh); fh_put(&argp->fh);
return nfsd_return_dirop(nfserr, resp); if (resp->status != nfs_ok)
goto out;
resp->status = fh_getattr(&resp->fh, &resp->stat);
out:
return resp->status;
} }
/* /*
...@@ -154,16 +151,15 @@ nfsd_proc_readlink(struct svc_rqst *rqstp) ...@@ -154,16 +151,15 @@ nfsd_proc_readlink(struct svc_rqst *rqstp)
{ {
struct nfsd_readlinkargs *argp = rqstp->rq_argp; struct nfsd_readlinkargs *argp = rqstp->rq_argp;
struct nfsd_readlinkres *resp = rqstp->rq_resp; struct nfsd_readlinkres *resp = rqstp->rq_resp;
__be32 nfserr;
dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh)); dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
/* Read the symlink. */ /* Read the symlink. */
resp->len = NFS_MAXPATHLEN; resp->len = NFS_MAXPATHLEN;
nfserr = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len); resp->status = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len);
fh_put(&argp->fh); fh_put(&argp->fh);
return nfserr; return resp->status;
} }
/* /*
...@@ -175,7 +171,6 @@ nfsd_proc_read(struct svc_rqst *rqstp) ...@@ -175,7 +171,6 @@ nfsd_proc_read(struct svc_rqst *rqstp)
{ {
struct nfsd_readargs *argp = rqstp->rq_argp; struct nfsd_readargs *argp = rqstp->rq_argp;
struct nfsd_readres *resp = rqstp->rq_resp; struct nfsd_readres *resp = rqstp->rq_resp;
__be32 nfserr;
u32 eof; u32 eof;
dprintk("nfsd: READ %s %d bytes at %d\n", dprintk("nfsd: READ %s %d bytes at %d\n",
...@@ -197,14 +192,17 @@ nfsd_proc_read(struct svc_rqst *rqstp) ...@@ -197,14 +192,17 @@ nfsd_proc_read(struct svc_rqst *rqstp)
svc_reserve_auth(rqstp, (19<<2) + argp->count + 4); svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
resp->count = argp->count; resp->count = argp->count;
nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), resp->status = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
argp->offset, argp->offset,
rqstp->rq_vec, argp->vlen, rqstp->rq_vec, argp->vlen,
&resp->count, &resp->count,
&eof); &eof);
if (resp->status != nfs_ok)
goto out;
if (nfserr) return nfserr; resp->status = fh_getattr(&resp->fh, &resp->stat);
return fh_getattr(&resp->fh, &resp->stat); out:
return resp->status;
} }
/* Reserved */ /* Reserved */
...@@ -223,7 +221,6 @@ nfsd_proc_write(struct svc_rqst *rqstp) ...@@ -223,7 +221,6 @@ nfsd_proc_write(struct svc_rqst *rqstp)
{ {
struct nfsd_writeargs *argp = rqstp->rq_argp; struct nfsd_writeargs *argp = rqstp->rq_argp;
struct nfsd_attrstat *resp = rqstp->rq_resp; struct nfsd_attrstat *resp = rqstp->rq_resp;
__be32 nfserr;
unsigned long cnt = argp->len; unsigned long cnt = argp->len;
unsigned int nvecs; unsigned int nvecs;
...@@ -233,12 +230,20 @@ nfsd_proc_write(struct svc_rqst *rqstp) ...@@ -233,12 +230,20 @@ nfsd_proc_write(struct svc_rqst *rqstp)
nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages, nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages,
&argp->first, cnt); &argp->first, cnt);
if (!nvecs) if (!nvecs) {
return nfserr_io; resp->status = nfserr_io;
nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), goto out;
}
resp->status = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
argp->offset, rqstp->rq_vec, nvecs, argp->offset, rqstp->rq_vec, nvecs,
&cnt, NFS_DATA_SYNC, NULL); &cnt, NFS_DATA_SYNC, NULL);
return nfsd_return_attrs(nfserr, resp); if (resp->status != nfs_ok)
goto out;
resp->status = fh_getattr(&resp->fh, &resp->stat);
out:
return resp->status;
} }
/* /*
...@@ -258,7 +263,6 @@ nfsd_proc_create(struct svc_rqst *rqstp) ...@@ -258,7 +263,6 @@ nfsd_proc_create(struct svc_rqst *rqstp)
struct inode *inode; struct inode *inode;
struct dentry *dchild; struct dentry *dchild;
int type, mode; int type, mode;
__be32 nfserr;
int hosterr; int hosterr;
dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size); dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size);
...@@ -266,40 +270,40 @@ nfsd_proc_create(struct svc_rqst *rqstp) ...@@ -266,40 +270,40 @@ nfsd_proc_create(struct svc_rqst *rqstp)
SVCFH_fmt(dirfhp), argp->len, argp->name); SVCFH_fmt(dirfhp), argp->len, argp->name);
/* First verify the parent file handle */ /* First verify the parent file handle */
nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC); resp->status = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC);
if (nfserr) if (resp->status != nfs_ok)
goto done; /* must fh_put dirfhp even on error */ goto done; /* must fh_put dirfhp even on error */
/* Check for NFSD_MAY_WRITE in nfsd_create if necessary */ /* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
nfserr = nfserr_exist; resp->status = nfserr_exist;
if (isdotent(argp->name, argp->len)) if (isdotent(argp->name, argp->len))
goto done; goto done;
hosterr = fh_want_write(dirfhp); hosterr = fh_want_write(dirfhp);
if (hosterr) { if (hosterr) {
nfserr = nfserrno(hosterr); resp->status = nfserrno(hosterr);
goto done; goto done;
} }
fh_lock_nested(dirfhp, I_MUTEX_PARENT); fh_lock_nested(dirfhp, I_MUTEX_PARENT);
dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len); dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
if (IS_ERR(dchild)) { if (IS_ERR(dchild)) {
nfserr = nfserrno(PTR_ERR(dchild)); resp->status = nfserrno(PTR_ERR(dchild));
goto out_unlock; goto out_unlock;
} }
fh_init(newfhp, NFS_FHSIZE); fh_init(newfhp, NFS_FHSIZE);
nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp); resp->status = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
if (!nfserr && d_really_is_negative(dchild)) if (!resp->status && d_really_is_negative(dchild))
nfserr = nfserr_noent; resp->status = nfserr_noent;
dput(dchild); dput(dchild);
if (nfserr) { if (resp->status) {
if (nfserr != nfserr_noent) if (resp->status != nfserr_noent)
goto out_unlock; goto out_unlock;
/* /*
* If the new file handle wasn't verified, we can't tell * If the new file handle wasn't verified, we can't tell
* whether the file exists or not. Time to bail ... * whether the file exists or not. Time to bail ...
*/ */
nfserr = nfserr_acces; resp->status = nfserr_acces;
if (!newfhp->fh_dentry) { if (!newfhp->fh_dentry) {
printk(KERN_WARNING printk(KERN_WARNING
"nfsd_proc_create: file handle not verified\n"); "nfsd_proc_create: file handle not verified\n");
...@@ -332,11 +336,11 @@ nfsd_proc_create(struct svc_rqst *rqstp) ...@@ -332,11 +336,11 @@ nfsd_proc_create(struct svc_rqst *rqstp)
* echo thing > device-special-file-or-pipe * echo thing > device-special-file-or-pipe
* by doing a CREATE with type==0 * by doing a CREATE with type==0
*/ */
nfserr = nfsd_permission(rqstp, resp->status = nfsd_permission(rqstp,
newfhp->fh_export, newfhp->fh_export,
newfhp->fh_dentry, newfhp->fh_dentry,
NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS); NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS);
if (nfserr && nfserr != nfserr_rofs) if (resp->status && resp->status != nfserr_rofs)
goto out_unlock; goto out_unlock;
} }
} else } else
...@@ -372,16 +376,17 @@ nfsd_proc_create(struct svc_rqst *rqstp) ...@@ -372,16 +376,17 @@ nfsd_proc_create(struct svc_rqst *rqstp)
attr->ia_valid &= ~ATTR_SIZE; attr->ia_valid &= ~ATTR_SIZE;
/* Make sure the type and device matches */ /* Make sure the type and device matches */
nfserr = nfserr_exist; resp->status = nfserr_exist;
if (inode && type != (inode->i_mode & S_IFMT)) if (inode && type != (inode->i_mode & S_IFMT))
goto out_unlock; goto out_unlock;
} }
nfserr = 0; resp->status = nfs_ok;
if (!inode) { if (!inode) {
/* File doesn't exist. Create it and set attrs */ /* File doesn't exist. Create it and set attrs */
nfserr = nfsd_create_locked(rqstp, dirfhp, argp->name, resp->status = nfsd_create_locked(rqstp, dirfhp, argp->name,
argp->len, attr, type, rdev, newfhp); argp->len, attr, type, rdev,
newfhp);
} else if (type == S_IFREG) { } else if (type == S_IFREG) {
dprintk("nfsd: existing %s, valid=%x, size=%ld\n", dprintk("nfsd: existing %s, valid=%x, size=%ld\n",
argp->name, attr->ia_valid, (long) attr->ia_size); argp->name, attr->ia_valid, (long) attr->ia_size);
...@@ -391,7 +396,8 @@ nfsd_proc_create(struct svc_rqst *rqstp) ...@@ -391,7 +396,8 @@ nfsd_proc_create(struct svc_rqst *rqstp)
*/ */
attr->ia_valid &= ATTR_SIZE; attr->ia_valid &= ATTR_SIZE;
if (attr->ia_valid) if (attr->ia_valid)
nfserr = nfsd_setattr(rqstp, newfhp, attr, 0, (time64_t)0); resp->status = nfsd_setattr(rqstp, newfhp, attr, 0,
(time64_t)0);
} }
out_unlock: out_unlock:
...@@ -400,7 +406,11 @@ nfsd_proc_create(struct svc_rqst *rqstp) ...@@ -400,7 +406,11 @@ nfsd_proc_create(struct svc_rqst *rqstp)
fh_drop_write(dirfhp); fh_drop_write(dirfhp);
done: done:
fh_put(dirfhp); fh_put(dirfhp);
return nfsd_return_dirop(nfserr, resp); if (resp->status != nfs_ok)
goto out;
resp->status = fh_getattr(&resp->fh, &resp->stat);
out:
return resp->status;
} }
static __be32 static __be32
...@@ -463,14 +473,18 @@ nfsd_proc_symlink(struct svc_rqst *rqstp) ...@@ -463,14 +473,18 @@ nfsd_proc_symlink(struct svc_rqst *rqstp)
struct svc_fh newfh; struct svc_fh newfh;
__be32 nfserr; __be32 nfserr;
if (argp->tlen > NFS_MAXPATHLEN) if (argp->tlen > NFS_MAXPATHLEN) {
return nfserr_nametoolong; nfserr = nfserr_nametoolong;
goto out;
}
argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first, argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first,
page_address(rqstp->rq_arg.pages[0]), page_address(rqstp->rq_arg.pages[0]),
argp->tlen); argp->tlen);
if (IS_ERR(argp->tname)) if (IS_ERR(argp->tname)) {
return nfserrno(PTR_ERR(argp->tname)); nfserr = nfserrno(PTR_ERR(argp->tname));
goto out;
}
dprintk("nfsd: SYMLINK %s %.*s -> %.*s\n", dprintk("nfsd: SYMLINK %s %.*s -> %.*s\n",
SVCFH_fmt(&argp->ffh), argp->flen, argp->fname, SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
...@@ -483,6 +497,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp) ...@@ -483,6 +497,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp)
kfree(argp->tname); kfree(argp->tname);
fh_put(&argp->ffh); fh_put(&argp->ffh);
fh_put(&newfh); fh_put(&newfh);
out:
return nfserr; return nfserr;
} }
...@@ -495,7 +510,6 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp) ...@@ -495,7 +510,6 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp)
{ {
struct nfsd_createargs *argp = rqstp->rq_argp; struct nfsd_createargs *argp = rqstp->rq_argp;
struct nfsd_diropres *resp = rqstp->rq_resp; struct nfsd_diropres *resp = rqstp->rq_resp;
__be32 nfserr;
dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
...@@ -506,10 +520,15 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp) ...@@ -506,10 +520,15 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp)
argp->attrs.ia_valid &= ~ATTR_SIZE; argp->attrs.ia_valid &= ~ATTR_SIZE;
fh_init(&resp->fh, NFS_FHSIZE); fh_init(&resp->fh, NFS_FHSIZE);
nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len, resp->status = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
&argp->attrs, S_IFDIR, 0, &resp->fh); &argp->attrs, S_IFDIR, 0, &resp->fh);
fh_put(&argp->fh); fh_put(&argp->fh);
return nfsd_return_dirop(nfserr, resp); if (resp->status != nfs_ok)
goto out;
resp->status = fh_getattr(&resp->fh, &resp->stat);
out:
return resp->status;
} }
/* /*
...@@ -537,7 +556,6 @@ nfsd_proc_readdir(struct svc_rqst *rqstp) ...@@ -537,7 +556,6 @@ nfsd_proc_readdir(struct svc_rqst *rqstp)
struct nfsd_readdirargs *argp = rqstp->rq_argp; struct nfsd_readdirargs *argp = rqstp->rq_argp;
struct nfsd_readdirres *resp = rqstp->rq_resp; struct nfsd_readdirres *resp = rqstp->rq_resp;
int count; int count;
__be32 nfserr;
loff_t offset; loff_t offset;
dprintk("nfsd: READDIR %s %d bytes at %d\n", dprintk("nfsd: READDIR %s %d bytes at %d\n",
...@@ -558,7 +576,7 @@ nfsd_proc_readdir(struct svc_rqst *rqstp) ...@@ -558,7 +576,7 @@ nfsd_proc_readdir(struct svc_rqst *rqstp)
resp->common.err = nfs_ok; resp->common.err = nfs_ok;
/* Read directory and encode entries on the fly */ /* Read directory and encode entries on the fly */
offset = argp->cookie; offset = argp->cookie;
nfserr = nfsd_readdir(rqstp, &argp->fh, &offset, resp->status = nfsd_readdir(rqstp, &argp->fh, &offset,
&resp->common, nfssvc_encode_entry); &resp->common, nfssvc_encode_entry);
resp->count = resp->buffer - argp->buffer; resp->count = resp->buffer - argp->buffer;
...@@ -566,7 +584,7 @@ nfsd_proc_readdir(struct svc_rqst *rqstp) ...@@ -566,7 +584,7 @@ nfsd_proc_readdir(struct svc_rqst *rqstp)
*resp->offset = htonl(offset); *resp->offset = htonl(offset);
fh_put(&argp->fh); fh_put(&argp->fh);
return nfserr; return resp->status;
} }
/* /*
...@@ -577,14 +595,13 @@ nfsd_proc_statfs(struct svc_rqst *rqstp) ...@@ -577,14 +595,13 @@ nfsd_proc_statfs(struct svc_rqst *rqstp)
{ {
struct nfsd_fhandle *argp = rqstp->rq_argp; struct nfsd_fhandle *argp = rqstp->rq_argp;
struct nfsd_statfsres *resp = rqstp->rq_resp; struct nfsd_statfsres *resp = rqstp->rq_resp;
__be32 nfserr;
dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh)); dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh));
nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
NFSD_MAY_BYPASS_GSS_ON_ROOT); NFSD_MAY_BYPASS_GSS_ON_ROOT);
fh_put(&argp->fh); fh_put(&argp->fh);
return nfserr; return resp->status;
} }
/* /*
......
...@@ -1056,10 +1056,6 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) ...@@ -1056,10 +1056,6 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
if (rqstp->rq_proc != 0) if (rqstp->rq_proc != 0)
*nfserrp++ = nfserr; *nfserrp++ = nfserr;
/*
* For NFSv2, additional info is never returned in case of an error.
*/
if (!(nfserr && rqstp->rq_vers == 2))
if (!proc->pc_encode(rqstp, nfserrp)) if (!proc->pc_encode(rqstp, nfserrp))
goto out_encode_err; goto out_encode_err;
......
...@@ -434,6 +434,9 @@ nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p) ...@@ -434,6 +434,9 @@ nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p)
{ {
struct nfsd_attrstat *resp = rqstp->rq_resp; struct nfsd_attrstat *resp = rqstp->rq_resp;
if (resp->status != nfs_ok)
return xdr_ressize_check(rqstp, p);
p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
return xdr_ressize_check(rqstp, p); return xdr_ressize_check(rqstp, p);
} }
...@@ -443,6 +446,9 @@ nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p) ...@@ -443,6 +446,9 @@ nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p)
{ {
struct nfsd_diropres *resp = rqstp->rq_resp; struct nfsd_diropres *resp = rqstp->rq_resp;
if (resp->status != nfs_ok)
return xdr_ressize_check(rqstp, p);
p = encode_fh(p, &resp->fh); p = encode_fh(p, &resp->fh);
p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
return xdr_ressize_check(rqstp, p); return xdr_ressize_check(rqstp, p);
...@@ -453,6 +459,9 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) ...@@ -453,6 +459,9 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
{ {
struct nfsd_readlinkres *resp = rqstp->rq_resp; struct nfsd_readlinkres *resp = rqstp->rq_resp;
if (resp->status != nfs_ok)
return xdr_ressize_check(rqstp, p);
*p++ = htonl(resp->len); *p++ = htonl(resp->len);
xdr_ressize_check(rqstp, p); xdr_ressize_check(rqstp, p);
rqstp->rq_res.page_len = resp->len; rqstp->rq_res.page_len = resp->len;
...@@ -470,6 +479,9 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p) ...@@ -470,6 +479,9 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
{ {
struct nfsd_readres *resp = rqstp->rq_resp; struct nfsd_readres *resp = rqstp->rq_resp;
if (resp->status != nfs_ok)
return xdr_ressize_check(rqstp, p);
p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
*p++ = htonl(resp->count); *p++ = htonl(resp->count);
xdr_ressize_check(rqstp, p); xdr_ressize_check(rqstp, p);
...@@ -490,6 +502,9 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) ...@@ -490,6 +502,9 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
{ {
struct nfsd_readdirres *resp = rqstp->rq_resp; struct nfsd_readdirres *resp = rqstp->rq_resp;
if (resp->status != nfs_ok)
return xdr_ressize_check(rqstp, p);
xdr_ressize_check(rqstp, p); xdr_ressize_check(rqstp, p);
p = resp->buffer; p = resp->buffer;
*p++ = 0; /* no more entries */ *p++ = 0; /* no more entries */
...@@ -505,6 +520,9 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p) ...@@ -505,6 +520,9 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p)
struct nfsd_statfsres *resp = rqstp->rq_resp; struct nfsd_statfsres *resp = rqstp->rq_resp;
struct kstatfs *stat = &resp->stats; struct kstatfs *stat = &resp->stats;
if (resp->status != nfs_ok)
return xdr_ressize_check(rqstp, p);
*p++ = htonl(NFSSVC_MAXBLKSIZE_V2); /* max transfer size */ *p++ = htonl(NFSSVC_MAXBLKSIZE_V2); /* max transfer size */
*p++ = htonl(stat->f_bsize); *p++ = htonl(stat->f_bsize);
*p++ = htonl(stat->f_blocks); *p++ = htonl(stat->f_blocks);
......
...@@ -83,26 +83,32 @@ struct nfsd_readdirargs { ...@@ -83,26 +83,32 @@ struct nfsd_readdirargs {
}; };
struct nfsd_attrstat { struct nfsd_attrstat {
__be32 status;
struct svc_fh fh; struct svc_fh fh;
struct kstat stat; struct kstat stat;
}; };
struct nfsd_diropres { struct nfsd_diropres {
__be32 status;
struct svc_fh fh; struct svc_fh fh;
struct kstat stat; struct kstat stat;
}; };
struct nfsd_readlinkres { struct nfsd_readlinkres {
__be32 status;
int len; int len;
}; };
struct nfsd_readres { struct nfsd_readres {
__be32 status;
struct svc_fh fh; struct svc_fh fh;
unsigned long count; unsigned long count;
struct kstat stat; struct kstat stat;
}; };
struct nfsd_readdirres { struct nfsd_readdirres {
__be32 status;
int count; int count;
struct readdir_cd common; struct readdir_cd common;
...@@ -112,6 +118,7 @@ struct nfsd_readdirres { ...@@ -112,6 +118,7 @@ struct nfsd_readdirres {
}; };
struct nfsd_statfsres { struct nfsd_statfsres {
__be32 status;
struct kstatfs stats; struct kstatfs stats;
}; };
......
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