* [PATCH v7 15/16] nfsd: Implement NFSv4 FATTR4_CASE_INSENSITIVE and FATTR4_CASE_PRESERVING
From: Chuck Lever @ 2026-01-22 16:03 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Jan Kara
Cc: linux-fsdevel, linux-ext4, linux-xfs, linux-cifs, linux-nfs,
linux-api, linux-f2fs-devel, hirofumi, linkinjeon, sj1557.seo,
yuezhang.mo, almaz.alexandrovich, slava, glaubitz, frank.li,
tytso, adilger.kernel, cem, sfrench, pc, ronniesahlberg, sprasad,
trondmy, anna, jaegeuk, chao, hansg, senozhatsky, Chuck Lever
In-Reply-To: <20260122160311.1117669-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
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.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/nfsd/nfs4xdr.c | 31 +++++++++++++++++++++++++++----
1 file changed, 27 insertions(+), 4 deletions(-)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 51ef97c25456..a4988a643d12 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2933,6 +2933,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,
@@ -3131,6 +3133,18 @@ 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_filehandle(struct xdr_stream *xdr,
const struct nfsd4_fattr_args *args)
{
@@ -3487,8 +3501,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,
@@ -3674,8 +3688,9 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
if (err)
goto out_nfserr;
}
- if ((attrmask[0] & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) &&
- !fhp) {
+ if ((attrmask[0] & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID |
+ FATTR4_WORD0_CASE_INSENSITIVE |
+ FATTR4_WORD0_CASE_PRESERVING)) && !fhp) {
tempfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
status = nfserr_jukebox;
if (!tempfh)
@@ -3687,6 +3702,14 @@ 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)) {
+ status = nfsd_get_case_info(args.fhp, &args.case_insensitive,
+ &args.case_preserving);
+ if (status != nfs_ok)
+ attrmask[0] &= ~(FATTR4_WORD0_CASE_INSENSITIVE |
+ FATTR4_WORD0_CASE_PRESERVING);
+ }
if (attrmask[0] & FATTR4_WORD0_ACL) {
err = nfsd4_get_nfs4_acl(rqstp, dentry, &args.acl);
--
2.52.0
^ permalink raw reply related
* [PATCH v7 14/16] nfsd: Report export case-folding via NFSv3 PATHCONF
From: Chuck Lever @ 2026-01-22 16:03 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Jan Kara
Cc: linux-fsdevel, linux-ext4, linux-xfs, linux-cifs, linux-nfs,
linux-api, linux-f2fs-devel, hirofumi, linkinjeon, sj1557.seo,
yuezhang.mo, almaz.alexandrovich, slava, glaubitz, frank.li,
tytso, adilger.kernel, cem, sfrench, pc, ronniesahlberg, sprasad,
trondmy, anna, jaegeuk, chao, hansg, senozhatsky, Chuck Lever
In-Reply-To: <20260122160311.1117669-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
The hard-coded MSDOS_SUPER_MAGIC check in nfsd3_proc_pathconf()
only recognizes FAT filesystems as case-insensitive. Modern
filesystems like F2FS, exFAT, and CIFS support case-insensitive
directories, but NFSv3 clients cannot discover this capability.
Query the export's actual case behavior through ->fileattr_get
instead. This allows NFSv3 clients to correctly handle case
sensitivity for any filesystem that implements the fileattr
interface. Filesystems without ->fileattr_get continue to report
the default POSIX behavior (case-sensitive, case-preserving).
This change assumes the ("fat: Implement fileattr_get for case
sensitivity") has been applied, which ensures FAT filesystems
report their case behavior correctly via the fileattr interface.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/nfsd/nfs3proc.c | 18 ++++++++++--------
fs/nfsd/vfs.c | 25 +++++++++++++++++++++++++
fs/nfsd/vfs.h | 2 ++
3 files changed, 37 insertions(+), 8 deletions(-)
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 42adc5461db0..9be0aca01de0 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -717,17 +717,19 @@ nfsd3_proc_pathconf(struct svc_rqst *rqstp)
if (resp->status == nfs_ok) {
struct super_block *sb = argp->fh.fh_dentry->d_sb;
+ bool case_insensitive, case_preserving;
- /* Note that we don't care for remote fs's here */
- switch (sb->s_magic) {
- case EXT2_SUPER_MAGIC:
+ if (sb->s_magic == EXT2_SUPER_MAGIC) {
resp->p_link_max = EXT2_LINK_MAX;
resp->p_name_max = EXT2_NAME_LEN;
- break;
- case MSDOS_SUPER_MAGIC:
- resp->p_case_insensitive = 1;
- resp->p_case_preserving = 0;
- break;
+ }
+
+ resp->status = nfsd_get_case_info(&argp->fh,
+ &case_insensitive,
+ &case_preserving);
+ if (resp->status == nfs_ok) {
+ resp->p_case_insensitive = case_insensitive;
+ resp->p_case_preserving = case_preserving;
}
}
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 168d3ccc8155..55cf0c0165c9 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -32,6 +32,7 @@
#include <linux/writeback.h>
#include <linux/security.h>
#include <linux/sunrpc/xdr.h>
+#include <linux/fileattr.h>
#include "xdr3.h"
@@ -2871,3 +2872,27 @@ nfsd_permission(struct svc_cred *cred, struct svc_export *exp,
return err? nfserrno(err) : 0;
}
+
+/**
+ * nfsd_get_case_info - get case sensitivity info for a file handle
+ * @fhp: file handle that has already been verified
+ * @case_insensitive: output, true if the filesystem is case-insensitive
+ * @case_preserving: output, true if the filesystem preserves case
+ *
+ * Returns nfs_ok on success, or an nfserr on failure.
+ */
+__be32
+nfsd_get_case_info(struct svc_fh *fhp, bool *case_insensitive,
+ bool *case_preserving)
+{
+ struct file_kattr fa = {};
+ int err;
+
+ err = vfs_fileattr_get(fhp->fh_dentry, &fa);
+ if (err && err != -ENOIOCTLCMD)
+ return nfserrno(err);
+
+ *case_insensitive = fa.fsx_xflags & FS_XFLAG_CASEFOLD;
+ *case_preserving = !(fa.fsx_xflags & FS_XFLAG_CASENONPRESERVING);
+ return nfs_ok;
+}
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index e192dca4a679..1ff62eecec09 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -155,6 +155,8 @@ __be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *,
loff_t *, struct readdir_cd *, nfsd_filldir_t);
__be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *,
struct kstatfs *, int access);
+__be32 nfsd_get_case_info(struct svc_fh *fhp, bool *case_insensitive,
+ bool *case_preserving);
__be32 nfsd_permission(struct svc_cred *cred, struct svc_export *exp,
struct dentry *dentry, int acc);
--
2.52.0
^ permalink raw reply related
* [PATCH v7 13/16] isofs: Implement fileattr_get for case sensitivity
From: Chuck Lever @ 2026-01-22 16:03 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Jan Kara
Cc: linux-fsdevel, linux-ext4, linux-xfs, linux-cifs, linux-nfs,
linux-api, linux-f2fs-devel, hirofumi, linkinjeon, sj1557.seo,
yuezhang.mo, almaz.alexandrovich, slava, glaubitz, frank.li,
tytso, adilger.kernel, cem, sfrench, pc, ronniesahlberg, sprasad,
trondmy, anna, jaegeuk, chao, hansg, senozhatsky, Chuck Lever
In-Reply-To: <20260122160311.1117669-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
Upper layers such as NFSD need a way to query whether a
filesystem handles filenames in a case-sensitive manner so
they can provide correct semantics to remote clients. Without
this information, NFS exports of ISO 9660 filesystems cannot
properly advertise their filename case behavior.
Implement isofs_fileattr_get() to report ISO 9660 case handling
behavior via the FS_XFLAG_CASEFOLD flag. The 'check=r' (relaxed)
mount option enables case-insensitive lookups, and this setting
determines the value reported. By default, Joliet extensions
operate in relaxed mode while plain ISO 9660 uses strict
(case-sensitive) mode. All ISO 9660 variants are case-preserving,
meaning filenames are stored exactly as they appear on the disc.
The callback is registered only on isofs_dir_inode_operations
because isofs has no custom inode_operations for regular
files, and symlinks use the generic page_symlink_inode_operations.
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/isofs/dir.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 09df40b612fb..e1a708f219f7 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -13,6 +13,7 @@
*/
#include <linux/gfp.h>
#include "isofs.h"
+#include <linux/fileattr.h>
int isofs_name_translate(struct iso_directory_record *de, char *new, struct inode *inode)
{
@@ -266,6 +267,19 @@ static int isofs_readdir(struct file *file, struct dir_context *ctx)
return result;
}
+static int isofs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
+{
+ struct isofs_sb_info *sbi = ISOFS_SB(dentry->d_sb);
+
+ /*
+ * FS_XFLAG_CASEFOLD indicates case-insensitive lookups.
+ * When check=r (relaxed) is set, lookups ignore case.
+ */
+ if (sbi->s_check == 'r')
+ fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
+ return 0;
+}
+
const struct file_operations isofs_dir_operations =
{
.llseek = generic_file_llseek,
@@ -279,6 +293,7 @@ const struct file_operations isofs_dir_operations =
const struct inode_operations isofs_dir_inode_operations =
{
.lookup = isofs_lookup,
+ .fileattr_get = isofs_fileattr_get,
};
--
2.52.0
^ permalink raw reply related
* [PATCH v7 12/16] vboxsf: Implement fileattr_get for case sensitivity
From: Chuck Lever @ 2026-01-22 16:03 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Jan Kara
Cc: linux-fsdevel, linux-ext4, linux-xfs, linux-cifs, linux-nfs,
linux-api, linux-f2fs-devel, hirofumi, linkinjeon, sj1557.seo,
yuezhang.mo, almaz.alexandrovich, slava, glaubitz, frank.li,
tytso, adilger.kernel, cem, sfrench, pc, ronniesahlberg, sprasad,
trondmy, anna, jaegeuk, chao, hansg, senozhatsky, Chuck Lever
In-Reply-To: <20260122160311.1117669-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
Upper layers such as NFSD need a way to query whether a
filesystem handles filenames in a case-sensitive manner. Report
VirtualBox shared folder case handling behavior via the
FS_XFLAG_CASEFOLD flag.
The case sensitivity property is queried from the VirtualBox host
service at mount time and cached in struct vboxsf_sbi. The host
determines case sensitivity based on the underlying host filesystem
(for example, Windows NTFS is case-insensitive while Linux ext4 is
case-sensitive).
VirtualBox shared folders always preserve filename case exactly
as provided by the guest. The host interface does not expose a
case_preserving property, so this is hardcoded to true.
The callback is registered in all three inode_operations
structures (directory, file, and symlink) to ensure consistent
reporting across all inode types.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/vboxsf/dir.c | 1 +
fs/vboxsf/file.c | 6 ++++--
fs/vboxsf/super.c | 4 ++++
fs/vboxsf/utils.c | 31 +++++++++++++++++++++++++++++++
fs/vboxsf/vfsmod.h | 6 ++++++
5 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/fs/vboxsf/dir.c b/fs/vboxsf/dir.c
index 42bedc4ec7af..c5bd3271aa96 100644
--- a/fs/vboxsf/dir.c
+++ b/fs/vboxsf/dir.c
@@ -477,4 +477,5 @@ const struct inode_operations vboxsf_dir_iops = {
.symlink = vboxsf_dir_symlink,
.getattr = vboxsf_getattr,
.setattr = vboxsf_setattr,
+ .fileattr_get = vboxsf_fileattr_get,
};
diff --git a/fs/vboxsf/file.c b/fs/vboxsf/file.c
index 4bebd947314a..06308e38a70d 100644
--- a/fs/vboxsf/file.c
+++ b/fs/vboxsf/file.c
@@ -223,7 +223,8 @@ const struct file_operations vboxsf_reg_fops = {
const struct inode_operations vboxsf_reg_iops = {
.getattr = vboxsf_getattr,
- .setattr = vboxsf_setattr
+ .setattr = vboxsf_setattr,
+ .fileattr_get = vboxsf_fileattr_get,
};
static int vboxsf_read_folio(struct file *file, struct folio *folio)
@@ -390,5 +391,6 @@ static const char *vboxsf_get_link(struct dentry *dentry, struct inode *inode,
}
const struct inode_operations vboxsf_lnk_iops = {
- .get_link = vboxsf_get_link
+ .get_link = vboxsf_get_link,
+ .fileattr_get = vboxsf_fileattr_get,
};
diff --git a/fs/vboxsf/super.c b/fs/vboxsf/super.c
index 241647b060ee..fcabeca2a339 100644
--- a/fs/vboxsf/super.c
+++ b/fs/vboxsf/super.c
@@ -185,6 +185,10 @@ static int vboxsf_fill_super(struct super_block *sb, struct fs_context *fc)
if (err)
goto fail_unmap;
+ err = vboxsf_query_case_sensitive(sbi);
+ if (err)
+ goto fail_unmap;
+
sb->s_magic = VBOXSF_SUPER_MAGIC;
sb->s_blocksize = 1024;
sb->s_maxbytes = MAX_LFS_FILESIZE;
diff --git a/fs/vboxsf/utils.c b/fs/vboxsf/utils.c
index 9515bbf0b54c..658b8b0ebbd7 100644
--- a/fs/vboxsf/utils.c
+++ b/fs/vboxsf/utils.c
@@ -11,6 +11,7 @@
#include <linux/sizes.h>
#include <linux/pagemap.h>
#include <linux/vfs.h>
+#include <linux/fileattr.h>
#include "vfsmod.h"
struct inode *vboxsf_new_inode(struct super_block *sb)
@@ -567,3 +568,33 @@ int vboxsf_dir_read_all(struct vboxsf_sbi *sbi, struct vboxsf_dir_info *sf_d,
return err;
}
+
+int vboxsf_query_case_sensitive(struct vboxsf_sbi *sbi)
+{
+ struct shfl_volinfo volinfo = {};
+ u32 buf_len;
+ int err;
+
+ buf_len = sizeof(volinfo);
+ err = vboxsf_fsinfo(sbi->root, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME,
+ &buf_len, &volinfo);
+ if (err)
+ return err;
+
+ sbi->case_insensitive = !volinfo.properties.case_sensitive;
+ return 0;
+}
+
+int vboxsf_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
+{
+ struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb);
+
+ /*
+ * VirtualBox shared folders preserve filename case exactly as
+ * provided by the guest (the default). The host interface does
+ * not expose a case-preservation property.
+ */
+ if (sbi->case_insensitive)
+ fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
+ return 0;
+}
diff --git a/fs/vboxsf/vfsmod.h b/fs/vboxsf/vfsmod.h
index 05973eb89d52..b61afd0ce842 100644
--- a/fs/vboxsf/vfsmod.h
+++ b/fs/vboxsf/vfsmod.h
@@ -47,6 +47,7 @@ struct vboxsf_sbi {
u32 next_generation;
u32 root;
int bdi_id;
+ bool case_insensitive;
};
/* per-inode information */
@@ -111,6 +112,11 @@ void vboxsf_dir_info_free(struct vboxsf_dir_info *p);
int vboxsf_dir_read_all(struct vboxsf_sbi *sbi, struct vboxsf_dir_info *sf_d,
u64 handle);
+int vboxsf_query_case_sensitive(struct vboxsf_sbi *sbi);
+
+struct file_kattr;
+int vboxsf_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
+
/* from vboxsf_wrappers.c */
int vboxsf_connect(void);
void vboxsf_disconnect(void);
--
2.52.0
^ permalink raw reply related
* [PATCH v7 11/16] f2fs: Add case sensitivity reporting to fileattr_get
From: Chuck Lever @ 2026-01-22 16:03 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Jan Kara
Cc: linux-fsdevel, linux-ext4, linux-xfs, linux-cifs, linux-nfs,
linux-api, linux-f2fs-devel, hirofumi, linkinjeon, sj1557.seo,
yuezhang.mo, almaz.alexandrovich, slava, glaubitz, frank.li,
tytso, adilger.kernel, cem, sfrench, pc, ronniesahlberg, sprasad,
trondmy, anna, jaegeuk, chao, hansg, senozhatsky, Chuck Lever
In-Reply-To: <20260122160311.1117669-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
NFS and other remote filesystem protocols need to determine
whether a local filesystem performs case-insensitive lookups
so they can provide correct semantics to clients. Without
this information, f2fs exports cannot properly advertise
their filename case behavior.
Report f2fs case sensitivity behavior via the FS_XFLAG_CASEFOLD
flag. Like ext4, f2fs supports per-directory case folding via
the casefold flag (IS_CASEFOLDED). Files are always case-preserving.
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/f2fs/file.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index d7047ca6b98d..91c255bbbf48 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -3439,6 +3439,13 @@ int f2fs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
if (f2fs_sb_has_project_quota(F2FS_I_SB(inode)))
fa->fsx_projid = from_kprojid(&init_user_ns, fi->i_projid);
+ /*
+ * f2fs preserves case (the default). If this inode is a
+ * casefolded directory, report case-insensitive; otherwise
+ * report case-sensitive (standard POSIX behavior).
+ */
+ if (IS_CASEFOLDED(inode))
+ fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
return 0;
}
--
2.52.0
^ permalink raw reply related
* [PATCH v7 10/16] nfs: Implement fileattr_get for case sensitivity
From: Chuck Lever @ 2026-01-22 16:03 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Jan Kara
Cc: linux-fsdevel, linux-ext4, linux-xfs, linux-cifs, linux-nfs,
linux-api, linux-f2fs-devel, hirofumi, linkinjeon, sj1557.seo,
yuezhang.mo, almaz.alexandrovich, slava, glaubitz, frank.li,
tytso, adilger.kernel, cem, sfrench, pc, ronniesahlberg, sprasad,
trondmy, anna, jaegeuk, chao, hansg, senozhatsky, Chuck Lever
In-Reply-To: <20260122160311.1117669-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
An NFS server re-exporting an NFS mount point needs to report the
case sensitivity behavior of the underlying filesystem to its
clients. Without this, re-export servers cannot accurately convey
case handling semantics, potentially causing client applications to
make incorrect assumptions about filename collisions and lookups.
The NFS client already retrieves case sensitivity information from
servers during mount via PATHCONF (NFSv3) or the
FATTR4_CASE_INSENSITIVE/FATTR4_CASE_PRESERVING attributes (NFSv4).
Expose this information through fileattr_get by reporting the
FS_XFLAG_CASEFOLD and FS_XFLAG_CASENONPRESERVING flags. NFSv2 lacks
PATHCONF support, so mounts using that protocol version default to
standard POSIX behavior: case-sensitive and case-preserving.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/nfs/client.c | 9 +++++++--
fs/nfs/inode.c | 20 ++++++++++++++++++++
fs/nfs/internal.h | 3 +++
fs/nfs/nfs3proc.c | 2 ++
fs/nfs/nfs3xdr.c | 7 +++++--
fs/nfs/nfs4proc.c | 2 ++
fs/nfs/proc.c | 3 +++
fs/nfs/symlink.c | 3 +++
include/linux/nfs_xdr.h | 2 ++
9 files changed, 47 insertions(+), 4 deletions(-)
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 2aaea9c98c2c..da437d89e14a 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -935,13 +935,18 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str
/* Get some general file system info */
if (server->namelen == 0) {
- struct nfs_pathconf pathinfo;
+ struct nfs_pathconf pathinfo = { };
pathinfo.fattr = fattr;
nfs_fattr_init(fattr);
- if (clp->rpc_ops->pathconf(server, mntfh, &pathinfo) >= 0)
+ if (clp->rpc_ops->pathconf(server, mntfh, &pathinfo) >= 0) {
server->namelen = pathinfo.max_namelen;
+ if (pathinfo.case_insensitive)
+ server->caps |= NFS_CAP_CASE_INSENSITIVE;
+ if (pathinfo.case_preserving)
+ server->caps |= NFS_CAP_CASE_PRESERVING;
+ }
}
if (clp->rpc_ops->discover_trunking != NULL &&
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index de2cce1d08f4..77b4de8a1050 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -41,6 +41,7 @@
#include <linux/freezer.h>
#include <linux/uaccess.h>
#include <linux/iversion.h>
+#include <linux/fileattr.h>
#include "nfs4_fs.h"
#include "callback.h"
@@ -1102,6 +1103,25 @@ int nfs_getattr(struct mnt_idmap *idmap, const struct path *path,
}
EXPORT_SYMBOL_GPL(nfs_getattr);
+/**
+ * nfs_fileattr_get - Retrieve file attributes
+ * @dentry: object to query
+ * @fa: file attributes to fill in
+ *
+ * Return: 0 on success
+ */
+int nfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
+{
+ struct inode *inode = d_inode(dentry);
+
+ if (nfs_server_capable(inode, NFS_CAP_CASE_INSENSITIVE))
+ fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
+ if (!nfs_server_capable(inode, NFS_CAP_CASE_PRESERVING))
+ fa->fsx_xflags |= FS_XFLAG_CASENONPRESERVING;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nfs_fileattr_get);
+
static void nfs_init_lock_context(struct nfs_lock_context *l_ctx)
{
refcount_set(&l_ctx->count, 1);
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 2e596244799f..a843e076aad7 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -453,6 +453,9 @@ extern void nfs_set_cache_invalid(struct inode *inode, unsigned long flags);
extern bool nfs_check_cache_invalid(struct inode *, unsigned long);
extern int nfs_wait_bit_killable(struct wait_bit_key *key, int mode);
+struct file_kattr;
+int nfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
+
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
/* localio.c */
struct nfs_local_dio {
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 1181f9cc6dbd..60344a83f400 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -1048,6 +1048,7 @@ static const struct inode_operations nfs3_dir_inode_operations = {
.permission = nfs_permission,
.getattr = nfs_getattr,
.setattr = nfs_setattr,
+ .fileattr_get = nfs_fileattr_get,
#ifdef CONFIG_NFS_V3_ACL
.listxattr = nfs3_listxattr,
.get_inode_acl = nfs3_get_acl,
@@ -1059,6 +1060,7 @@ static const struct inode_operations nfs3_file_inode_operations = {
.permission = nfs_permission,
.getattr = nfs_getattr,
.setattr = nfs_setattr,
+ .fileattr_get = nfs_fileattr_get,
#ifdef CONFIG_NFS_V3_ACL
.listxattr = nfs3_listxattr,
.get_inode_acl = nfs3_get_acl,
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index e17d72908412..e745e78faab0 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -2276,8 +2276,11 @@ static int decode_pathconf3resok(struct xdr_stream *xdr,
if (unlikely(!p))
return -EIO;
result->max_link = be32_to_cpup(p++);
- result->max_namelen = be32_to_cpup(p);
- /* ignore remaining fields */
+ result->max_namelen = be32_to_cpup(p++);
+ p++; /* ignore no_trunc */
+ p++; /* ignore chown_restricted */
+ result->case_insensitive = be32_to_cpup(p++) != 0;
+ result->case_preserving = be32_to_cpup(p) != 0;
return 0;
}
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index a0885ae55abc..7bb1ea77d20e 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -11072,6 +11072,7 @@ static const struct inode_operations nfs4_dir_inode_operations = {
.getattr = nfs_getattr,
.setattr = nfs_setattr,
.listxattr = nfs4_listxattr,
+ .fileattr_get = nfs_fileattr_get,
};
static const struct inode_operations nfs4_file_inode_operations = {
@@ -11079,6 +11080,7 @@ static const struct inode_operations nfs4_file_inode_operations = {
.getattr = nfs_getattr,
.setattr = nfs_setattr,
.listxattr = nfs4_listxattr,
+ .fileattr_get = nfs_fileattr_get,
};
static struct nfs_server *nfs4_clone_server(struct nfs_server *source,
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 39df80e4ae6f..48f02a80b800 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -597,6 +597,7 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
{
info->max_link = 0;
info->max_namelen = NFS2_MAXNAMLEN;
+ info->case_preserving = true;
return 0;
}
@@ -718,12 +719,14 @@ static const struct inode_operations nfs_dir_inode_operations = {
.permission = nfs_permission,
.getattr = nfs_getattr,
.setattr = nfs_setattr,
+ .fileattr_get = nfs_fileattr_get,
};
static const struct inode_operations nfs_file_inode_operations = {
.permission = nfs_permission,
.getattr = nfs_getattr,
.setattr = nfs_setattr,
+ .fileattr_get = nfs_fileattr_get,
};
const struct nfs_rpc_ops nfs_v2_clientops = {
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index 58146e935402..74a072896f8d 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -22,6 +22,8 @@
#include <linux/mm.h>
#include <linux/string.h>
+#include "internal.h"
+
/* Symlink caching in the page cache is even more simplistic
* and straight-forward than readdir caching.
*/
@@ -74,4 +76,5 @@ const struct inode_operations nfs_symlink_inode_operations = {
.get_link = nfs_get_link,
.getattr = nfs_getattr,
.setattr = nfs_setattr,
+ .fileattr_get = nfs_fileattr_get,
};
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 79fe2dfb470f..5f061a9db2c2 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -182,6 +182,8 @@ struct nfs_pathconf {
struct nfs_fattr *fattr; /* Post-op attributes */
__u32 max_link; /* max # of hard links */
__u32 max_namelen; /* max name length */
+ bool case_insensitive;
+ bool case_preserving;
};
struct nfs4_change_info {
--
2.52.0
^ permalink raw reply related
* [PATCH v7 09/16] cifs: Implement fileattr_get for case sensitivity
From: Chuck Lever @ 2026-01-22 16:03 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Jan Kara
Cc: linux-fsdevel, linux-ext4, linux-xfs, linux-cifs, linux-nfs,
linux-api, linux-f2fs-devel, hirofumi, linkinjeon, sj1557.seo,
yuezhang.mo, almaz.alexandrovich, slava, glaubitz, frank.li,
tytso, adilger.kernel, cem, sfrench, pc, ronniesahlberg, sprasad,
trondmy, anna, jaegeuk, chao, hansg, senozhatsky, Chuck Lever
In-Reply-To: <20260122160311.1117669-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
Upper layers such as NFSD need a way to query whether a filesystem
handles filenames in a case-sensitive manner. Report CIFS/SMB case
handling behavior via the FS_XFLAG_CASEFOLD flag.
CIFS servers (typically Windows or Samba) are usually case-insensitive
but case-preserving, meaning they ignore case during lookups but store
filenames exactly as provided.
The implementation reports case sensitivity based on the nocase mount
option, which reflects whether the client expects the server to perform
case-insensitive comparisons. When nocase is set, the mount is reported
as case-insensitive.
The callback is registered in all three inode_operations structures
(directory, file, and symlink) to ensure consistent reporting across
all inode types.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/smb/client/cifsfs.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index d9664634144d..39426a128b3d 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -30,6 +30,7 @@
#include <linux/xattr.h>
#include <linux/mm.h>
#include <linux/key-type.h>
+#include <linux/fileattr.h>
#include <uapi/linux/magic.h>
#include <net/ipv6.h>
#include "cifsfs.h"
@@ -1193,6 +1194,22 @@ struct file_system_type smb3_fs_type = {
MODULE_ALIAS_FS("smb3");
MODULE_ALIAS("smb3");
+static int cifs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
+{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
+ struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+
+ /*
+ * Case sensitivity is reported based on the nocase mount option.
+ * CIFS servers typically perform case-insensitive lookups while
+ * preserving case in stored filenames. The nocase option indicates
+ * case-insensitive comparison is in effect for this mount.
+ */
+ if (tcon->nocase)
+ fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
+ return 0;
+}
+
const struct inode_operations cifs_dir_inode_ops = {
.create = cifs_create,
.atomic_open = cifs_atomic_open,
@@ -1210,6 +1227,7 @@ const struct inode_operations cifs_dir_inode_ops = {
.listxattr = cifs_listxattr,
.get_acl = cifs_get_acl,
.set_acl = cifs_set_acl,
+ .fileattr_get = cifs_fileattr_get,
};
const struct inode_operations cifs_file_inode_ops = {
@@ -1220,6 +1238,7 @@ const struct inode_operations cifs_file_inode_ops = {
.fiemap = cifs_fiemap,
.get_acl = cifs_get_acl,
.set_acl = cifs_set_acl,
+ .fileattr_get = cifs_fileattr_get,
};
const char *cifs_get_link(struct dentry *dentry, struct inode *inode,
@@ -1254,6 +1273,7 @@ const struct inode_operations cifs_symlink_inode_ops = {
.setattr = cifs_setattr,
.permission = cifs_permission,
.listxattr = cifs_listxattr,
+ .fileattr_get = cifs_fileattr_get,
};
/*
--
2.52.0
^ permalink raw reply related
* [PATCH v7 08/16] xfs: Report case sensitivity in fileattr_get
From: Chuck Lever @ 2026-01-22 16:03 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Jan Kara
Cc: linux-fsdevel, linux-ext4, linux-xfs, linux-cifs, linux-nfs,
linux-api, linux-f2fs-devel, hirofumi, linkinjeon, sj1557.seo,
yuezhang.mo, almaz.alexandrovich, slava, glaubitz, frank.li,
tytso, adilger.kernel, cem, sfrench, pc, ronniesahlberg, sprasad,
trondmy, anna, jaegeuk, chao, hansg, senozhatsky, Chuck Lever,
Darrick J. Wong
In-Reply-To: <20260122160311.1117669-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
Upper layers such as NFSD need to query whether a filesystem is
case-sensitive. Report case sensitivity via the FS_XFLAG_CASEFOLD
flag in xfs_fileattr_get(). XFS always preserves case. XFS is
case-sensitive by default, but supports ASCII case-insensitive
lookups when formatted with the ASCIICI feature flag.
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/xfs/xfs_ioctl.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index f0417c4d1fca..da98d4422b02 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -516,6 +516,13 @@ xfs_fileattr_get(
xfs_fill_fsxattr(ip, XFS_DATA_FORK, fa);
xfs_iunlock(ip, XFS_ILOCK_SHARED);
+ /*
+ * FS_XFLAG_CASEFOLD indicates case-insensitive lookups with
+ * case preservation. This matches ASCIICI behavior: lookups
+ * fold ASCII case while filenames remain stored verbatim.
+ */
+ if (xfs_has_asciici(ip->i_mount))
+ fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
return 0;
}
--
2.52.0
^ permalink raw reply related
* [PATCH v7 07/16] ext4: Report case sensitivity in fileattr_get
From: Chuck Lever @ 2026-01-22 16:03 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Jan Kara
Cc: linux-fsdevel, linux-ext4, linux-xfs, linux-cifs, linux-nfs,
linux-api, linux-f2fs-devel, hirofumi, linkinjeon, sj1557.seo,
yuezhang.mo, almaz.alexandrovich, slava, glaubitz, frank.li,
tytso, adilger.kernel, cem, sfrench, pc, ronniesahlberg, sprasad,
trondmy, anna, jaegeuk, chao, hansg, senozhatsky, Chuck Lever
In-Reply-To: <20260122160311.1117669-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
Report ext4's case sensitivity behavior via the FS_XFLAG_CASEFOLD
flag. ext4 always preserves case at rest.
Case sensitivity is a per-directory setting in ext4. If the queried
inode is a casefolded directory, report case-insensitive; otherwise
report case-sensitive (standard POSIX behavior).
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/ext4/ioctl.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 7ce0fc40aec2..462da7aadc80 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -996,6 +996,13 @@ int ext4_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
if (ext4_has_feature_project(inode->i_sb))
fa->fsx_projid = from_kprojid(&init_user_ns, ei->i_projid);
+ /*
+ * Case folding is a directory attribute in ext4. Set FS_XFLAG_CASEFOLD
+ * for directories with the casefold attribute; all other inodes use
+ * standard case-sensitive semantics.
+ */
+ if (IS_CASEFOLDED(inode))
+ fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
return 0;
}
--
2.52.0
^ permalink raw reply related
* [PATCH v7 06/16] hfsplus: Report case sensitivity in fileattr_get
From: Chuck Lever @ 2026-01-22 16:03 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Jan Kara
Cc: linux-fsdevel, linux-ext4, linux-xfs, linux-cifs, linux-nfs,
linux-api, linux-f2fs-devel, hirofumi, linkinjeon, sj1557.seo,
yuezhang.mo, almaz.alexandrovich, slava, glaubitz, frank.li,
tytso, adilger.kernel, cem, sfrench, pc, ronniesahlberg, sprasad,
trondmy, anna, jaegeuk, chao, hansg, senozhatsky, Chuck Lever
In-Reply-To: <20260122160311.1117669-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
Add case sensitivity reporting to the existing hfsplus_fileattr_get()
function via the FS_XFLAG_CASEFOLD flag. HFS+ always preserves case
at rest.
Case sensitivity depends on how the volume was formatted: HFSX
volumes may be either case-sensitive or case-insensitive, indicated
by the HFSPLUS_SB_CASEFOLD superblock flag.
Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/hfsplus/inode.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 7ae6745ca7ae..ec9a144aac02 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -694,6 +694,7 @@ int hfsplus_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
{
struct inode *inode = d_inode(dentry);
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
+ struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
unsigned int flags = 0;
if (inode->i_flags & S_IMMUTABLE)
@@ -705,6 +706,13 @@ int hfsplus_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
fileattr_fill_flags(fa, flags);
+ /*
+ * HFS+ preserves case (the default). Case sensitivity depends
+ * on how the filesystem was formatted: HFSX volumes may be
+ * either case-sensitive or case-insensitive.
+ */
+ if (test_bit(HFSPLUS_SB_CASEFOLD, &sbi->flags))
+ fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
return 0;
}
--
2.52.0
^ permalink raw reply related
* [PATCH v7 05/16] hfs: Implement fileattr_get for case sensitivity
From: Chuck Lever @ 2026-01-22 16:03 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Jan Kara
Cc: linux-fsdevel, linux-ext4, linux-xfs, linux-cifs, linux-nfs,
linux-api, linux-f2fs-devel, hirofumi, linkinjeon, sj1557.seo,
yuezhang.mo, almaz.alexandrovich, slava, glaubitz, frank.li,
tytso, adilger.kernel, cem, sfrench, pc, ronniesahlberg, sprasad,
trondmy, anna, jaegeuk, chao, hansg, senozhatsky, Chuck Lever
In-Reply-To: <20260122160311.1117669-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
Report HFS case sensitivity behavior via the FS_XFLAG_CASEFOLD
flag. HFS is always case-insensitive (using Mac OS Roman case
folding) and always preserves case at rest.
Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/hfs/dir.c | 1 +
fs/hfs/hfs_fs.h | 2 ++
fs/hfs/inode.c | 13 +++++++++++++
3 files changed, 16 insertions(+)
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index 86a6b317b474..552156896105 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -321,4 +321,5 @@ const struct inode_operations hfs_dir_inode_operations = {
.rmdir = hfs_remove,
.rename = hfs_rename,
.setattr = hfs_inode_setattr,
+ .fileattr_get = hfs_fileattr_get,
};
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
index e94dbc04a1e4..a25cdda8ab34 100644
--- a/fs/hfs/hfs_fs.h
+++ b/fs/hfs/hfs_fs.h
@@ -177,6 +177,8 @@ extern int hfs_get_block(struct inode *inode, sector_t block,
extern const struct address_space_operations hfs_aops;
extern const struct address_space_operations hfs_btree_aops;
+struct file_kattr;
+int hfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
int hfs_write_begin(const struct kiocb *iocb, struct address_space *mapping,
loff_t pos, unsigned int len, struct folio **foliop,
void **fsdata);
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 524db1389737..8d7ef19af538 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -18,6 +18,7 @@
#include <linux/uio.h>
#include <linux/xattr.h>
#include <linux/blkdev.h>
+#include <linux/fileattr.h>
#include "hfs_fs.h"
#include "btree.h"
@@ -698,6 +699,17 @@ static int hfs_file_fsync(struct file *filp, loff_t start, loff_t end,
return ret;
}
+int hfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
+{
+ /*
+ * Report case-insensitive behavior: all name comparisons use
+ * Mac OS Roman case folding. FS_XFLAG_CASENONPRESERVING remains
+ * unset because original case is preserved on disk.
+ */
+ fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
+ return 0;
+}
+
static const struct file_operations hfs_file_operations = {
.llseek = generic_file_llseek,
.read_iter = generic_file_read_iter,
@@ -714,4 +726,5 @@ static const struct inode_operations hfs_file_inode_operations = {
.lookup = hfs_file_lookup,
.setattr = hfs_inode_setattr,
.listxattr = generic_listxattr,
+ .fileattr_get = hfs_fileattr_get,
};
--
2.52.0
^ permalink raw reply related
* [PATCH v7 04/16] ntfs3: Implement fileattr_get for case sensitivity
From: Chuck Lever @ 2026-01-22 16:02 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Jan Kara
Cc: linux-fsdevel, linux-ext4, linux-xfs, linux-cifs, linux-nfs,
linux-api, linux-f2fs-devel, hirofumi, linkinjeon, sj1557.seo,
yuezhang.mo, almaz.alexandrovich, slava, glaubitz, frank.li,
tytso, adilger.kernel, cem, sfrench, pc, ronniesahlberg, sprasad,
trondmy, anna, jaegeuk, chao, hansg, senozhatsky, Chuck Lever
In-Reply-To: <20260122160311.1117669-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
Report NTFS case sensitivity behavior via the FS_XFLAG_CASEFOLD
flag. NTFS always preserves case at rest.
Case sensitivity depends on mount options: with "nocase", NTFS
is case-insensitive; otherwise it is case-sensitive.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/ntfs3/file.c | 23 +++++++++++++++++++++++
fs/ntfs3/inode.c | 1 +
fs/ntfs3/namei.c | 2 ++
fs/ntfs3/ntfs_fs.h | 1 +
4 files changed, 27 insertions(+)
diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
index 2e7b2e566ebe..6562768f4574 100644
--- a/fs/ntfs3/file.c
+++ b/fs/ntfs3/file.c
@@ -146,6 +146,28 @@ long ntfs_compat_ioctl(struct file *filp, u32 cmd, unsigned long arg)
}
#endif
+/*
+ * ntfs_fileattr_get - inode_operations::fileattr_get
+ */
+int ntfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
+{
+ struct inode *inode = d_inode(dentry);
+ struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info;
+
+ /* Avoid any operation if inode is bad. */
+ if (unlikely(is_bad_ni(ntfs_i(inode))))
+ return -EINVAL;
+
+ /*
+ * NTFS preserves case (the default). Case sensitivity depends on
+ * mount options: with "nocase", NTFS is case-insensitive;
+ * otherwise it is case-sensitive.
+ */
+ if (sbi->options && sbi->options->nocase)
+ fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
+ return 0;
+}
+
/*
* ntfs_getattr - inode_operations::getattr
*/
@@ -1460,6 +1482,7 @@ const struct inode_operations ntfs_file_inode_operations = {
.get_acl = ntfs_get_acl,
.set_acl = ntfs_set_acl,
.fiemap = ntfs_fiemap,
+ .fileattr_get = ntfs_fileattr_get,
};
const struct file_operations ntfs_file_operations = {
diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c
index 0a9ac5efeb67..205083e8a6e0 100644
--- a/fs/ntfs3/inode.c
+++ b/fs/ntfs3/inode.c
@@ -2089,6 +2089,7 @@ const struct inode_operations ntfs_link_inode_operations = {
.get_link = ntfs_get_link,
.setattr = ntfs_setattr,
.listxattr = ntfs_listxattr,
+ .fileattr_get = ntfs_fileattr_get,
};
const struct address_space_operations ntfs_aops = {
diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c
index 3b24ca02de61..d09414711016 100644
--- a/fs/ntfs3/namei.c
+++ b/fs/ntfs3/namei.c
@@ -519,6 +519,7 @@ const struct inode_operations ntfs_dir_inode_operations = {
.getattr = ntfs_getattr,
.listxattr = ntfs_listxattr,
.fiemap = ntfs_fiemap,
+ .fileattr_get = ntfs_fileattr_get,
};
const struct inode_operations ntfs_special_inode_operations = {
@@ -527,6 +528,7 @@ const struct inode_operations ntfs_special_inode_operations = {
.listxattr = ntfs_listxattr,
.get_acl = ntfs_get_acl,
.set_acl = ntfs_set_acl,
+ .fileattr_get = ntfs_fileattr_get,
};
const struct dentry_operations ntfs_dentry_ops = {
diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h
index a4559c9f64e6..a578b75f31fc 100644
--- a/fs/ntfs3/ntfs_fs.h
+++ b/fs/ntfs3/ntfs_fs.h
@@ -504,6 +504,7 @@ extern const struct file_operations ntfs_dir_operations;
extern const struct file_operations ntfs_legacy_dir_operations;
/* Globals from file.c */
+int ntfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path,
struct kstat *stat, u32 request_mask, u32 flags);
int ntfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
--
2.52.0
^ permalink raw reply related
* [PATCH v7 03/16] exfat: Implement fileattr_get for case sensitivity
From: Chuck Lever @ 2026-01-22 16:02 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Jan Kara
Cc: linux-fsdevel, linux-ext4, linux-xfs, linux-cifs, linux-nfs,
linux-api, linux-f2fs-devel, hirofumi, linkinjeon, sj1557.seo,
yuezhang.mo, almaz.alexandrovich, slava, glaubitz, frank.li,
tytso, adilger.kernel, cem, sfrench, pc, ronniesahlberg, sprasad,
trondmy, anna, jaegeuk, chao, hansg, senozhatsky, Chuck Lever
In-Reply-To: <20260122160311.1117669-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
Report exFAT's case sensitivity behavior via the FS_XFLAG_CASEFOLD
flag. exFAT is always case-insensitive (using an upcase table for
comparison) and always preserves case at rest.
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/exfat/exfat_fs.h | 2 ++
fs/exfat/file.c | 16 ++++++++++++++--
fs/exfat/namei.c | 1 +
3 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index 176fef62574c..11c782a28843 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -468,6 +468,8 @@ int exfat_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
int exfat_getattr(struct mnt_idmap *idmap, const struct path *path,
struct kstat *stat, unsigned int request_mask,
unsigned int query_flags);
+struct file_kattr;
+int exfat_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
int exfat_file_fsync(struct file *file, loff_t start, loff_t end, int datasync);
long exfat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
long exfat_compat_ioctl(struct file *filp, unsigned int cmd,
diff --git a/fs/exfat/file.c b/fs/exfat/file.c
index 536c8078f0c1..eb01238e1189 100644
--- a/fs/exfat/file.c
+++ b/fs/exfat/file.c
@@ -12,6 +12,7 @@
#include <linux/security.h>
#include <linux/msdos_fs.h>
#include <linux/writeback.h>
+#include <linux/fileattr.h>
#include "exfat_raw.h"
#include "exfat_fs.h"
@@ -281,6 +282,16 @@ int exfat_getattr(struct mnt_idmap *idmap, const struct path *path,
return 0;
}
+int exfat_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
+{
+ /*
+ * exFAT is always case-insensitive (using upcase table).
+ * Case is preserved at rest (the default).
+ */
+ fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
+ return 0;
+}
+
int exfat_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
struct iattr *attr)
{
@@ -775,6 +786,7 @@ const struct file_operations exfat_file_operations = {
};
const struct inode_operations exfat_file_inode_operations = {
- .setattr = exfat_setattr,
- .getattr = exfat_getattr,
+ .setattr = exfat_setattr,
+ .getattr = exfat_getattr,
+ .fileattr_get = exfat_fileattr_get,
};
diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c
index dfe957493d49..a3a854ddc83a 100644
--- a/fs/exfat/namei.c
+++ b/fs/exfat/namei.c
@@ -1323,4 +1323,5 @@ const struct inode_operations exfat_dir_inode_operations = {
.rename = exfat_rename,
.setattr = exfat_setattr,
.getattr = exfat_getattr,
+ .fileattr_get = exfat_fileattr_get,
};
--
2.52.0
^ permalink raw reply related
* [PATCH v7 02/16] fat: Implement fileattr_get for case sensitivity
From: Chuck Lever @ 2026-01-22 16:02 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Jan Kara
Cc: linux-fsdevel, linux-ext4, linux-xfs, linux-cifs, linux-nfs,
linux-api, linux-f2fs-devel, hirofumi, linkinjeon, sj1557.seo,
yuezhang.mo, almaz.alexandrovich, slava, glaubitz, frank.li,
tytso, adilger.kernel, cem, sfrench, pc, ronniesahlberg, sprasad,
trondmy, anna, jaegeuk, chao, hansg, senozhatsky, Chuck Lever
In-Reply-To: <20260122160311.1117669-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
Report FAT's case sensitivity behavior via the FS_XFLAG_CASEFOLD
and FS_XFLAG_CASENONPRESERVING flags. FAT filesystems are
case-insensitive by default.
MSDOS supports a 'nocase' mount option that enables case-sensitive
behavior; check this option when reporting case sensitivity.
VFAT long filename entries preserve case; without VFAT, only
uppercased 8.3 short names are stored. MSDOS with 'nocase' also
preserves case since the name-formatting code skips upcasing when
'nocase' is set. Check both options when reporting case preservation.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/fat/fat.h | 3 +++
fs/fat/file.c | 21 +++++++++++++++++++++
fs/fat/namei_msdos.c | 1 +
fs/fat/namei_vfat.c | 1 +
4 files changed, 26 insertions(+)
diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index d3e426de5f01..9e208eeb46c4 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -10,6 +10,8 @@
#include <linux/fs_context.h>
#include <linux/fs_parser.h>
+struct file_kattr;
+
/*
* vfat shortname flags
*/
@@ -407,6 +409,7 @@ extern void fat_truncate_blocks(struct inode *inode, loff_t offset);
extern int fat_getattr(struct mnt_idmap *idmap,
const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int flags);
+int fat_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
extern int fat_file_fsync(struct file *file, loff_t start, loff_t end,
int datasync);
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 4fc49a614fb8..f7f613cb763b 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -16,6 +16,7 @@
#include <linux/fsnotify.h>
#include <linux/security.h>
#include <linux/falloc.h>
+#include <linux/fileattr.h>
#include "fat.h"
static long fat_fallocate(struct file *file, int mode,
@@ -395,6 +396,25 @@ void fat_truncate_blocks(struct inode *inode, loff_t offset)
fat_flush_inodes(inode->i_sb, inode, NULL);
}
+int fat_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
+{
+ struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
+
+ /*
+ * FAT filesystems are case-insensitive by default. MSDOS
+ * supports a 'nocase' mount option for case-sensitive behavior.
+ *
+ * VFAT long filename entries preserve case. Without VFAT, only
+ * uppercased 8.3 short names are stored. MSDOS with 'nocase'
+ * also preserves case.
+ */
+ if (!sbi->options.nocase)
+ fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
+ if (!sbi->options.isvfat && !sbi->options.nocase)
+ fa->fsx_xflags |= FS_XFLAG_CASENONPRESERVING;
+ return 0;
+}
+
int fat_getattr(struct mnt_idmap *idmap, const struct path *path,
struct kstat *stat, u32 request_mask, unsigned int flags)
{
@@ -574,5 +594,6 @@ EXPORT_SYMBOL_GPL(fat_setattr);
const struct inode_operations fat_file_inode_operations = {
.setattr = fat_setattr,
.getattr = fat_getattr,
+ .fileattr_get = fat_fileattr_get,
.update_time = fat_update_time,
};
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
index 0b920ee40a7f..380add5c6c66 100644
--- a/fs/fat/namei_msdos.c
+++ b/fs/fat/namei_msdos.c
@@ -640,6 +640,7 @@ static const struct inode_operations msdos_dir_inode_operations = {
.rename = msdos_rename,
.setattr = fat_setattr,
.getattr = fat_getattr,
+ .fileattr_get = fat_fileattr_get,
.update_time = fat_update_time,
};
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index 5dbc4cbb8fce..6cf513f97afa 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -1180,6 +1180,7 @@ static const struct inode_operations vfat_dir_inode_operations = {
.rename = vfat_rename2,
.setattr = fat_setattr,
.getattr = fat_getattr,
+ .fileattr_get = fat_fileattr_get,
.update_time = fat_update_time,
};
--
2.52.0
^ permalink raw reply related
* [PATCH v7 01/16] fs: Add case sensitivity flags to file_kattr
From: Chuck Lever @ 2026-01-22 16:02 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Jan Kara
Cc: linux-fsdevel, linux-ext4, linux-xfs, linux-cifs, linux-nfs,
linux-api, linux-f2fs-devel, hirofumi, linkinjeon, sj1557.seo,
yuezhang.mo, almaz.alexandrovich, slava, glaubitz, frank.li,
tytso, adilger.kernel, cem, sfrench, pc, ronniesahlberg, sprasad,
trondmy, anna, jaegeuk, chao, hansg, senozhatsky, Chuck Lever
In-Reply-To: <20260122160311.1117669-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
Enable upper layers such as NFSD to retrieve case sensitivity
information from file systems by adding FS_XFLAG_CASEFOLD and
FS_XFLAG_CASENONPRESERVING flags.
Filesystems report case-insensitive or case-nonpreserving behavior
by setting these flags directly in fa->fsx_xflags. The default
(flags unset) indicates POSIX semantics: case-sensitive and
case-preserving. These flags are read-only; userspace cannot set
them via ioctl.
Remove struct file_kattr initialization from fileattr_fill_xflags()
and fileattr_fill_flags(). Callers at ioctl/syscall entry points
zero-initialize the struct themselves, which allows them to pass
hints (flags_valid, fsx_valid) to the filesystem's ->fileattr_get()
callback via the fa argument. Filesystem handlers that invoke these
fill functions can now set flags directly in fa->fsx_xflags before
calling them, without the fill functions zeroing those values.
Case sensitivity information is exported to userspace via the
fa_xflags field in the FS_IOC_FSGETXATTR ioctl and file_getattr()
system call.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/file_attr.c | 12 ++++--------
fs/xfs/xfs_ioctl.c | 2 +-
include/linux/fileattr.h | 3 ++-
include/uapi/linux/fs.h | 2 ++
4 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/fs/file_attr.c b/fs/file_attr.c
index 13cdb31a3e94..6e37040fc5fa 100644
--- a/fs/file_attr.c
+++ b/fs/file_attr.c
@@ -15,12 +15,10 @@
* @fa: fileattr pointer
* @xflags: FS_XFLAG_* flags
*
- * Set ->fsx_xflags, ->fsx_valid and ->flags (translated xflags). All
- * other fields are zeroed.
+ * Set ->fsx_xflags, ->fsx_valid and ->flags (translated xflags).
*/
void fileattr_fill_xflags(struct file_kattr *fa, u32 xflags)
{
- memset(fa, 0, sizeof(*fa));
fa->fsx_valid = true;
fa->fsx_xflags = xflags;
if (fa->fsx_xflags & FS_XFLAG_IMMUTABLE)
@@ -46,11 +44,9 @@ EXPORT_SYMBOL(fileattr_fill_xflags);
* @flags: FS_*_FL flags
*
* Set ->flags, ->flags_valid and ->fsx_xflags (translated flags).
- * All other fields are zeroed.
*/
void fileattr_fill_flags(struct file_kattr *fa, u32 flags)
{
- memset(fa, 0, sizeof(*fa));
fa->flags_valid = true;
fa->flags = flags;
if (fa->flags & FS_SYNC_FL)
@@ -323,7 +319,7 @@ int ioctl_setflags(struct file *file, unsigned int __user *argp)
{
struct mnt_idmap *idmap = file_mnt_idmap(file);
struct dentry *dentry = file->f_path.dentry;
- struct file_kattr fa;
+ struct file_kattr fa = {};
unsigned int flags;
int err;
@@ -355,7 +351,7 @@ int ioctl_fssetxattr(struct file *file, void __user *argp)
{
struct mnt_idmap *idmap = file_mnt_idmap(file);
struct dentry *dentry = file->f_path.dentry;
- struct file_kattr fa;
+ struct file_kattr fa = {};
int err;
err = copy_fsxattr_from_user(&fa, argp);
@@ -434,7 +430,7 @@ SYSCALL_DEFINE5(file_setattr, int, dfd, const char __user *, filename,
struct filename *name __free(putname) = NULL;
unsigned int lookup_flags = 0;
struct file_attr fattr;
- struct file_kattr fa;
+ struct file_kattr fa = {};
int error;
BUILD_BUG_ON(sizeof(struct file_attr) < FILE_ATTR_SIZE_VER0);
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 59eaad774371..f0417c4d1fca 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -496,7 +496,7 @@ xfs_ioc_fsgetxattra(
xfs_inode_t *ip,
void __user *arg)
{
- struct file_kattr fa;
+ struct file_kattr fa = {};
xfs_ilock(ip, XFS_ILOCK_SHARED);
xfs_fill_fsxattr(ip, XFS_ATTR_FORK, &fa);
diff --git a/include/linux/fileattr.h b/include/linux/fileattr.h
index f89dcfad3f8f..709de829659f 100644
--- a/include/linux/fileattr.h
+++ b/include/linux/fileattr.h
@@ -16,7 +16,8 @@
/* Read-only inode flags */
#define FS_XFLAG_RDONLY_MASK \
- (FS_XFLAG_PREALLOC | FS_XFLAG_HASATTR)
+ (FS_XFLAG_PREALLOC | FS_XFLAG_HASATTR | \
+ FS_XFLAG_CASEFOLD | FS_XFLAG_CASENONPRESERVING)
/* Flags to indicate valid value of fsx_ fields */
#define FS_XFLAG_VALUES_MASK \
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index 66ca526cf786..919148beaa8c 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -253,6 +253,8 @@ struct file_attr {
#define FS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */
#define FS_XFLAG_DAX 0x00008000 /* use DAX for IO */
#define FS_XFLAG_COWEXTSIZE 0x00010000 /* CoW extent size allocator hint */
+#define FS_XFLAG_CASEFOLD 0x00020000 /* case-insensitive lookups */
+#define FS_XFLAG_CASENONPRESERVING 0x00040000 /* case not preserved */
#define FS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
/* the read-only stuff doesn't really belong here, but any other place is
--
2.52.0
^ permalink raw reply related
* [PATCH v7 00/16] Exposing case folding behavior
From: Chuck Lever @ 2026-01-22 16:02 UTC (permalink / raw)
To: Al Viro, Christian Brauner, Jan Kara
Cc: linux-fsdevel, linux-ext4, linux-xfs, linux-cifs, linux-nfs,
linux-api, linux-f2fs-devel, hirofumi, linkinjeon, sj1557.seo,
yuezhang.mo, almaz.alexandrovich, slava, glaubitz, frank.li,
tytso, adilger.kernel, cem, sfrench, pc, ronniesahlberg, sprasad,
trondmy, anna, jaegeuk, chao, hansg, senozhatsky, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
Following on from
https://lore.kernel.org/linux-nfs/20251021-zypressen-bazillus-545a44af57fd@brauner/T/#m0ba197d75b7921d994cf284f3cef3a62abb11aaa
I'm attempting to implement enough support in the Linux VFS to
enable file services like NFSD and ksmbd (and user space
equivalents) to provide the actual status of case folding support
in local file systems. The default behavior for local file systems
not explicitly supported in this series is to reflect the usual
POSIX behaviors:
case-insensitive = false
case-nonpreserving = true
The case-insensitivity and case-nonpreserving booleans can be
consumed immediately by NFSD. These two attributes have been part of
the NFSv3 and NFSv4 protocols for decades, in order to support NFS
client implementations on non-POSIX systems.
Support for user space file servers is why this series exposes case
folding information via a user-space API. I don't know of any other
category of user-space application that requires access to case
folding info.
The Linux NFS community has a growing interest in supporting NFS
clients on Windows and MacOS platforms, where file name behavior does
not align with traditional POSIX semantics.
One example of a Windows-based NFS client is [1]. This client
implementation explicitly requires servers to report
FATTR4_WORD0_CASE_INSENSITIVE = TRUE for proper operation, a hard
requirement for Windows client interoperability because Windows
applications expect case-insensitive behavior. When an NFS client
knows the server is case-insensitive, it can avoid issuing multiple
LOOKUP/READDIR requests to search for case variants, and applications
like Win32 programs work correctly without manual workarounds or
code changes.
Even the Linux client can take advantage of this information. Trond
merged patches 4 years ago [2] that introduce support for case
insensitivity, in support of the Hammerspace NFS server. In
particular, when a client detects a case-insensitive NFS share,
negative dentry caching must be disabled (a lookup for "FILE.TXT"
failing shouldn't cache a negative entry when "file.txt" exists)
and directory change invalidation must clear all cached case-folded
file name variants.
Hammerspace servers and several other NFS server implementations
operate in multi-protocol environments, where a single file service
instance caters to both NFS and SMB clients. In those cases, things
work more smoothly for everyone when the NFS client can see and adapt
to the case folding behavior that SMB users rely on and expect. NFSD
needs to support the case-insensitivity and case-nonpreserving
booleans properly in order to participate as a first-class citizen
in such environments.
Series based on v6.19-rc6.
[1] https://github.com/kofemann/ms-nfs41-client
[2] https://patchwork.kernel.org/project/linux-nfs/cover/20211217203658.439352-1-trondmy@kernel.org/
---
Changes since v6:
- Remove the memset from vfs_fileattr_get
Changes since v5:
- Finish the conversion to FS_XFLAGs
- NFSv4 GETATTR now clears the attr mask bit if nfsd_get_case_info()
fails
Changes since v4:
- Observe the MSDOS "nocase" mount option
- Define new FS_XFLAGs for the user API
Changes since v3:
- Change fa->case_preserving to fa_case_nonpreserving
- VFAT is case preserving
- Make new fields available to user space
Changes since v2:
- Remove unicode labels
- Replace vfs_get_case_info
- Add support for several more local file system implementations
- Add support for in-kernel SMB server
Changes since RFC:
- Use file_getattr instead of statx
- Postpone exposing Unicode version until later
- Support NTFS and ext4 in addition to FAT
- Support NFSv4 fattr4 in addition to NFSv3 PATHCONF
Chuck Lever (16):
fs: Add case sensitivity flags to file_kattr
fat: Implement fileattr_get for case sensitivity
exfat: Implement fileattr_get for case sensitivity
ntfs3: Implement fileattr_get for case sensitivity
hfs: Implement fileattr_get for case sensitivity
hfsplus: Report case sensitivity in fileattr_get
ext4: Report case sensitivity in fileattr_get
xfs: Report case sensitivity in fileattr_get
cifs: Implement fileattr_get for case sensitivity
nfs: Implement fileattr_get for case sensitivity
f2fs: Add case sensitivity reporting to fileattr_get
vboxsf: Implement fileattr_get for case sensitivity
isofs: Implement fileattr_get for case sensitivity
nfsd: Report export case-folding via NFSv3 PATHCONF
nfsd: Implement NFSv4 FATTR4_CASE_INSENSITIVE and
FATTR4_CASE_PRESERVING
ksmbd: Report filesystem case sensitivity via FS_ATTRIBUTE_INFORMATION
fs/exfat/exfat_fs.h | 2 ++
fs/exfat/file.c | 16 ++++++++++++++--
fs/exfat/namei.c | 1 +
fs/ext4/ioctl.c | 7 +++++++
fs/f2fs/file.c | 7 +++++++
fs/fat/fat.h | 3 +++
fs/fat/file.c | 21 +++++++++++++++++++++
fs/fat/namei_msdos.c | 1 +
fs/fat/namei_vfat.c | 1 +
fs/file_attr.c | 12 ++++--------
fs/hfs/dir.c | 1 +
fs/hfs/hfs_fs.h | 2 ++
fs/hfs/inode.c | 13 +++++++++++++
fs/hfsplus/inode.c | 8 ++++++++
fs/isofs/dir.c | 15 +++++++++++++++
fs/nfs/client.c | 9 +++++++--
fs/nfs/inode.c | 20 ++++++++++++++++++++
fs/nfs/internal.h | 3 +++
fs/nfs/nfs3proc.c | 2 ++
fs/nfs/nfs3xdr.c | 7 +++++--
fs/nfs/nfs4proc.c | 2 ++
fs/nfs/proc.c | 3 +++
fs/nfs/symlink.c | 3 +++
fs/nfsd/nfs3proc.c | 18 ++++++++++--------
fs/nfsd/nfs4xdr.c | 31 +++++++++++++++++++++++++++----
fs/nfsd/vfs.c | 25 +++++++++++++++++++++++++
fs/nfsd/vfs.h | 2 ++
fs/ntfs3/file.c | 23 +++++++++++++++++++++++
fs/ntfs3/inode.c | 1 +
fs/ntfs3/namei.c | 2 ++
fs/ntfs3/ntfs_fs.h | 1 +
fs/smb/client/cifsfs.c | 20 ++++++++++++++++++++
fs/smb/server/smb2pdu.c | 25 +++++++++++++++++++------
fs/vboxsf/dir.c | 1 +
fs/vboxsf/file.c | 6 ++++--
fs/vboxsf/super.c | 4 ++++
fs/vboxsf/utils.c | 31 +++++++++++++++++++++++++++++++
fs/vboxsf/vfsmod.h | 6 ++++++
fs/xfs/xfs_ioctl.c | 9 ++++++++-
include/linux/fileattr.h | 3 ++-
include/linux/nfs_xdr.h | 2 ++
include/uapi/linux/fs.h | 2 ++
42 files changed, 335 insertions(+), 36 deletions(-)
--
2.52.0
^ permalink raw reply
* Re: [PATCH net-next v2 0/4] net: uapi: Provide an UAPI definition of 'struct sockaddr'
From: Jakub Kicinski @ 2026-01-22 3:27 UTC (permalink / raw)
To: Thomas Weißschuh
Cc: Eric Dumazet, Kuniyuki Iwashima, Paolo Abeni, Willem de Bruijn,
David S. Miller, Simon Horman, Shuah Khan, Matthieu Baerts,
Mat Martineau, Geliang Tang, Mickaël Salaün,
Günther Noack, Alexei Starovoitov, Daniel Borkmann,
Jesper Dangaard Brouer, John Fastabend, Stanislav Fomichev,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, KP Singh, Hao Luo, Jiri Olsa, netdev, linux-kernel,
linux-api, Arnd Bergmann, linux-kselftest, mptcp,
linux-security-module, bpf, libc-alpha, Carlos O'Donell,
Adhemerval Zanella, Rich Felker, klibc, Florian Weimer
In-Reply-To: <20260120-uapi-sockaddr-v2-0-63c319111cf6@linutronix.de>
On Tue, 20 Jan 2026 15:10:30 +0100 Thomas Weißschuh wrote:
> Various UAPI headers reference 'struct sockaddr'. Currently the
> definition of this struct is pulled in from the libc header
> sys/socket.h. This is problematic as it introduces a dependency
> on a full userspace toolchain.
>
> Add a definition of 'struct sockaddr' to the UAPI headers.
> Before that, reorder some problematic header inclusions in the selftests.
> include/linux/socket.h | 10 ----------
> include/uapi/linux/if.h | 4 ----
> include/uapi/linux/libc-compat.h | 12 ++++++++++++
> include/uapi/linux/socket.h | 14 ++++++++++++++
> samples/bpf/xdp_adjust_tail_user.c | 6 ++++--
> samples/bpf/xdp_fwd_user.c | 7 ++++---
> samples/bpf/xdp_router_ipv4_user.c | 6 +++---
> samples/bpf/xdp_sample_user.c | 15 ++++++++-------
> samples/bpf/xdp_tx_iptunnel_user.c | 4 ++--
> tools/testing/selftests/landlock/audit.h | 7 ++++---
> tools/testing/selftests/net/af_unix/diag_uid.c | 9 +++++----
> tools/testing/selftests/net/busy_poller.c | 3 ++-
> tools/testing/selftests/net/mptcp/mptcp_diag.c | 11 ++++++-----
> tools/testing/selftests/net/nettest.c | 4 ++--
> tools/testing/selftests/net/tcp_ao/icmps-discard.c | 6 +++---
> tools/testing/selftests/net/tcp_ao/lib/netlink.c | 9 +++++----
> tools/testing/selftests/net/tun.c | 5 +++--
> 17 files changed, 77 insertions(+), 55 deletions(-)
Are all those selftests / samples getting broken by this patch set?
I understand that we should avoid libc dependencies in uAPI but at
least speaking for networking - building selftests without libc is..
not a practical proposition?
^ permalink raw reply
* Re: [PATCH 0/2] mount: add OPEN_TREE_NAMESPACE
From: Rob Landley @ 2026-01-21 19:56 UTC (permalink / raw)
To: Jeff Layton, Andy Lutomirski, Askar Safin
Cc: amir73il, cyphar, jack, josef, linux-fsdevel, viro,
Lennart Poettering, David Howells, Zhang Yunkai, cgel.zte,
Menglong Dong, linux-kernel, initramfs, containers, linux-api,
news, lwn, Jonathan Corbet, emily, Christoph Hellwig
In-Reply-To: <acb859e1684122e1a73f30115f2389d2c9897251.camel@kernel.org>
>>>> You want rootfs to be a NULLFS instead of ramfs. You don't seem to want it to
>>>> actually _be_ a filesystem. Even with your "fix", containers could communicate
>>>> with each _other_ through it if it becomes accessible. If a container can get
>>>> access to an empty initramfs and write into it, it can ask/answer the question
>>>> "Are there any other containers on this machine running stux24" and then coordinate.
Or you could just make the ROOT= codepath remount the empty initramfs -o
ro like some switch_root implementations do. If the PID 1 you launch
isn't in initramfs, don't leave initramfs writeable. That seems unlikely
to break userspace.
(Having permissions to remount initramfs but _not_ having already
"cracked root" seems... a bit funky? You have waaaaay more faith in
security modules than I do...)
>> I think this new OPEN_TREE_NAMESPACE is nifty, but I don't think the
>> path that gives it sensible behavior should be conditional like this.
>> Either make it *always* mount on top of nullfs (regardless of boot
>> options) or find some way to have it actually be the root. I assume
>> the latter is challenging for some reason.
>
> I think that's the plan. I suggested the same to Christian last week,
> and he was amenable to removing the option and just always doing a
> nullfs_rootfs mount.
Since 2013, initramfs might be ramfs or tmpfs depending on
circumstances. Adding a third option for it be nullfs when there's no
cpio.gz extracted into it seems reasonable. (You can always mount a
tmpfs _over_ it if you need that later, it's writeable so a PID 1
launched in it has workspace.)
That said, if you are changing the semantics, right now we switch_root
from initramfs instead of pivot_root because initramfs couldn't be
unmounted. With this change would pivot_root become the mechanism for
initramfs too? (If the cpio.gz recipient wasn't actually rootfs but was
an overmount the way ROOT= does it.)
Aside: it would be nice if inaccessible mount points could automatically
be garbage collected. There's already some "lazy umount" plumbing that
does that when explicitly requested to, but last I checked there were
cases that didn't get caught. It's been a while though, might already
have been fixed. Presumably initramfs would always get pinned because
it's PID 0's / reference...
Also, could you guys make CONFIG_DEVTMPFS_MOUNT work with initramfs?
I've posted patches for that on and off since 2017, most recent one's
probably
https://landley.net/bin/mkroot/0.8.13/linux-patches/0003-Wire-up-CONFIG_DEVTMPFS_MOUNT-to-initramfs.patch
(tested on a 6.17 kernel).
> We think that older runtimes should still "just work" with this scheme.
> Out of an abundance of caution, we _might_ want a command-line option
> to make it go back to old way, in case we find some userland stuff that
> doesn't like this for some reason, but hopefully we won't even need
> that.
I assume it will break stuff, but I also assume the systems it breaks
will never upgrade to a 7.x kernel because the kernel itself would
consume all available memory before launching PID 1.
Rob
^ permalink raw reply
* Re: [PATCH 0/2] mount: add OPEN_TREE_NAMESPACE
From: Andy Lutomirski @ 2026-01-21 18:00 UTC (permalink / raw)
To: Jeff Layton
Cc: Askar Safin, brauner, amir73il, cyphar, jack, josef,
linux-fsdevel, viro, Lennart Poettering, David Howells,
Yunkai Zhang, cgel.zte, Menglong Dong, linux-kernel, initramfs,
containers, linux-api, news, lwn, Jonathan Corbet, Rob Landley,
emily, Christoph Hellwig
In-Reply-To: <acb859e1684122e1a73f30115f2389d2c9897251.camel@kernel.org>
> On Jan 19, 2026, at 2:21 PM, Jeff Layton <jlayton@kernel.org> wrote:
>
> On Mon, 2026-01-19 at 11:05 -0800, Andy Lutomirski wrote:
>>> On Mon, Jan 19, 2026 at 10:56 AM Askar Safin <safinaskar@gmail.com> wrote:
>>>
>>> Christian Brauner <brauner@kernel.org>:
>>>> Extend open_tree() with a new OPEN_TREE_NAMESPACE flag. Similar to
>>>> OPEN_TREE_CLONE only the indicated mount tree is copied. Instead of
>>>> returning a file descriptor referring to that mount tree
>>>> OPEN_TREE_NAMESPACE will cause open_tree() to return a file descriptor
>>>> to a new mount namespace. In that new mount namespace the copied mount
>>>> tree has been mounted on top of a copy of the real rootfs.
>>>
>>> I want to point at security benefits of this.
>>>
>>> [[ TL;DR: [1] and [2] are very big changes to how mount namespaces work.
>>> I like them, and I think they should get wider exposure. ]]
>>>
>>> If this patchset ([1]) and [2] both land (they are both in "next" now and
>>> likely will be submitted to mainline soon) and "nullfs_rootfs" is passed on
>>> command line, then mount namespace created by open_tree(OPEN_TREE_NAMESPACE) will
>>> usually contain exactly 2 mounts: nullfs and whatever was passed to
>>> open_tree(OPEN_TREE_NAMESPACE).
>>>
>>> This means that even if attacker somehow is able to unmount its root and
>>> get access to underlying mounts, then the only underlying thing they will
>>> get is nullfs.
>>>
>>> Also this means that other mounts are not only hidden in new namespace, they
>>> are fully absent. This prevents attacks discussed here: [3], [4].
>>>
>>> Also this means that (assuming we have both [1] and [2] and "nullfs_rootfs"
>>> is passed), there is no anymore hidden writable mount shared by all containers,
>>> potentially available to attackers. This is concern raised in [5]:
>>>
>>>> You want rootfs to be a NULLFS instead of ramfs. You don't seem to want it to
>>>> actually _be_ a filesystem. Even with your "fix", containers could communicate
>>>> with each _other_ through it if it becomes accessible. If a container can get
>>>> access to an empty initramfs and write into it, it can ask/answer the question
>>>> "Are there any other containers on this machine running stux24" and then coordinate.
>>
>> I think this new OPEN_TREE_NAMESPACE is nifty, but I don't think the
>> path that gives it sensible behavior should be conditional like this.
>> Either make it *always* mount on top of nullfs (regardless of boot
>> options) or find some way to have it actually be the root. I assume
>> the latter is challenging for some reason.
>>
>
> I think that's the plan. I suggested the same to Christian last week,
> and he was amenable to removing the option and just always doing a
> nullfs_rootfs mount.
>
> We think that older runtimes should still "just work" with this scheme.
> Out of an abundance of caution, we _might_ want a command-line option
> to make it go back to old way, in case we find some userland stuff that
> doesn't like this for some reason, but hopefully we won't even need
> that.
What I mean is: even if for some reason the kernel is running in a
mode where the *initial* rootfs is a real fs, I think it would be nice
for OPEN_TREE_NAMESPACE to use nullfs.
^ permalink raw reply
* Re: [PATCH 0/2] mount: add OPEN_TREE_NAMESPACE
From: Christian Brauner @ 2026-01-21 10:20 UTC (permalink / raw)
To: Jeff Layton
Cc: Andy Lutomirski, Askar Safin, amir73il, cyphar, jack, josef,
linux-fsdevel, viro, Lennart Poettering, David Howells,
Zhang Yunkai, cgel.zte, Menglong Dong, linux-kernel, initramfs,
containers, linux-api, news, lwn, Jonathan Corbet, Rob Landley,
emily, Christoph Hellwig
In-Reply-To: <acb859e1684122e1a73f30115f2389d2c9897251.camel@kernel.org>
On Mon, Jan 19, 2026 at 05:21:30PM -0500, Jeff Layton wrote:
> On Mon, 2026-01-19 at 11:05 -0800, Andy Lutomirski wrote:
> > On Mon, Jan 19, 2026 at 10:56 AM Askar Safin <safinaskar@gmail.com> wrote:
> > >
> > > Christian Brauner <brauner@kernel.org>:
> > > > Extend open_tree() with a new OPEN_TREE_NAMESPACE flag. Similar to
> > > > OPEN_TREE_CLONE only the indicated mount tree is copied. Instead of
> > > > returning a file descriptor referring to that mount tree
> > > > OPEN_TREE_NAMESPACE will cause open_tree() to return a file descriptor
> > > > to a new mount namespace. In that new mount namespace the copied mount
> > > > tree has been mounted on top of a copy of the real rootfs.
> > >
> > > I want to point at security benefits of this.
> > >
> > > [[ TL;DR: [1] and [2] are very big changes to how mount namespaces work.
> > > I like them, and I think they should get wider exposure. ]]
> > >
> > > If this patchset ([1]) and [2] both land (they are both in "next" now and
> > > likely will be submitted to mainline soon) and "nullfs_rootfs" is passed on
> > > command line, then mount namespace created by open_tree(OPEN_TREE_NAMESPACE) will
> > > usually contain exactly 2 mounts: nullfs and whatever was passed to
> > > open_tree(OPEN_TREE_NAMESPACE).
> > >
> > > This means that even if attacker somehow is able to unmount its root and
> > > get access to underlying mounts, then the only underlying thing they will
> > > get is nullfs.
> > >
> > > Also this means that other mounts are not only hidden in new namespace, they
> > > are fully absent. This prevents attacks discussed here: [3], [4].
> > >
> > > Also this means that (assuming we have both [1] and [2] and "nullfs_rootfs"
> > > is passed), there is no anymore hidden writable mount shared by all containers,
> > > potentially available to attackers. This is concern raised in [5]:
> > >
> > > > You want rootfs to be a NULLFS instead of ramfs. You don't seem to want it to
> > > > actually _be_ a filesystem. Even with your "fix", containers could communicate
> > > > with each _other_ through it if it becomes accessible. If a container can get
> > > > access to an empty initramfs and write into it, it can ask/answer the question
> > > > "Are there any other containers on this machine running stux24" and then coordinate.
> >
> > I think this new OPEN_TREE_NAMESPACE is nifty, but I don't think the
> > path that gives it sensible behavior should be conditional like this.
> > Either make it *always* mount on top of nullfs (regardless of boot
> > options) or find some way to have it actually be the root. I assume
> > the latter is challenging for some reason.
> >
>
> I think that's the plan. I suggested the same to Christian last week,
> and he was amenable to removing the option and just always doing a
> nullfs_rootfs mount.
Whether or not the underlying mount is nullfs or not is irrelevant. If
it's not nullfs but a regular tmpfs it works just as well. If it has any
locked overmounts the new rootfs will become locked as well similarly if
it'll be owned by a new userns.
^ permalink raw reply
* Re: [klibc] [PATCH net-next] net: uapi: Provide an UAPI definition of 'struct sockaddr'
From: H. Peter Anvin @ 2026-01-20 23:20 UTC (permalink / raw)
To: Arnd Bergmann, Thomas Weißschuh, Eric Dumazet,
Kuniyuki Iwashima, Paolo Abeni, Willem de Bruijn, Xi Ruoyao,
Carlos O'Donell, Adhemerval Zanella Netto, Rich Felker
Cc: Netdev, linux-kernel, linux-api, klibc
In-Reply-To: <212d2e51-abc1-47bb-8666-755917cad889@app.fastmail.com>
On 2026-01-20 14:31, Arnd Bergmann wrote:
>>
> I must have accidentally cut that from my reply, sorry.
> Looking at it again now, I think I ran into problems with the
> flexible array that was removed from the in-kernel sockaddr
> structure in commit 2b5e9f9b7e41 ("net: Convert struct sockaddr
> to fixed-size "sa_data[14]""), so there is a good chance it works
> now with the (once more) fixed-size version.
>
> The other problem is that the structures that embed 'sockaddr'
> are used a lot inside of the kernel, in particular in 'ifreq',
> so changing the uapi sockaddr to __kernel_sockaddr requires
> additional changes wherever the struct members are passed
> by reference.
>
Well, the kernel should do what opting-in libcs do:
#define sockaddr __kernel_sockaddr
or
struct sockaddr { struct __kernel_sockaddr; };
... now when we have ms extensions turned on. Unfortunately gcc/clang don't
support them without the option even with __extension__, so user space is
limited to using macros.
-hpa
^ permalink raw reply
* Re: [PATCH v6 01/16] fs: Add case sensitivity flags to file_kattr
From: Darrick J. Wong @ 2026-01-20 22:58 UTC (permalink / raw)
To: Chuck Lever
Cc: Christian Brauner, Alexander Viro, Jan Kara, linux-fsdevel,
linux-ext4, linux-xfs, linux-cifs, linux-nfs, linux-f2fs-devel,
OGAWA Hirofumi, Namjae Jeon, Sungjong Seo, Yuezhang Mo,
almaz.alexandrovich, Viacheslav Dubeyko, glaubitz, frank.li,
Theodore Tso, adilger.kernel, Carlos Maiolino, Steve French,
Paulo Alcantara, Ronnie Sahlberg, Shyam Prasad N, Trond Myklebust,
Anna Schumaker, Jaegeuk Kim, Chao Yu, Hans de Goede, senozhatsky,
Chuck Lever, linux-api
In-Reply-To: <38bf1452-8cf8-477b-bcc3-9fe442033bc5@app.fastmail.com>
[uapi change, so add linux-api]
On Tue, Jan 20, 2026 at 04:48:31PM -0500, Chuck Lever wrote:
>
>
> On Tue, Jan 20, 2026, at 12:26 PM, Darrick J. Wong wrote:
> > On Tue, Jan 20, 2026 at 09:24:24AM -0500, Chuck Lever wrote:
> >> From: Chuck Lever <chuck.lever@oracle.com>
> >>
> >> Enable upper layers such as NFSD to retrieve case sensitivity
> >> information from file systems by adding FS_XFLAG_CASEFOLD and
> >> FS_XFLAG_CASENONPRESERVING flags.
> >>
> >> Filesystems report case-insensitive or case-nonpreserving behavior
> >> by setting these flags directly in fa->fsx_xflags. The default
> >> (flags unset) indicates POSIX semantics: case-sensitive and
> >> case-preserving. These flags are read-only; userspace cannot set
> >> them via ioctl.
> >>
> >> Relocate struct file_kattr initialization from fileattr_fill_xflags()
> >> and fileattr_fill_flags() to vfs_fileattr_get() and the ioctl/syscall
> >> call sites. This allows filesystem ->fileattr_get() callbacks to set
> >> flags directly in fa->fsx_xflags before invoking the fill functions,
> >> which previously would have zeroed those values. Callers that bypass
> >> vfs_fileattr_get() must now zero-initialize the struct themselves.
> >>
> >> Case sensitivity information is exported to userspace via the
> >> fa_xflags field in the FS_IOC_FSGETXATTR ioctl and file_getattr()
> >> system call.
> >>
> >> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> >> ---
> >> fs/file_attr.c | 14 ++++++--------
> >> fs/xfs/xfs_ioctl.c | 2 +-
> >> include/linux/fileattr.h | 3 ++-
> >> include/uapi/linux/fs.h | 2 ++
> >
> > This ought to go to linux-api because you're changing the userspace api.
> > Granted it's only adding a flag definition to an existing ioctl, but
> > FS_XFLAG_CASEFOLD /does/ collide with Andrey's fsverity xflag patch...
> >
> > (The rest of the changes looks ok to me.)
>
> Process question for Christian: Do you want to see a v7 of this
> series with Cc: linux-api before proceeding, or are you taking
> both Andrey's and mine and can resolve the conflict, or ... ?
Well now that I've griped at both patchsets on the same public list,
I'll at least chime in that I'd be satisfied if whoever decides to merge
them to fix up the conflicts whenever they merge them. :)
--D
>
> > --D
> >
> >> 4 files changed, 11 insertions(+), 10 deletions(-)
> >>
> >> diff --git a/fs/file_attr.c b/fs/file_attr.c
> >> index 13cdb31a3e94..2700200c5b9c 100644
> >> --- a/fs/file_attr.c
> >> +++ b/fs/file_attr.c
> >> @@ -15,12 +15,10 @@
> >> * @fa: fileattr pointer
> >> * @xflags: FS_XFLAG_* flags
> >> *
> >> - * Set ->fsx_xflags, ->fsx_valid and ->flags (translated xflags). All
> >> - * other fields are zeroed.
> >> + * Set ->fsx_xflags, ->fsx_valid and ->flags (translated xflags).
> >> */
> >> void fileattr_fill_xflags(struct file_kattr *fa, u32 xflags)
> >> {
> >> - memset(fa, 0, sizeof(*fa));
> >> fa->fsx_valid = true;
> >> fa->fsx_xflags = xflags;
> >> if (fa->fsx_xflags & FS_XFLAG_IMMUTABLE)
> >> @@ -46,11 +44,9 @@ EXPORT_SYMBOL(fileattr_fill_xflags);
> >> * @flags: FS_*_FL flags
> >> *
> >> * Set ->flags, ->flags_valid and ->fsx_xflags (translated flags).
> >> - * All other fields are zeroed.
> >> */
> >> void fileattr_fill_flags(struct file_kattr *fa, u32 flags)
> >> {
> >> - memset(fa, 0, sizeof(*fa));
> >> fa->flags_valid = true;
> >> fa->flags = flags;
> >> if (fa->flags & FS_SYNC_FL)
> >> @@ -84,6 +80,8 @@ int vfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
> >> struct inode *inode = d_inode(dentry);
> >> int error;
> >>
> >> + memset(fa, 0, sizeof(*fa));
> >> +
> >> if (!inode->i_op->fileattr_get)
> >> return -ENOIOCTLCMD;
> >>
> >> @@ -323,7 +321,7 @@ int ioctl_setflags(struct file *file, unsigned int __user *argp)
> >> {
> >> struct mnt_idmap *idmap = file_mnt_idmap(file);
> >> struct dentry *dentry = file->f_path.dentry;
> >> - struct file_kattr fa;
> >> + struct file_kattr fa = {};
> >> unsigned int flags;
> >> int err;
> >>
> >> @@ -355,7 +353,7 @@ int ioctl_fssetxattr(struct file *file, void __user *argp)
> >> {
> >> struct mnt_idmap *idmap = file_mnt_idmap(file);
> >> struct dentry *dentry = file->f_path.dentry;
> >> - struct file_kattr fa;
> >> + struct file_kattr fa = {};
> >> int err;
> >>
> >> err = copy_fsxattr_from_user(&fa, argp);
> >> @@ -434,7 +432,7 @@ SYSCALL_DEFINE5(file_setattr, int, dfd, const char __user *, filename,
> >> struct filename *name __free(putname) = NULL;
> >> unsigned int lookup_flags = 0;
> >> struct file_attr fattr;
> >> - struct file_kattr fa;
> >> + struct file_kattr fa = {};
> >> int error;
> >>
> >> BUILD_BUG_ON(sizeof(struct file_attr) < FILE_ATTR_SIZE_VER0);
> >> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> >> index 59eaad774371..f0417c4d1fca 100644
> >> --- a/fs/xfs/xfs_ioctl.c
> >> +++ b/fs/xfs/xfs_ioctl.c
> >> @@ -496,7 +496,7 @@ xfs_ioc_fsgetxattra(
> >> xfs_inode_t *ip,
> >> void __user *arg)
> >> {
> >> - struct file_kattr fa;
> >> + struct file_kattr fa = {};
> >>
> >> xfs_ilock(ip, XFS_ILOCK_SHARED);
> >> xfs_fill_fsxattr(ip, XFS_ATTR_FORK, &fa);
> >> diff --git a/include/linux/fileattr.h b/include/linux/fileattr.h
> >> index f89dcfad3f8f..709de829659f 100644
> >> --- a/include/linux/fileattr.h
> >> +++ b/include/linux/fileattr.h
> >> @@ -16,7 +16,8 @@
> >>
> >> /* Read-only inode flags */
> >> #define FS_XFLAG_RDONLY_MASK \
> >> - (FS_XFLAG_PREALLOC | FS_XFLAG_HASATTR)
> >> + (FS_XFLAG_PREALLOC | FS_XFLAG_HASATTR | \
> >> + FS_XFLAG_CASEFOLD | FS_XFLAG_CASENONPRESERVING)
> >>
> >> /* Flags to indicate valid value of fsx_ fields */
> >> #define FS_XFLAG_VALUES_MASK \
> >> diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
> >> index 66ca526cf786..919148beaa8c 100644
> >> --- a/include/uapi/linux/fs.h
> >> +++ b/include/uapi/linux/fs.h
> >> @@ -253,6 +253,8 @@ struct file_attr {
> >> #define FS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */
> >> #define FS_XFLAG_DAX 0x00008000 /* use DAX for IO */
> >> #define FS_XFLAG_COWEXTSIZE 0x00010000 /* CoW extent size allocator hint */
> >> +#define FS_XFLAG_CASEFOLD 0x00020000 /* case-insensitive lookups */
> >> +#define FS_XFLAG_CASENONPRESERVING 0x00040000 /* case not preserved */
> >> #define FS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
> >>
> >> /* the read-only stuff doesn't really belong here, but any other place is
> >> --
> >> 2.52.0
> >>
> >>
>
> --
> Chuck Lever
>
^ permalink raw reply
* Re: [klibc] [PATCH net-next] net: uapi: Provide an UAPI definition of 'struct sockaddr'
From: Arnd Bergmann @ 2026-01-20 22:31 UTC (permalink / raw)
To: H. Peter Anvin, Thomas Weißschuh, Eric Dumazet,
Kuniyuki Iwashima, Paolo Abeni, Willem de Bruijn, Xi Ruoyao,
Carlos O'Donell, Adhemerval Zanella Netto, Rich Felker
Cc: Netdev, linux-kernel, linux-api, klibc
In-Reply-To: <0fc5b4ef-c468-416f-a065-f64989d75378@zytor.com>
On Tue, Jan 20, 2026, at 19:50, H. Peter Anvin wrote:
> On 2026-01-05 05:50, Arnd Bergmann wrote:
>>
>> This looks like the right approach to me. I have previously
>> tried to introduce a 'struct __kernel_sockaddr' structure and
>> use that in uapi headers in place of the libc sockaddr, but
>> that seemed worse in the end, and introduce the same problems
>> as using the existing __kernel_sockaddr_storage.
>>
>
> You say "the same problems". It's not clear to me what that means.
I must have accidentally cut that from my reply, sorry.
Looking at it again now, I think I ran into problems with the
flexible array that was removed from the in-kernel sockaddr
structure in commit 2b5e9f9b7e41 ("net: Convert struct sockaddr
to fixed-size "sa_data[14]""), so there is a good chance it works
now with the (once more) fixed-size version.
The other problem is that the structures that embed 'sockaddr'
are used a lot inside of the kernel, in particular in 'ifreq',
so changing the uapi sockaddr to __kernel_sockaddr requires
additional changes wherever the struct members are passed
by reference.
> Based on my own libc experience, hacking both a minimal (klibc) and a
> maximal (glibc) libc, there are a *lot* of advantages to having
> __kernel_* definitions available, *regardless* of if they are exported
> into the libc namespace at all.
Absolutely, I am totally in agreement about this in general, which
is why I tried this approach first.
Arnd
^ permalink raw reply
* Re: [PATCH net-next v2 2/4] selftests/landlock: Move some UAPI header inclusions after libc ones
From: Mickaël Salaün @ 2026-01-20 21:46 UTC (permalink / raw)
To: Thomas Weißschuh
Cc: Eric Dumazet, Kuniyuki Iwashima, Paolo Abeni, Willem de Bruijn,
David S. Miller, Jakub Kicinski, Simon Horman, Shuah Khan,
Matthieu Baerts, Mat Martineau, Geliang Tang, Günther Noack,
Alexei Starovoitov, Daniel Borkmann, Jesper Dangaard Brouer,
John Fastabend, Stanislav Fomichev, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
KP Singh, Hao Luo, Jiri Olsa, netdev, linux-kernel, linux-api,
Arnd Bergmann, linux-kselftest, mptcp, linux-security-module, bpf,
libc-alpha, Carlos O'Donell, Adhemerval Zanella, Rich Felker,
klibc, Florian Weimer
In-Reply-To: <20260120-uapi-sockaddr-v2-2-63c319111cf6@linutronix.de>
On Tue, Jan 20, 2026 at 03:10:32PM +0100, Thomas Weißschuh wrote:
> Interleaving inclusions of UAPI headers and libc headers is problematic.
> Both sets of headers define conflicting symbols. To enable their
> coexistence a compatibility-mechanism is in place.
>
> An upcoming change will define 'struct sockaddr' from linux/socket.h.
> However sys/socket.h from libc does not yet handle this case and a
> symbol conflict will arise.
>
> Move the inclusion of all UAPI headers after the inclusion of the glibc
> ones, so the compatibility mechanism from the UAPI headers is used.
>
> Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Reviewed-by: Mickaël Salaün <mic@digikod.net>
Thanks!
> ---
> tools/testing/selftests/landlock/audit.h | 7 ++++---
> 1 file changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/tools/testing/selftests/landlock/audit.h b/tools/testing/selftests/landlock/audit.h
> index 44eb433e9666..c12b16c690dc 100644
> --- a/tools/testing/selftests/landlock/audit.h
> +++ b/tools/testing/selftests/landlock/audit.h
> @@ -7,9 +7,6 @@
>
> #define _GNU_SOURCE
> #include <errno.h>
> -#include <linux/audit.h>
> -#include <linux/limits.h>
> -#include <linux/netlink.h>
> #include <regex.h>
> #include <stdbool.h>
> #include <stdint.h>
> @@ -20,6 +17,10 @@
> #include <sys/time.h>
> #include <unistd.h>
>
> +#include <linux/audit.h>
> +#include <linux/limits.h>
> +#include <linux/netlink.h>
> +
> #include "kselftest.h"
>
> #ifndef ARRAY_SIZE
>
> --
> 2.52.0
>
>
^ permalink raw reply
* Re: [RFC v1] man/man2/close.2: CAVEATS: Document divergence from POSIX.1-2024
From: Alejandro Colomar @ 2026-01-20 20:42 UTC (permalink / raw)
To: Rich Felker
Cc: Zack Weinberg, Vincent Lefevre, Jan Kara, Alexander Viro,
Christian Brauner, linux-fsdevel, linux-api, GNU libc development
In-Reply-To: <aW_jz7nucPBjhu0C@devuan>
[-- Attachment #1: Type: text/plain, Size: 9759 bytes --]
On Tue, Jan 20, 2026 at 09:35:43PM +0100, Alejandro Colomar wrote:
> Hi Rich, Zack,
>
> On Tue, Jan 20, 2026 at 12:46:59PM -0500, Rich Felker wrote:
> > On Tue, Jan 20, 2026 at 12:05:52PM -0500, Zack Weinberg wrote:
> > > > On Fri, May 23, 2025 at 02:10:57PM -0400, Zack Weinberg wrote:
>
> [...]
>
> > > Now, the abstract correct behavior is secondary to the fact that we
> > > know there are both systems where close should not be retried after
> > > EINTR (Linux) and systems where the fd is still open after EINTR
> > > (HP-UX). But it is my position that *portable code* should assume the
> > > Linux behavior, because that is the safest option. If you assume the
> > > HP-UX behavior on a machine that implements the Linux behavior, you
> > > might close some unrelated file out from under yourself (probably but
> > > not necessarily a different thread). If you assume the Linux behavior
> > > on a machine that implements the HP-UX behavior, you have leaked a
> > > file descriptor; the worst things that can do are much less severe.
> >
> > Unfortunately, regardless of what happens, code portable to old
> > systems needs to avoid getting in the situation to begin with. By
> > either not installing interrupting signal handlers or blocking EINTR
> > around close.
>
> [...]
>
> > > > While I agree with all of this, I think the tone is way too
> > > > proscriptive. The man pages are to document the behaviors, not tell
> > > > people how to program.
> > >
> > > I could be persuaded to tone it down a little but in this case I think
> > > the man page's job *is* to tell people how to program. We know lots of
> > > existing code has gotten the fine details of close() wrong and we are
> > > trying to document how to do it right.
> >
> > No, the job of the man pages absolutely is not "to tell people how to
> > program". It's to document behaviors. They are not a programming
> > tutorial. They are not polemic diatribes. They are unbiased statements
> > of facts. Facts of what the standards say and what implementations do,
> > that equip programmers with the knowledge they need to make their own
> > informed decisions, rather than blindly following what someone who
> > thinks they know better told them to do.
>
> This reminds me a little bit of the realloc(p,0) fiasco of C89 and
> glibc.
>
> In most cases, I agree with you that manual pages are and should be
> aseptic, there are cases where I think the manual page needs to be
> tutorial. Especially when there's such a mess, we need to both explain
> all the possible behaviors (or at least mention them to some degree).
... and guide programmers about how to best use the API.
I forgot to finish the sentence.
>
> But for example, there's the case of realloc(p,0), where we have
> a fiasco that was pushed by a compoundment of wrong decisions by the
> C Committee, and prior to that from System V. We're a bit lucky that
> C17 accidentally broke it so badly that we now have it as UB, and that
> gives us the opportunity to fix it now (which BTW might also be the case
> for close(2)).
>
> In the case of realloc(3), I went and documented in the manual page that
> glibc is broken, and that ISO C is also broken.
>
> STANDARDS
> malloc()
> free()
> calloc()
> realloc()
> C23, POSIX.1‐2024.
>
> reallocarray()
> POSIX.1‐2024.
>
> realloc(p, 0)
> The behavior of realloc(p, 0) in glibc doesn’t conform to
> any of C99, C11, POSIX.1‐2001, POSIX.1‐2004, POSIX.1‐2008,
> POSIX.1‐2013, POSIX.1‐2017, or POSIX.1‐2024. The C17
> specification was changed to make it conforming, but that
> specification made it impossible to write code that reli‐
> ably determines if the input pointer is freed after real‐
> loc(p, 0), and C23 changed it again to make this undefined
> behavior, acknowledging that the C17 specification was
> broad enough, so that undefined behavior wasn’t worse than
> that.
>
> reallocarray() suffers the same issues in glibc.
>
> musl libc and the BSDs conform to all versions of ISO C
> and POSIX.1.
>
> gnulib provides the realloc‐posix module, which provides
> wrappers realloc() and reallocarray() that conform to all
> versions of ISO C and POSIX.1.
>
> There’s a proposal to standardize the BSD behavior: https:
> //www.open-std.org/jtc1/sc22/wg14/www/docs/n3621.txt.
>
> HISTORY
> malloc()
> free()
> calloc()
> realloc()
> POSIX.1‐2001, C89.
>
> reallocarray()
> glibc 2.26. OpenBSD 5.6, FreeBSD 11.0.
>
> malloc() and related functions rejected sizes greater than
> PTRDIFF_MAX starting in glibc 2.30.
>
> free() preserved errno starting in glibc 2.33.
>
> realloc(p, 0)
> C89 was ambiguous in its specification of realloc(p, 0).
> C99 partially fixed this.
>
> The original implementation in glibc would have been con‐
> forming to C99. However, and ironically, trying to comply
> with C99 before the standard was released, glibc changed
> its behavior in glibc 2.1.1 into something that ended up
> not conforming to the final C99 specification (but this is
> debated, as the wording of the standard seems self‐contra‐
> dicting).
>
> ...
>
> BUGS
> Programmers would naturally expect by induction that
> realloc(p, size) is consistent with free(p) and mal‐
> loc(size), as that is the behavior in the general case.
> This is not explicitly required by POSIX.1‐2024 or C11,
> but all conforming implementations are consistent with
> that.
>
> The glibc implementation of realloc() is not consistent
> with that, and as a consequence, it is dangerous to call
> realloc(p, 0) in glibc.
>
> A trivial workaround for glibc is calling it as
> realloc(p, size?size:1).
>
> The workaround for reallocarray() in glibc ——which shares
> the same bug—— would be
> reallocarray(p, n?n:1, size?size:1).
>
>
> Apart from documenting that glibc and ISO C are broken, we document how
> to best deal with it (see the last paragraph in BUGS). This is
> necessary because I fear that just by documenting the different
> behaviors, programmers would still not know what to do with that.
> Just take into account that even several members of the committee don't
> know how to deal with it.
>
> I'd be willing to have something similar for close(2).
>
>
> Have a lovely night!
> Alex
>
> P.S.: I have great news about realloc(p,0)! Microsoft is on-board with
> the change. They told me they like the proposal, and are willing to
> fix their realloc(3) implementation. They'll now conduct tests to make
> sure it doesn't break anything too badly, and will come back to me with
> any feedback they have from those tests.
>
> I'll put the standards proposal for realloc(3) on hold, waiting for
> Microsoft's feedback.
>
> > > > Aside: the reason EINTR *has to* be specified this way is that pthread
> > > > cancellation is aligned with EINTR. If EINTR were defined to have
> > > > closed the fd, then acting on cancellation during close would also
> > > > have closed the fd, but the cancellation handler would have no way to
> > > > distinguish this, leading to a situation where you're forced to either
> > > > leak fds or introduce a double-close vuln.
> > >
> > > The correct way to address this would be to make close() not be a
> > > cancellation point.
> >
> > This would also be a desirable change, one I would support if other
> > implementors are on-board with pushing for it.
> >
> > > > An outline of what I'd like to see instead:
> > > >
> > > > - Clear explanation of why double-close is a serious bug that must
> > > > always be avoided. (I think we all agree on this.)
> > > >
> > > > - Statement that the historical Linux/glibc behavior and current POSIX
> > > > requirement differ, without language that tries to paint the POSIX
> > > > behavior as a HP-UX bug/quirk. Possibly citing real sources/history
> > > > of the issue (Austin Group tracker items 529, 614; maybe others).
> > > >
> > > > - Consequence of just assuming the Linux behavior (fd leaks on
> > > > conforming systems).
> > > >
> > > > - Consequences of assuming the POSIX behavior (double-close vulns on
> > > > GNU/Linux, maybe others).
> > > >
> > > > - Survey of methods for avoiding the problem (ways to preclude EINTR,
> > > > possibly ways to infer behavior, etc).
> > >
> > > This outline seems more or less reasonable to me but, if it's me
> > > writing the text, I _will_ characterize what POSIX currently says
> > > about EINTR returns from close() as a bug in POSIX. As far as I'm
> > > concerned, that is a fact, not polemic.
> > >
> > > I have found that arguing with you in particular, Rich, is generally
> > > not worth the effort. Therefore, unless you reply and _accept_ that
> > > the final version of the close manpage will say that POSIX is buggy,
> > > I am not going to write another version of this text, nor will I be
> > > drawn into further debate.
> >
> > I will not accept that because it's a gross violation of the
> > responsibility of document writing.
> >
> > Rich
>
> --
> <https://www.alejandro-colomar.es>
--
<https://www.alejandro-colomar.es>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox