On Fri, 29 Jul 2022, Chuck Lever III wrote: > > > On Jul 26, 2022, at 2:45 AM, NeilBrown <neilb@xxxxxxx> wrote: > > > > When creating or unlinking a name in a directory use explicit > > inode_lock_nested() instead of fh_lock(), and explicit calls to > > fh_fill_pre_attrs() and fh_fill_post_attrs(). This is already done for > > renames. > > IIUC, the antecedent of "This is already done" is only "explicit > calls to fh_fill_pre_attrs() and fh_fill_post_attrs()" ? The "This" is both explicit locking and explicit fh_fill* calls. In rename it isn't inode_lock_nested(), it is lock_rename() Maybe This is already done for renames, with lock_rename() as the explicit locking. ?? > > > > > Also move the 'fill' calls closer to the operation that might change the > > attributes. This way they are avoided on some error paths. > > > > For the v2-only code in nfsproc.c, drop the fill calls as they aren't > > needed. > > This feels like 3 independent changes to me. At least the v2 change > should be moved to a separate patch. Relocating the "fill attrs" calls > seems like it could cause noticeable behavior changes, so maybe it > belongs also in a separate patch? Three intimately related changes that could be applied in sequence. What would be gained by having separate patches? To my mind, the primary issue is review effort. Mixing unrelated changes make review of each change harder, so keep them separate. Mixing related changes is less of a problem as the abstraction that you need to keep front-of-mind are fewer. On the flip side, every patch added increases the review burden. If I wanted to move all calls to foo(), I wouldn't have one patch for each call. I think that patch is easy to review as it stands, but if you think not I guess it could be split. Allowing bisect to isolate the problem precisely is another reason for keeping patches small. If a bug were found to be caused by this patch I doubt it would be at all hard to localise which part of the patch caused it. > > > > Having the locking explicit will simplify proposed future changes to > > ^Having^Making ? Yes, that's probably a little clearer. Thanks, NeilBrown > > > > locking for directories. It also makes it easily visible exactly where > > pre/post attributes are used - not all callers of fh_lock() actually > > need the pre/post attributes. > > > > Reviewed-by: Jeff Layton <jlayton@xxxxxxxxxx> > > Signed-off-by: NeilBrown <neilb@xxxxxxx> > > --- > > fs/nfsd/nfs3proc.c | 6 ++++-- > > fs/nfsd/nfs4proc.c | 6 ++++-- > > fs/nfsd/nfsproc.c | 5 ++--- > > fs/nfsd/vfs.c | 30 +++++++++++++++++++----------- > > 4 files changed, 29 insertions(+), 18 deletions(-) > > > > diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c > > index 774e4a2ab9b1..c2f992b4387a 100644 > > --- a/fs/nfsd/nfs3proc.c > > +++ b/fs/nfsd/nfs3proc.c > > @@ -256,7 +256,7 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, > > if (host_err) > > return nfserrno(host_err); > > > > - fh_lock_nested(fhp, I_MUTEX_PARENT); > > + inode_lock_nested(inode, I_MUTEX_PARENT); > > > > child = lookup_one_len(argp->name, parent, argp->len); > > if (IS_ERR(child)) { > > @@ -314,11 +314,13 @@ 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); > > host_err = vfs_create(&init_user_ns, inode, child, iap->ia_mode, true); > > if (host_err < 0) { > > status = nfserrno(host_err); > > goto out; > > } > > + fh_fill_post_attrs(fhp); > > > > /* A newly created file already has a file size of zero. */ > > if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0)) > > @@ -336,7 +338,7 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, > > status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs); > > > > out: > > - fh_unlock(fhp); > > + inode_unlock(inode); > > if (child && !IS_ERR(child)) > > dput(child); > > fh_drop_write(fhp); > > diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c > > index 48e4efb39a9c..90af82d49119 100644 > > --- a/fs/nfsd/nfs4proc.c > > +++ b/fs/nfsd/nfs4proc.c > > @@ -264,7 +264,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, > > if (is_create_with_attrs(open)) > > nfsd4_acl_to_attr(NF4REG, open->op_acl, &attrs); > > > > - fh_lock_nested(fhp, I_MUTEX_PARENT); > > + inode_lock_nested(inode, I_MUTEX_PARENT); > > > > child = lookup_one_len(open->op_fname, parent, open->op_fnamelen); > > if (IS_ERR(child)) { > > @@ -348,10 +348,12 @@ 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 = nfsd4_vfs_create(fhp, child, open); > > if (status != nfs_ok) > > goto out; > > open->op_created = true; > > + fh_fill_post_attrs(fhp); > > > > /* A newly created file already has a file size of zero. */ > > if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0)) > > @@ -373,7 +375,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, > > if (attrs.acl_failed) > > open->op_bmval[0] &= ~FATTR4_WORD0_ACL; > > out: > > - fh_unlock(fhp); > > + inode_unlock(inode); > > nfsd_attrs_free(&attrs); > > if (child && !IS_ERR(child)) > > dput(child); > > diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c > > index d09d516188d2..4cff332f58bb 100644 > > --- a/fs/nfsd/nfsproc.c > > +++ b/fs/nfsd/nfsproc.c > > @@ -287,7 +287,7 @@ nfsd_proc_create(struct svc_rqst *rqstp) > > goto done; > > } > > > > - fh_lock_nested(dirfhp, I_MUTEX_PARENT); > > + inode_lock_nested(dirfhp->fh_dentry->d_inode, I_MUTEX_PARENT); > > dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len); > > if (IS_ERR(dchild)) { > > resp->status = nfserrno(PTR_ERR(dchild)); > > @@ -403,8 +403,7 @@ nfsd_proc_create(struct svc_rqst *rqstp) > > } > > > > out_unlock: > > - /* We don't really need to unlock, as fh_put does it. */ > > - fh_unlock(dirfhp); > > + inode_unlock(dirfhp->fh_dentry->d_inode); > > fh_drop_write(dirfhp); > > done: > > fh_put(dirfhp); > > diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c > > index 8ebad4a99552..f2cb9b047766 100644 > > --- a/fs/nfsd/vfs.c > > +++ b/fs/nfsd/vfs.c > > @@ -1369,7 +1369,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, > > if (host_err) > > return nfserrno(host_err); > > > > - fh_lock_nested(fhp, I_MUTEX_PARENT); > > + inode_lock_nested(dentry->d_inode, I_MUTEX_PARENT); > > dchild = lookup_one_len(fname, dentry, flen); > > host_err = PTR_ERR(dchild); > > if (IS_ERR(dchild)) { > > @@ -1384,10 +1384,12 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, > > dput(dchild); > > if (err) > > goto out_unlock; > > + fh_fill_pre_attrs(fhp); > > err = nfsd_create_locked(rqstp, fhp, fname, flen, attrs, type, > > rdev, resfhp); > > + fh_fill_post_attrs(fhp); > > out_unlock: > > - fh_unlock(fhp); > > + inode_unlock(dentry->d_inode); > > return err; > > } > > > > @@ -1460,20 +1462,22 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, > > goto out; > > } > > > > - fh_lock(fhp); > > dentry = fhp->fh_dentry; > > + inode_lock_nested(dentry->d_inode, I_MUTEX_PARENT); > > dnew = lookup_one_len(fname, dentry, flen); > > if (IS_ERR(dnew)) { > > err = nfserrno(PTR_ERR(dnew)); > > - fh_unlock(fhp); > > + inode_unlock(dentry->d_inode); > > goto out_drop_write; > > } > > + fh_fill_pre_attrs(fhp); > > host_err = vfs_symlink(&init_user_ns, 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_unlock(fhp); > > + fh_fill_post_attrs(fhp); > > + inode_unlock(dentry->d_inode); > > if (!err) > > err = nfserrno(commit_metadata(fhp)); > > dput(dnew); > > @@ -1519,9 +1523,9 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, > > goto out; > > } > > > > - fh_lock_nested(ffhp, I_MUTEX_PARENT); > > ddir = ffhp->fh_dentry; > > dirp = d_inode(ddir); > > + inode_lock_nested(dirp, I_MUTEX_PARENT); > > > > dnew = lookup_one_len(name, ddir, len); > > if (IS_ERR(dnew)) { > > @@ -1534,8 +1538,10 @@ 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); > > host_err = vfs_link(dold, &init_user_ns, dirp, dnew, NULL); > > - fh_unlock(ffhp); > > + fh_fill_post_attrs(ffhp); > > + inode_unlock(dirp); > > if (!host_err) { > > err = nfserrno(commit_metadata(ffhp)); > > if (!err) > > @@ -1555,7 +1561,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, > > out_dput: > > dput(dnew); > > out_unlock: > > - fh_unlock(ffhp); > > + inode_unlock(dirp); > > goto out_drop_write; > > } > > > > @@ -1730,9 +1736,9 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, > > if (host_err) > > goto out_nfserr; > > > > - fh_lock_nested(fhp, I_MUTEX_PARENT); > > dentry = fhp->fh_dentry; > > dirp = d_inode(dentry); > > + inode_lock_nested(dirp, I_MUTEX_PARENT); > > > > rdentry = lookup_one_len(fname, dentry, flen); > > host_err = PTR_ERR(rdentry); > > @@ -1750,6 +1756,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, > > if (!type) > > type = d_inode(rdentry)->i_mode & S_IFMT; > > > > + fh_fill_pre_attrs(fhp); > > if (type != S_IFDIR) { > > if (rdentry->d_sb->s_export_op->flags & EXPORT_OP_CLOSE_BEFORE_UNLINK) > > nfsd_close_cached_files(rdentry); > > @@ -1757,8 +1764,9 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, > > } else { > > host_err = vfs_rmdir(&init_user_ns, dirp, rdentry); > > } > > + fh_fill_post_attrs(fhp); > > > > - fh_unlock(fhp); > > + inode_unlock(dirp); > > if (!host_err) > > host_err = commit_metadata(fhp); > > dput(rdentry); > > @@ -1781,7 +1789,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, > > out: > > return err; > > out_unlock: > > - fh_unlock(fhp); > > + inode_unlock(dirp); > > goto out_drop_write; > > } > > > > > > > > -- > Chuck Lever > > > >