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);
......
This diff is collapsed.
...@@ -1056,12 +1056,8 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) ...@@ -1056,12 +1056,8 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
if (rqstp->rq_proc != 0) if (rqstp->rq_proc != 0)
*nfserrp++ = nfserr; *nfserrp++ = nfserr;
/* if (!proc->pc_encode(rqstp, nfserrp))
* For NFSv2, additional info is never returned in case of an error. goto out_encode_err;
*/
if (!(nfserr && rqstp->rq_vers == 2))
if (!proc->pc_encode(rqstp, nfserrp))
goto out_encode_err;
nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1); nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1);
out_cached_reply: out_cached_reply:
......
...@@ -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