Re: [PATCH 7/8] NFSD: use (un)lock_inode instead of fh_(un)lock for file operations

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 07 Jul 2022, Chuck Lever III wrote:
> 
> > On Jul 6, 2022, at 12:18 AM, NeilBrown <neilb@xxxxxxx> wrote:
> > 
> > When locking a file to access ACLs and xattrs etc, use explicit locking
> > with inode_lock() instead of fh_lock().  This means that the calls to
> > fh_fill_pre/post_attr() are also explicit which improves readability and
> > allows us to place them only where they are needed.  Only the xattr
> > calls need pre/post information.
> > 
> > When locking a file we don't need I_MUTEX_PARENT as the file is not a
> > parent of anything, so we can use inode_lock() directly rather than the
> > inode_lock_nested() call that fh_lock() uses.
> > 
> > Signed-off-by: NeilBrown <neilb@xxxxxxx>
> > ---
> > fs/nfsd/nfs2acl.c   |    6 +++---
> > fs/nfsd/nfs3acl.c   |    4 ++--
> > fs/nfsd/nfs4acl.c   |    7 +++----
> > fs/nfsd/nfs4state.c |    8 ++++----
> > fs/nfsd/vfs.c       |   25 ++++++++++++-------------
> > 5 files changed, 24 insertions(+), 26 deletions(-)
> > 
> > diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
> > index b5760801d377..9edd3c1a30fb 100644
> > --- a/fs/nfsd/nfs2acl.c
> > +++ b/fs/nfsd/nfs2acl.c
> > @@ -111,7 +111,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
> > 	if (error)
> > 		goto out_errno;
> > 
> > -	fh_lock(fh);
> > +	inode_lock(inode);
> > 
> > 	error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
> > 			      argp->acl_access);
> > @@ -122,7 +122,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
> > 	if (error)
> > 		goto out_drop_lock;
> > 
> > -	fh_unlock(fh);
> > +	inode_unlock(inode);
> > 
> > 	fh_drop_write(fh);
> > 
> > @@ -136,7 +136,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
> > 	return rpc_success;
> > 
> > out_drop_lock:
> > -	fh_unlock(fh);
> > +	inode_unlock(inode);
> > 	fh_drop_write(fh);
> > out_errno:
> > 	resp->status = nfserrno(error);
> > diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
> > index 35b2ebda14da..9446c6743664 100644
> > --- a/fs/nfsd/nfs3acl.c
> > +++ b/fs/nfsd/nfs3acl.c
> > @@ -101,7 +101,7 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp)
> > 	if (error)
> > 		goto out_errno;
> > 
> > -	fh_lock(fh);
> > +	inode_lock(inode);
> > 
> > 	error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
> > 			      argp->acl_access);
> > @@ -111,7 +111,7 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp)
> > 			      argp->acl_default);
> > 
> > out_drop_lock:
> > -	fh_unlock(fh);
> > +	inode_unlock(inode);
> > 	fh_drop_write(fh);
> > out_errno:
> > 	resp->status = nfserrno(error);
> > diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
> > index 5c9b7e01e8ca..a33cacf62ea0 100644
> > --- a/fs/nfsd/nfs4acl.c
> > +++ b/fs/nfsd/nfs4acl.c
> > @@ -781,19 +781,18 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
> > 	if (host_error < 0)
> > 		goto out_nfserr;
> > 
> > -	fh_lock(fhp);
> > +	inode_lock(inode);
> > 
> > 	host_error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS, pacl);
> > 	if (host_error < 0)
> > 		goto out_drop_lock;
> > 
> > -	if (S_ISDIR(inode->i_mode)) {
> > +	if (S_ISDIR(inode->i_mode))
> > 		host_error = set_posix_acl(&init_user_ns, inode,
> > 					   ACL_TYPE_DEFAULT, dpacl);
> > -	}
> > 
> > out_drop_lock:
> > -	fh_unlock(fhp);
> > +	inode_unlock(inode);
> > 
> > 	posix_acl_release(pacl);
> > 	posix_acl_release(dpacl);
> > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> > index 9d1a3e131c49..307317ba9aff 100644
> > --- a/fs/nfsd/nfs4state.c
> > +++ b/fs/nfsd/nfs4state.c
> > @@ -7322,21 +7322,21 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> > static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock)
> > {
> > 	struct nfsd_file *nf;
> > +	struct inode *inode = fhp->fh_dentry->d_inode;
> 
> I don't think this is correct.
> 
> nfsd_file_acquire() calls fh_verify(), which can updated fhp->fh_dentry.
> Anyway, is it guaranteed that fh_dentry is not NULL here?

nfsd_test_lock() is only ever called from nfsd4_lockt(), and that always
calls fh_verify() before calling nfsd_test_lock().  So the code is safe.

> 
> It would be more defensive to set @inode /after/ the call to
> nfsd_file_acquire().

Yes, that would make it even safer - thanks.

NeilBrown


> 
> 
> > 	__be32 err;
> > 
> > 	err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf);
> > 	if (err)
> > 		return err;
> > -	fh_lock(fhp); /* to block new leases till after test_lock: */
> > -	err = nfserrno(nfsd_open_break_lease(fhp->fh_dentry->d_inode,
> > -							NFSD_MAY_READ));
> > +	inode_lock(inode); /* to block new leases till after test_lock: */
> > +	err = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ));
> > 	if (err)
> > 		goto out;
> > 	lock->fl_file = nf->nf_file;
> > 	err = nfserrno(vfs_test_lock(nf->nf_file, lock));
> > 	lock->fl_file = NULL;
> > out:
> > -	fh_unlock(fhp);
> > +	inode_unlock(inode);
> > 	nfsd_file_put(nf);
> > 	return err;
> > }
> > diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> > index 2ca748aa83bb..2526615285ca 100644
> > --- a/fs/nfsd/vfs.c
> > +++ b/fs/nfsd/vfs.c
> > @@ -444,7 +444,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
> > 			return err;
> > 	}
> > 
> > -	fh_lock(fhp);
> > +	inode_lock(inode);
> > 	if (size_change) {
> > 		/*
> > 		 * RFC5661, Section 18.30.4:
> > @@ -480,7 +480,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
> > 	host_err = notify_change(&init_user_ns, dentry, iap, NULL);
> > 
> > out_unlock:
> > -	fh_unlock(fhp);
> > +	inode_unlock(inode);
> > 	if (size_change)
> > 		put_write_access(inode);
> > out:
> > @@ -2196,12 +2196,8 @@ nfsd_listxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char **bufp,
> > }
> > 
> > /*
> > - * Removexattr and setxattr need to call fh_lock to both lock the inode
> > - * and set the change attribute. Since the top-level vfs_removexattr
> > - * and vfs_setxattr calls already do their own inode_lock calls, call
> > - * the _locked variant. Pass in a NULL pointer for delegated_inode,
> > - * and let the client deal with NFS4ERR_DELAY (same as with e.g.
> > - * setattr and remove).
> > + * Pass in a NULL pointer for delegated_inode, and let the client deal
> > + * with NFS4ERR_DELAY (same as with e.g.  setattr and remove).
> >  */
> > __be32
> > nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name)
> > @@ -2217,12 +2213,14 @@ nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name)
> > 	if (ret)
> > 		return nfserrno(ret);
> > 
> > -	fh_lock(fhp);
> > +	inode_lock(fhp->fh_dentry->d_inode);
> > +	fh_fill_pre_attrs(fhp);
> > 
> > 	ret = __vfs_removexattr_locked(&init_user_ns, fhp->fh_dentry,
> > 				       name, NULL);
> > 
> > -	fh_unlock(fhp);
> > +	fh_fill_post_attrs(fhp);
> > +	inode_unlock(fhp->fh_dentry->d_inode);
> > 	fh_drop_write(fhp);
> > 
> > 	return nfsd_xattr_errno(ret);
> > @@ -2242,12 +2240,13 @@ nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name,
> > 	ret = fh_want_write(fhp);
> > 	if (ret)
> > 		return nfserrno(ret);
> > -	fh_lock(fhp);
> > +	inode_lock(fhp->fh_dentry->d_inode);
> > +	fh_fill_pre_attrs(fhp);
> > 
> > 	ret = __vfs_setxattr_locked(&init_user_ns, fhp->fh_dentry, name, buf,
> > 				    len, flags, NULL);
> > -
> > -	fh_unlock(fhp);
> > +	fh_fill_post_attrs(fhp);
> > +	inode_unlock(fhp->fh_dentry->d_inode);
> > 	fh_drop_write(fhp);
> > 
> > 	return nfsd_xattr_errno(ret);
> > 
> > 
> 
> --
> Chuck Lever
> 
> 
> 
> 




[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux