Commit a332018a authored by Jeff Layton's avatar Jeff Layton Committed by Chuck Lever

nfsd: handle failure to collect pre/post-op attrs more sanely

Collecting pre_op_attrs can fail, in which case it's probably best to
fail the whole operation.

Change fh_fill_pre_attrs and fh_fill_both_attrs to return __be32, and
have the callers check the return code and abort the operation if it's
not nfs_ok.
Signed-off-by: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 5865bafa
...@@ -307,7 +307,9 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -307,7 +307,9 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (!IS_POSIXACL(inode)) if (!IS_POSIXACL(inode))
iap->ia_mode &= ~current_umask(); iap->ia_mode &= ~current_umask();
fh_fill_pre_attrs(fhp); status = fh_fill_pre_attrs(fhp);
if (status != nfs_ok)
goto out;
host_err = vfs_create(&nop_mnt_idmap, inode, child, iap->ia_mode, true); host_err = vfs_create(&nop_mnt_idmap, inode, child, iap->ia_mode, true);
if (host_err < 0) { if (host_err < 0) {
status = nfserrno(host_err); status = nfserrno(host_err);
......
...@@ -297,12 +297,12 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -297,12 +297,12 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
} }
if (d_really_is_positive(child)) { if (d_really_is_positive(child)) {
status = nfs_ok;
/* NFSv4 protocol requires change attributes even though /* NFSv4 protocol requires change attributes even though
* no change happened. * no change happened.
*/ */
fh_fill_both_attrs(fhp); status = fh_fill_both_attrs(fhp);
if (status != nfs_ok)
goto out;
switch (open->op_createmode) { switch (open->op_createmode) {
case NFS4_CREATE_UNCHECKED: case NFS4_CREATE_UNCHECKED:
...@@ -345,7 +345,9 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -345,7 +345,9 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (!IS_POSIXACL(inode)) if (!IS_POSIXACL(inode))
iap->ia_mode &= ~current_umask(); iap->ia_mode &= ~current_umask();
fh_fill_pre_attrs(fhp); status = fh_fill_pre_attrs(fhp);
if (status != nfs_ok)
goto out;
status = nfsd4_vfs_create(fhp, child, open); status = nfsd4_vfs_create(fhp, child, open);
if (status != nfs_ok) if (status != nfs_ok)
goto out; goto out;
...@@ -424,11 +426,11 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru ...@@ -424,11 +426,11 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
} else { } else {
status = nfsd_lookup(rqstp, current_fh, status = nfsd_lookup(rqstp, current_fh,
open->op_fname, open->op_fnamelen, *resfh); open->op_fname, open->op_fnamelen, *resfh);
if (!status) if (status == nfs_ok)
/* NFSv4 protocol requires change attributes even though /* NFSv4 protocol requires change attributes even though
* no change happened. * no change happened.
*/ */
fh_fill_both_attrs(current_fh); status = fh_fill_both_attrs(current_fh);
} }
if (status) if (status)
goto out; goto out;
......
...@@ -614,7 +614,7 @@ fh_update(struct svc_fh *fhp) ...@@ -614,7 +614,7 @@ fh_update(struct svc_fh *fhp)
* @fhp: file handle to be updated * @fhp: file handle to be updated
* *
*/ */
void fh_fill_pre_attrs(struct svc_fh *fhp) __be32 __must_check fh_fill_pre_attrs(struct svc_fh *fhp)
{ {
bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE);
struct inode *inode; struct inode *inode;
...@@ -622,12 +622,12 @@ void fh_fill_pre_attrs(struct svc_fh *fhp) ...@@ -622,12 +622,12 @@ void fh_fill_pre_attrs(struct svc_fh *fhp)
__be32 err; __be32 err;
if (fhp->fh_no_wcc || fhp->fh_pre_saved) if (fhp->fh_no_wcc || fhp->fh_pre_saved)
return; return nfs_ok;
inode = d_inode(fhp->fh_dentry); inode = d_inode(fhp->fh_dentry);
err = fh_getattr(fhp, &stat); err = fh_getattr(fhp, &stat);
if (err) if (err)
return; return err;
if (v4) if (v4)
fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode); fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode);
...@@ -636,6 +636,7 @@ void fh_fill_pre_attrs(struct svc_fh *fhp) ...@@ -636,6 +636,7 @@ void fh_fill_pre_attrs(struct svc_fh *fhp)
fhp->fh_pre_ctime = stat.ctime; fhp->fh_pre_ctime = stat.ctime;
fhp->fh_pre_size = stat.size; fhp->fh_pre_size = stat.size;
fhp->fh_pre_saved = true; fhp->fh_pre_saved = true;
return nfs_ok;
} }
/** /**
...@@ -643,26 +644,27 @@ void fh_fill_pre_attrs(struct svc_fh *fhp) ...@@ -643,26 +644,27 @@ void fh_fill_pre_attrs(struct svc_fh *fhp)
* @fhp: file handle to be updated * @fhp: file handle to be updated
* *
*/ */
void fh_fill_post_attrs(struct svc_fh *fhp) __be32 fh_fill_post_attrs(struct svc_fh *fhp)
{ {
bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE);
struct inode *inode = d_inode(fhp->fh_dentry); struct inode *inode = d_inode(fhp->fh_dentry);
__be32 err; __be32 err;
if (fhp->fh_no_wcc) if (fhp->fh_no_wcc)
return; return nfs_ok;
if (fhp->fh_post_saved) if (fhp->fh_post_saved)
printk("nfsd: inode locked twice during operation.\n"); printk("nfsd: inode locked twice during operation.\n");
err = fh_getattr(fhp, &fhp->fh_post_attr); err = fh_getattr(fhp, &fhp->fh_post_attr);
if (err) if (err)
return; return err;
fhp->fh_post_saved = true; fhp->fh_post_saved = true;
if (v4) if (v4)
fhp->fh_post_change = fhp->fh_post_change =
nfsd4_change_attribute(&fhp->fh_post_attr, inode); nfsd4_change_attribute(&fhp->fh_post_attr, inode);
return nfs_ok;
} }
/** /**
...@@ -672,16 +674,20 @@ void fh_fill_post_attrs(struct svc_fh *fhp) ...@@ -672,16 +674,20 @@ void fh_fill_post_attrs(struct svc_fh *fhp)
* This is used when the directory wasn't changed, but wcc attributes * This is used when the directory wasn't changed, but wcc attributes
* are needed anyway. * are needed anyway.
*/ */
void fh_fill_both_attrs(struct svc_fh *fhp) __be32 __must_check fh_fill_both_attrs(struct svc_fh *fhp)
{ {
fh_fill_post_attrs(fhp); __be32 err;
if (!fhp->fh_post_saved)
return; err = fh_fill_post_attrs(fhp);
if (err)
return err;
fhp->fh_pre_change = fhp->fh_post_change; fhp->fh_pre_change = fhp->fh_post_change;
fhp->fh_pre_mtime = fhp->fh_post_attr.mtime; fhp->fh_pre_mtime = fhp->fh_post_attr.mtime;
fhp->fh_pre_ctime = fhp->fh_post_attr.ctime; fhp->fh_pre_ctime = fhp->fh_post_attr.ctime;
fhp->fh_pre_size = fhp->fh_post_attr.size; fhp->fh_pre_size = fhp->fh_post_attr.size;
fhp->fh_pre_saved = true; fhp->fh_pre_saved = true;
return nfs_ok;
} }
/* /*
......
...@@ -294,7 +294,7 @@ static inline void fh_clear_pre_post_attrs(struct svc_fh *fhp) ...@@ -294,7 +294,7 @@ static inline void fh_clear_pre_post_attrs(struct svc_fh *fhp)
} }
u64 nfsd4_change_attribute(struct kstat *stat, struct inode *inode); u64 nfsd4_change_attribute(struct kstat *stat, struct inode *inode);
extern void fh_fill_pre_attrs(struct svc_fh *fhp); __be32 __must_check fh_fill_pre_attrs(struct svc_fh *fhp);
extern void fh_fill_post_attrs(struct svc_fh *fhp); __be32 fh_fill_post_attrs(struct svc_fh *fhp);
extern void fh_fill_both_attrs(struct svc_fh *fhp); __be32 __must_check fh_fill_both_attrs(struct svc_fh *fhp);
#endif /* _LINUX_NFSD_NFSFH_H */ #endif /* _LINUX_NFSD_NFSFH_H */
...@@ -1540,7 +1540,9 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -1540,7 +1540,9 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
dput(dchild); dput(dchild);
if (err) if (err)
goto out_unlock; goto out_unlock;
fh_fill_pre_attrs(fhp); err = fh_fill_pre_attrs(fhp);
if (err != nfs_ok)
goto out_unlock;
err = nfsd_create_locked(rqstp, fhp, attrs, type, rdev, resfhp); err = nfsd_create_locked(rqstp, fhp, attrs, type, rdev, resfhp);
fh_fill_post_attrs(fhp); fh_fill_post_attrs(fhp);
out_unlock: out_unlock:
...@@ -1635,13 +1637,16 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -1635,13 +1637,16 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
inode_unlock(dentry->d_inode); inode_unlock(dentry->d_inode);
goto out_drop_write; goto out_drop_write;
} }
fh_fill_pre_attrs(fhp); err = fh_fill_pre_attrs(fhp);
if (err != nfs_ok)
goto out_unlock;
host_err = vfs_symlink(&nop_mnt_idmap, d_inode(dentry), dnew, path); host_err = vfs_symlink(&nop_mnt_idmap, d_inode(dentry), dnew, path);
err = nfserrno(host_err); err = nfserrno(host_err);
cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
if (!err) if (!err)
nfsd_create_setattr(rqstp, fhp, resfhp, attrs); nfsd_create_setattr(rqstp, fhp, resfhp, attrs);
fh_fill_post_attrs(fhp); fh_fill_post_attrs(fhp);
out_unlock:
inode_unlock(dentry->d_inode); inode_unlock(dentry->d_inode);
if (!err) if (!err)
err = nfserrno(commit_metadata(fhp)); err = nfserrno(commit_metadata(fhp));
...@@ -1703,7 +1708,9 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, ...@@ -1703,7 +1708,9 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
err = nfserr_noent; err = nfserr_noent;
if (d_really_is_negative(dold)) if (d_really_is_negative(dold))
goto out_dput; goto out_dput;
fh_fill_pre_attrs(ffhp); err = fh_fill_pre_attrs(ffhp);
if (err != nfs_ok)
goto out_dput;
host_err = vfs_link(dold, &nop_mnt_idmap, dirp, dnew, NULL); host_err = vfs_link(dold, &nop_mnt_idmap, dirp, dnew, NULL);
fh_fill_post_attrs(ffhp); fh_fill_post_attrs(ffhp);
inode_unlock(dirp); inode_unlock(dirp);
...@@ -1789,8 +1796,12 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, ...@@ -1789,8 +1796,12 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
} }
trap = lock_rename(tdentry, fdentry); trap = lock_rename(tdentry, fdentry);
fh_fill_pre_attrs(ffhp); err = fh_fill_pre_attrs(ffhp);
fh_fill_pre_attrs(tfhp); if (err != nfs_ok)
goto out_unlock;
err = fh_fill_pre_attrs(tfhp);
if (err != nfs_ok)
goto out_unlock;
odentry = lookup_one_len(fname, fdentry, flen); odentry = lookup_one_len(fname, fdentry, flen);
host_err = PTR_ERR(odentry); host_err = PTR_ERR(odentry);
...@@ -1857,6 +1868,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, ...@@ -1857,6 +1868,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
fh_fill_post_attrs(ffhp); fh_fill_post_attrs(ffhp);
fh_fill_post_attrs(tfhp); fh_fill_post_attrs(tfhp);
} }
out_unlock:
unlock_rename(tdentry, fdentry); unlock_rename(tdentry, fdentry);
fh_drop_write(ffhp); fh_drop_write(ffhp);
...@@ -1916,12 +1928,14 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, ...@@ -1916,12 +1928,14 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
goto out_unlock; goto out_unlock;
} }
rinode = d_inode(rdentry); rinode = d_inode(rdentry);
ihold(rinode); err = fh_fill_pre_attrs(fhp);
if (err != nfs_ok)
goto out_unlock;
ihold(rinode);
if (!type) if (!type)
type = d_inode(rdentry)->i_mode & S_IFMT; type = d_inode(rdentry)->i_mode & S_IFMT;
fh_fill_pre_attrs(fhp);
if (type != S_IFDIR) { if (type != S_IFDIR) {
int retries; int retries;
...@@ -2341,16 +2355,18 @@ nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name) ...@@ -2341,16 +2355,18 @@ nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name)
return nfserrno(ret); return nfserrno(ret);
inode_lock(fhp->fh_dentry->d_inode); inode_lock(fhp->fh_dentry->d_inode);
fh_fill_pre_attrs(fhp); err = fh_fill_pre_attrs(fhp);
if (err != nfs_ok)
goto out_unlock;
ret = __vfs_removexattr_locked(&nop_mnt_idmap, fhp->fh_dentry, ret = __vfs_removexattr_locked(&nop_mnt_idmap, fhp->fh_dentry,
name, NULL); name, NULL);
err = nfsd_xattr_errno(ret);
fh_fill_post_attrs(fhp); fh_fill_post_attrs(fhp);
out_unlock:
inode_unlock(fhp->fh_dentry->d_inode); inode_unlock(fhp->fh_dentry->d_inode);
fh_drop_write(fhp); fh_drop_write(fhp);
return nfsd_xattr_errno(ret); return err;
} }
__be32 __be32
...@@ -2368,15 +2384,17 @@ nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name, ...@@ -2368,15 +2384,17 @@ nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name,
if (ret) if (ret)
return nfserrno(ret); return nfserrno(ret);
inode_lock(fhp->fh_dentry->d_inode); inode_lock(fhp->fh_dentry->d_inode);
fh_fill_pre_attrs(fhp); err = fh_fill_pre_attrs(fhp);
if (err != nfs_ok)
ret = __vfs_setxattr_locked(&nop_mnt_idmap, fhp->fh_dentry, name, buf, goto out_unlock;
len, flags, NULL); ret = __vfs_setxattr_locked(&nop_mnt_idmap, fhp->fh_dentry,
name, buf, len, flags, NULL);
fh_fill_post_attrs(fhp); fh_fill_post_attrs(fhp);
err = nfsd_xattr_errno(ret);
out_unlock:
inode_unlock(fhp->fh_dentry->d_inode); inode_unlock(fhp->fh_dentry->d_inode);
fh_drop_write(fhp); fh_drop_write(fhp);
return err;
return nfsd_xattr_errno(ret);
} }
#endif #endif
......
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