mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-23 16:53:58 -05:00
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: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
parent
5865bafa19
commit
a332018a91
5 changed files with 65 additions and 37 deletions
|
@ -307,7 +307,9 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||
if (!IS_POSIXACL(inode))
|
||||
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);
|
||||
if (host_err < 0) {
|
||||
status = nfserrno(host_err);
|
||||
|
|
|
@ -297,12 +297,12 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||
}
|
||||
|
||||
if (d_really_is_positive(child)) {
|
||||
status = nfs_ok;
|
||||
|
||||
/* NFSv4 protocol requires change attributes even though
|
||||
* no change happened.
|
||||
*/
|
||||
fh_fill_both_attrs(fhp);
|
||||
status = fh_fill_both_attrs(fhp);
|
||||
if (status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
switch (open->op_createmode) {
|
||||
case NFS4_CREATE_UNCHECKED:
|
||||
|
@ -345,7 +345,9 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||
if (!IS_POSIXACL(inode))
|
||||
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);
|
||||
if (status != nfs_ok)
|
||||
goto out;
|
||||
|
@ -424,11 +426,11 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
|
|||
} else {
|
||||
status = nfsd_lookup(rqstp, current_fh,
|
||||
open->op_fname, open->op_fnamelen, *resfh);
|
||||
if (!status)
|
||||
if (status == nfs_ok)
|
||||
/* NFSv4 protocol requires change attributes even though
|
||||
* no change happened.
|
||||
*/
|
||||
fh_fill_both_attrs(current_fh);
|
||||
status = fh_fill_both_attrs(current_fh);
|
||||
}
|
||||
if (status)
|
||||
goto out;
|
||||
|
|
|
@ -614,7 +614,7 @@ out_negative:
|
|||
* @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);
|
||||
struct inode *inode;
|
||||
|
@ -622,12 +622,12 @@ void fh_fill_pre_attrs(struct svc_fh *fhp)
|
|||
__be32 err;
|
||||
|
||||
if (fhp->fh_no_wcc || fhp->fh_pre_saved)
|
||||
return;
|
||||
return nfs_ok;
|
||||
|
||||
inode = d_inode(fhp->fh_dentry);
|
||||
err = fh_getattr(fhp, &stat);
|
||||
if (err)
|
||||
return;
|
||||
return err;
|
||||
|
||||
if (v4)
|
||||
fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode);
|
||||
|
@ -636,6 +636,7 @@ void fh_fill_pre_attrs(struct svc_fh *fhp)
|
|||
fhp->fh_pre_ctime = stat.ctime;
|
||||
fhp->fh_pre_size = stat.size;
|
||||
fhp->fh_pre_saved = true;
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -643,26 +644,27 @@ void fh_fill_pre_attrs(struct svc_fh *fhp)
|
|||
* @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);
|
||||
struct inode *inode = d_inode(fhp->fh_dentry);
|
||||
__be32 err;
|
||||
|
||||
if (fhp->fh_no_wcc)
|
||||
return;
|
||||
return nfs_ok;
|
||||
|
||||
if (fhp->fh_post_saved)
|
||||
printk("nfsd: inode locked twice during operation.\n");
|
||||
|
||||
err = fh_getattr(fhp, &fhp->fh_post_attr);
|
||||
if (err)
|
||||
return;
|
||||
return err;
|
||||
|
||||
fhp->fh_post_saved = true;
|
||||
if (v4)
|
||||
fhp->fh_post_change =
|
||||
nfsd4_change_attribute(&fhp->fh_post_attr, inode);
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
* 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);
|
||||
if (!fhp->fh_post_saved)
|
||||
return;
|
||||
__be32 err;
|
||||
|
||||
err = fh_fill_post_attrs(fhp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
fhp->fh_pre_change = fhp->fh_post_change;
|
||||
fhp->fh_pre_mtime = fhp->fh_post_attr.mtime;
|
||||
fhp->fh_pre_ctime = fhp->fh_post_attr.ctime;
|
||||
fhp->fh_pre_size = fhp->fh_post_attr.size;
|
||||
fhp->fh_pre_saved = true;
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
extern void fh_fill_pre_attrs(struct svc_fh *fhp);
|
||||
extern void fh_fill_post_attrs(struct svc_fh *fhp);
|
||||
extern void fh_fill_both_attrs(struct svc_fh *fhp);
|
||||
__be32 __must_check fh_fill_pre_attrs(struct svc_fh *fhp);
|
||||
__be32 fh_fill_post_attrs(struct svc_fh *fhp);
|
||||
__be32 __must_check fh_fill_both_attrs(struct svc_fh *fhp);
|
||||
#endif /* _LINUX_NFSD_NFSFH_H */
|
||||
|
|
|
@ -1540,7 +1540,9 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||
dput(dchild);
|
||||
if (err)
|
||||
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);
|
||||
fh_fill_post_attrs(fhp);
|
||||
out_unlock:
|
||||
|
@ -1635,13 +1637,16 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||
inode_unlock(dentry->d_inode);
|
||||
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);
|
||||
err = nfserrno(host_err);
|
||||
cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
|
||||
if (!err)
|
||||
nfsd_create_setattr(rqstp, fhp, resfhp, attrs);
|
||||
fh_fill_post_attrs(fhp);
|
||||
out_unlock:
|
||||
inode_unlock(dentry->d_inode);
|
||||
if (!err)
|
||||
err = nfserrno(commit_metadata(fhp));
|
||||
|
@ -1703,7 +1708,9 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
|
|||
err = nfserr_noent;
|
||||
if (d_really_is_negative(dold))
|
||||
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);
|
||||
fh_fill_post_attrs(ffhp);
|
||||
inode_unlock(dirp);
|
||||
|
@ -1789,8 +1796,12 @@ retry:
|
|||
}
|
||||
|
||||
trap = lock_rename(tdentry, fdentry);
|
||||
fh_fill_pre_attrs(ffhp);
|
||||
fh_fill_pre_attrs(tfhp);
|
||||
err = fh_fill_pre_attrs(ffhp);
|
||||
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);
|
||||
host_err = PTR_ERR(odentry);
|
||||
|
@ -1857,6 +1868,7 @@ retry:
|
|||
fh_fill_post_attrs(ffhp);
|
||||
fh_fill_post_attrs(tfhp);
|
||||
}
|
||||
out_unlock:
|
||||
unlock_rename(tdentry, fdentry);
|
||||
fh_drop_write(ffhp);
|
||||
|
||||
|
@ -1916,12 +1928,14 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
|
|||
goto out_unlock;
|
||||
}
|
||||
rinode = d_inode(rdentry);
|
||||
ihold(rinode);
|
||||
err = fh_fill_pre_attrs(fhp);
|
||||
if (err != nfs_ok)
|
||||
goto out_unlock;
|
||||
|
||||
ihold(rinode);
|
||||
if (!type)
|
||||
type = d_inode(rdentry)->i_mode & S_IFMT;
|
||||
|
||||
fh_fill_pre_attrs(fhp);
|
||||
if (type != S_IFDIR) {
|
||||
int retries;
|
||||
|
||||
|
@ -2341,16 +2355,18 @@ nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name)
|
|||
return nfserrno(ret);
|
||||
|
||||
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,
|
||||
name, NULL);
|
||||
|
||||
err = nfsd_xattr_errno(ret);
|
||||
fh_fill_post_attrs(fhp);
|
||||
out_unlock:
|
||||
inode_unlock(fhp->fh_dentry->d_inode);
|
||||
fh_drop_write(fhp);
|
||||
|
||||
return nfsd_xattr_errno(ret);
|
||||
return err;
|
||||
}
|
||||
|
||||
__be32
|
||||
|
@ -2368,15 +2384,17 @@ nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name,
|
|||
if (ret)
|
||||
return nfserrno(ret);
|
||||
inode_lock(fhp->fh_dentry->d_inode);
|
||||
fh_fill_pre_attrs(fhp);
|
||||
|
||||
ret = __vfs_setxattr_locked(&nop_mnt_idmap, fhp->fh_dentry, name, buf,
|
||||
len, flags, NULL);
|
||||
err = fh_fill_pre_attrs(fhp);
|
||||
if (err != nfs_ok)
|
||||
goto out_unlock;
|
||||
ret = __vfs_setxattr_locked(&nop_mnt_idmap, fhp->fh_dentry,
|
||||
name, buf, len, flags, NULL);
|
||||
fh_fill_post_attrs(fhp);
|
||||
err = nfsd_xattr_errno(ret);
|
||||
out_unlock:
|
||||
inode_unlock(fhp->fh_dentry->d_inode);
|
||||
fh_drop_write(fhp);
|
||||
|
||||
return nfsd_xattr_errno(ret);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue