When accessing the exported filesystem, or the filesystem storing state-recovery data, we should use the idmap associated with the mount, or incorrect behaviour could eventuate of an idmapped filesystem were in use. This patch adds fh_idmap() to return the mnt_idmap for a given svc_fh() and uses that or other means to provide the correct mnt_idmap. nfsd no longer users nop_mnt_idmap. Signed-off-by: NeilBrown <neil@xxxxxxxxxx> --- fs/nfsd/nfs2acl.c | 4 ++-- fs/nfsd/nfs3acl.c | 4 ++-- fs/nfsd/nfs3proc.c | 2 +- fs/nfsd/nfs4recover.c | 7 ++++--- fs/nfsd/nfs4state.c | 9 ++++++--- fs/nfsd/nfs4xdr.c | 2 +- fs/nfsd/state.h | 4 +++- fs/nfsd/vfs.h | 12 ++++++++++++ 8 files changed, 31 insertions(+), 13 deletions(-) diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 5fb202acb0fd..cb15d2d0dd50 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -115,11 +115,11 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp) inode_lock(inode); - error = set_posix_acl(&nop_mnt_idmap, fh->fh_dentry, ACL_TYPE_ACCESS, + error = set_posix_acl(fh_idmap(fh), fh->fh_dentry, ACL_TYPE_ACCESS, argp->acl_access); if (error) goto out_drop_lock; - error = set_posix_acl(&nop_mnt_idmap, fh->fh_dentry, ACL_TYPE_DEFAULT, + error = set_posix_acl(fh_idmap(fh), fh->fh_dentry, ACL_TYPE_DEFAULT, argp->acl_default); if (error) goto out_drop_lock; diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index 7b5433bd3019..2e92a5673021 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -105,11 +105,11 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp) inode_lock(inode); - error = set_posix_acl(&nop_mnt_idmap, fh->fh_dentry, ACL_TYPE_ACCESS, + error = set_posix_acl(fh_idmap(fh), fh->fh_dentry, ACL_TYPE_ACCESS, argp->acl_access); if (error) goto out_drop_lock; - error = set_posix_acl(&nop_mnt_idmap, fh->fh_dentry, ACL_TYPE_DEFAULT, + error = set_posix_acl(fh_idmap(fh), fh->fh_dentry, ACL_TYPE_DEFAULT, argp->acl_default); out_drop_lock: diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 457638bf0f32..d32ce5956ca0 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -344,7 +344,7 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *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(fh_idmap(fhp), inode, child, iap->ia_mode, true); if (host_err < 0) { status = nfserrno(host_err); goto out; diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 10d24bec532f..f8fe23941873 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -233,7 +233,8 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) * as well be forgiving and just succeed silently. */ goto out_put; - dentry = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), dentry, S_IRWXU); + dentry = vfs_mkdir(mnt_idmap(nn->rec_file->f_path.mnt), d_inode(dir), + dentry, S_IRWXU); if (IS_ERR(dentry)) status = PTR_ERR(dentry); out_put: @@ -357,7 +358,7 @@ nfsd4_unlink_clid_dir(char *name, struct nfsd_net *nn) status = -ENOENT; if (d_really_is_negative(dentry)) goto out; - status = vfs_rmdir(&nop_mnt_idmap, d_inode(dir), dentry); + status = vfs_rmdir(mnt_idmap(nn->rec_file->f_path.mnt), d_inode(dir), dentry); out: dput(dentry); out_unlock: @@ -447,7 +448,7 @@ purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) if (nfs4_has_reclaimed_state(name, nn)) goto out_free; - status = vfs_rmdir(&nop_mnt_idmap, d_inode(parent), child); + status = vfs_rmdir(mnt_idmap(nn->rec_file->f_path.mnt), d_inode(parent), child); if (status) printk("failed to remove client recovery directory %pd\n", child); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 153eeea2c7c9..1796a6aeedd8 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -9079,7 +9079,8 @@ static bool set_cb_time(struct timespec64 *cb, const struct timespec64 *orig, return true; } -static int cb_getattr_update_times(struct dentry *dentry, struct nfs4_delegation *dp) +static int cb_getattr_update_times(struct vfsmount *mnt, struct dentry *dentry, + struct nfs4_delegation *dp) { struct inode *inode = d_inode(dentry); struct timespec64 now = current_time(inode); @@ -9111,7 +9112,7 @@ static int cb_getattr_update_times(struct dentry *dentry, struct nfs4_delegation attrs.ia_valid |= ATTR_DELEG; inode_lock(inode); - ret = notify_change(&nop_mnt_idmap, dentry, &attrs, NULL); + ret = notify_change(mnt_idmap(mnt), dentry, &attrs, NULL); inode_unlock(inode); return ret; } @@ -9120,6 +9121,7 @@ static int cb_getattr_update_times(struct dentry *dentry, struct nfs4_delegation * nfsd4_deleg_getattr_conflict - Recall if GETATTR causes conflict * @rqstp: RPC transaction context * @dentry: dentry of inode to be checked for a conflict + * @exp: svc_export being accessed * @pdp: returned WRITE delegation, if one was found * * This function is called when there is a conflict between a write @@ -9135,6 +9137,7 @@ static int cb_getattr_update_times(struct dentry *dentry, struct nfs4_delegation */ __be32 nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct dentry *dentry, + struct svc_export *exp, struct nfs4_delegation **pdp) { __be32 status; @@ -9203,7 +9206,7 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct dentry *dentry, * not update the file's metadata with the client's * modified size */ - err = cb_getattr_update_times(dentry, dp); + err = cb_getattr_update_times(exp->ex_path.mnt, dentry, dp); if (err) { status = nfserrno(err); goto out_status; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 64ab2c605e93..e7c87653e979 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3618,7 +3618,7 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr, (attrmask[1] & (FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_METADATA))) { - status = nfsd4_deleg_getattr_conflict(rqstp, dentry, &dp); + status = nfsd4_deleg_getattr_conflict(rqstp, dentry, exp, &dp); if (status) goto out; } diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 74d2d7b42676..8ef2bec43afa 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -826,5 +826,7 @@ static inline bool try_to_expire_client(struct nfs4_client *clp) } extern __be32 nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, - struct dentry *dentry, struct nfs4_delegation **pdp); + struct dentry *dentry, + struct svc_export *exp, + struct nfs4_delegation **pdp); #endif /* NFSD4_STATE_H */ diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index 5a60004468b8..1bb75d740427 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -205,4 +205,16 @@ static inline struct vfsmount *fh_mnt(struct svc_fh *fhp) return fhp->fh_export->ex_path.mnt; } +/** + * fh_idmap - access idmap of vfsmount of a given file handle + * @fhp: the filehandle + * + * Returns the struct idmap from the vfsmount of the export referenced in the + * filehandle. + */ +static inline struct mnt_idmap *fh_idmap(struct svc_fh *fhp) +{ + return mnt_idmap(fh_mnt(fhp));; +} + #endif /* LINUX_NFSD_VFS_H */ -- 2.48.1