mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-26 09:34:32 -04:00
nfsd: Implement NFSv4 FATTR4_CASE_INSENSITIVE and FATTR4_CASE_PRESERVING
NFSD currently provides NFSv4 clients with hard-coded responses indicating all exported filesystems are case-sensitive and case-preserving. This is incorrect for case-insensitive filesystems and ext4 directories with casefold enabled. Query the underlying filesystem's actual case sensitivity via nfsd_get_case_info() and return accurate values to clients. This supports per-directory settings for filesystems that allow mixing case-sensitive and case-insensitive directories within an export. The helper queries the parent dentry for non-directory filehandles because case-folding is a per-directory property. That resolution has the same corner cases here as for NFSv3 PATHCONF: single-file exports query an unexported parent, disconnected dentries report defaults until reconnected, and hardlinked files track whichever alias the dcache currently holds. Reviewed-by: Roland Mainz <roland.mainz@nrubsig.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Link: https://patch.msgid.link/20260507-case-sensitivity-v14-14-e62cc8200435@oracle.com Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
committed by
Christian Brauner
parent
211cb2ba48
commit
01ee7c3d2e
@@ -3158,6 +3158,8 @@ struct nfsd4_fattr_args {
|
||||
u32 rdattr_err;
|
||||
bool contextsupport;
|
||||
bool ignore_crossmnt;
|
||||
bool case_insensitive;
|
||||
bool case_preserving;
|
||||
};
|
||||
|
||||
typedef __be32(*nfsd4_enc_attr)(struct xdr_stream *xdr,
|
||||
@@ -3356,6 +3358,33 @@ static __be32 nfsd4_encode_fattr4_acl(struct xdr_stream *xdr,
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static __be32 nfsd4_encode_fattr4_case_insensitive(struct xdr_stream *xdr,
|
||||
const struct nfsd4_fattr_args *args)
|
||||
{
|
||||
return nfsd4_encode_bool(xdr, args->case_insensitive);
|
||||
}
|
||||
|
||||
static __be32 nfsd4_encode_fattr4_case_preserving(struct xdr_stream *xdr,
|
||||
const struct nfsd4_fattr_args *args)
|
||||
{
|
||||
return nfsd4_encode_bool(xdr, args->case_preserving);
|
||||
}
|
||||
|
||||
static __be32 nfsd4_encode_fattr4_homogeneous(struct xdr_stream *xdr,
|
||||
const struct nfsd4_fattr_args *args)
|
||||
{
|
||||
/*
|
||||
* Casefold-capable filesystems (e.g. ext4 or f2fs with the
|
||||
* casefold feature) attach a Unicode encoding at mount time
|
||||
* but apply case folding per directory. The per-file-system
|
||||
* case_insensitive and case_preserving values can therefore
|
||||
* legitimately differ across objects that share the same fsid.
|
||||
* Report FATTR4_HOMOGENEOUS = FALSE on such filesystems to
|
||||
* keep that variation consistent with RFC 8881 Section 5.8.2.16.
|
||||
*/
|
||||
return nfsd4_encode_bool(xdr, !sb_has_encoding(args->dentry->d_sb));
|
||||
}
|
||||
|
||||
static __be32 nfsd4_encode_fattr4_filehandle(struct xdr_stream *xdr,
|
||||
const struct nfsd4_fattr_args *args)
|
||||
{
|
||||
@@ -3748,8 +3777,8 @@ static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = {
|
||||
[FATTR4_ACLSUPPORT] = nfsd4_encode_fattr4_aclsupport,
|
||||
[FATTR4_ARCHIVE] = nfsd4_encode_fattr4__noop,
|
||||
[FATTR4_CANSETTIME] = nfsd4_encode_fattr4__true,
|
||||
[FATTR4_CASE_INSENSITIVE] = nfsd4_encode_fattr4__false,
|
||||
[FATTR4_CASE_PRESERVING] = nfsd4_encode_fattr4__true,
|
||||
[FATTR4_CASE_INSENSITIVE] = nfsd4_encode_fattr4_case_insensitive,
|
||||
[FATTR4_CASE_PRESERVING] = nfsd4_encode_fattr4_case_preserving,
|
||||
[FATTR4_CHOWN_RESTRICTED] = nfsd4_encode_fattr4__true,
|
||||
[FATTR4_FILEHANDLE] = nfsd4_encode_fattr4_filehandle,
|
||||
[FATTR4_FILEID] = nfsd4_encode_fattr4_fileid,
|
||||
@@ -3758,7 +3787,7 @@ static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = {
|
||||
[FATTR4_FILES_TOTAL] = nfsd4_encode_fattr4_files_total,
|
||||
[FATTR4_FS_LOCATIONS] = nfsd4_encode_fattr4_fs_locations,
|
||||
[FATTR4_HIDDEN] = nfsd4_encode_fattr4__noop,
|
||||
[FATTR4_HOMOGENEOUS] = nfsd4_encode_fattr4__true,
|
||||
[FATTR4_HOMOGENEOUS] = nfsd4_encode_fattr4_homogeneous,
|
||||
[FATTR4_MAXFILESIZE] = nfsd4_encode_fattr4_maxfilesize,
|
||||
[FATTR4_MAXLINK] = nfsd4_encode_fattr4_maxlink,
|
||||
[FATTR4_MAXNAME] = nfsd4_encode_fattr4_maxname,
|
||||
@@ -3968,6 +3997,23 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
|
||||
args.fhp = tempfh;
|
||||
} else
|
||||
args.fhp = fhp;
|
||||
if (attrmask[0] & (FATTR4_WORD0_CASE_INSENSITIVE |
|
||||
FATTR4_WORD0_CASE_PRESERVING)) {
|
||||
err = nfsd_get_case_info(dentry, &args.case_insensitive,
|
||||
&args.case_preserving);
|
||||
/*
|
||||
* Per RFC 8881 Section 18.7.3, an attribute advertised
|
||||
* in SUPPORTED_ATTRS must come back with a value or the
|
||||
* GETATTR must fail. nfsd_get_case_info() fills POSIX
|
||||
* defaults and returns -EOPNOTSUPP when the underlying
|
||||
* filesystem does not expose case state; encode those
|
||||
* defaults so the reply agrees with what SUPPORTED_ATTRS
|
||||
* advertises. Other errors fail the operation as the
|
||||
* spec requires.
|
||||
*/
|
||||
if (err && err != -EOPNOTSUPP)
|
||||
goto out_nfserr;
|
||||
}
|
||||
|
||||
if (attrmask[0] & FATTR4_WORD0_ACL) {
|
||||
err = nfsd4_get_nfs4_acl(rqstp, dentry, &args.acl);
|
||||
|
||||
Reference in New Issue
Block a user