Exposing case folding behavior
Subsystems (15)
Chuck Lever
maintainerv3 cover Exposing case folding behavior
From: Chuck Lever <[email protected]>
Following on from
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-preserving = true
The case-insensitivity and case-preserving booleans can be consumed immediately by NFSD. These two booleans have been part of the NFSv3 and NFSv4 protocols for decades, in order to support NFS clients 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-preserving booleans properly in order to participate as a first-class citizen in such environments.
Series based on v6.19-rc5.
[1] https://github.com/kofemann/ms-nfs41-client
[2] https://patchwork.kernel.org/project/linux-nfs/cover/[email protected]/
---
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 info 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 | 17 +++++++++++++++-- fs/exfat/namei.c | 1 + fs/ext4/ioctl.c | 8 ++++++++ fs/f2fs/file.c | 8 ++++++++ fs/fat/fat.h | 3 +++ fs/fat/file.c | 18 ++++++++++++++++++ fs/fat/namei_msdos.c | 1 + fs/fat/namei_vfat.c | 1 + fs/file_attr.c | 10 ++++++++++ fs/hfs/dir.c | 1 + fs/hfs/hfs_fs.h | 2 ++ fs/hfs/inode.c | 13 +++++++++++++ fs/hfsplus/inode.c | 9 +++++++++ fs/isofs/dir.c | 11 +++++++++++ fs/nfs/client.c | 9 +++++++-- fs/nfs/inode.c | 18 ++++++++++++++++++ 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 | 30 ++++++++++++++++++++++++++---- 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 | 19 +++++++++++++++++++ fs/smb/server/smb2pdu.c | 30 ++++++++++++++++++++++++------ 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 | 7 +++++++ include/linux/fileattr.h | 3 +++ include/linux/nfs_xdr.h | 2 ++ 41 files changed, 337 insertions(+), 26 deletions(-)
Signature · 1 line
2.52.0
Chuck Lever
maintainerPATCH v3 1/16 fs: Add case sensitivity info to file_kattr
From: Chuck Lever <[email protected]>
Enable upper layers such as NFSD to retrieve case sensitivity information from file systems by adding case_insensitive and case_preserving boolean fields to struct file_kattr.
The default POSIX behavior (case-sensitive, case-preserving) is initialized in vfs_fileattr_get(), allowing filesystems to override these values only when they differ from the default.
--- fs/file_attr.c | 10 ++++++++++ include/linux/fileattr.h | 3 +++ 2 files changed, 13 insertions(+)
fs/file_attr.c +10 -0
@@ -21,6 +21,9 @@void fileattr_fill_xflags (struct file_kattr *fa,u32 xflags) {memset (fa,0 ,sizeof (*fa)); +/* Default: POSIX semantics (case-sensitive, case-preserving) */ + fa->case_insensitive = false; + fa->case_preserving = true; fa->fsx_valid = true; fa->fsx_xflags = xflags;if (fa->fsx_xflags &FS_XFLAG_IMMUTABLE )
@@ -51,6 +54,9 @@ EXPORT_SYMBOL(fileattr_fill_xflags);void fileattr_fill_flags (struct file_kattr *fa,u32 flags) {memset (fa,0 ,sizeof (*fa)); +/* Default: POSIX semantics (case-sensitive, case-preserving) */ + fa->case_insensitive = false; + fa->case_preserving = true; fa->flags_valid = true; fa->flags = flags;if (fa->flags &FS_SYNC_FL )
@@ -84,6 +90,10 @@ int vfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)struct inode *inode =d_inode (dentry);int error; +/* Default: POSIX semantics (case-sensitive, case-preserving) */ + fa->case_insensitive = false; + fa->case_preserving = true; +if (!inode->i_op->fileattr_get)return -ENOIOCTLCMD ;
include/linux/fileattr.h +3 -0
@@ -51,6 +51,9 @@ struct file_kattr {/* selectors: */ bool flags_valid:1; bool fsx_valid:1; +/* case sensitivity behavior: */ + bool case_insensitive:1; + bool case_preserving:1; };int copy_fsxattr_to_user (const struct file_kattr *fa,struct fsxattr __user *ufa);
Signature · 1 line
2.52.0
Re: [PATCH v3 01/16] fs: Add case sensitivity info to file_kattr
include/linux/fileattr.h struct file_kattr { · line 56
Quoted 3 lines
include/linux/fileattr.h +3
-0+/* case sensitivity behavior: */ + bool case_insensitive:1; + bool case_preserving:1;
Given that not case preserving is by far the exception, maybe have a flag for that instead?
Chuck Lever
maintainerPATCH v3 2/16 fat: Implement fileattr_get for case sensitivity
In reply to Chuck LeverFrom: Chuck Lever <[email protected]>
Report FAT's case sensitivity behavior via the file_kattr boolean fields. FAT filesystems are case-insensitive by default and do not preserve case at rest (stored names are uppercased).
MSDOS supports a 'nocase' mount option that enables case-sensitive behavior; check this option when reporting case sensitivity.
--- fs/fat/fat.h | 3 +++ fs/fat/file.c | 18 ++++++++++++++++++ fs/fat/namei_msdos.c | 1 + fs/fat/namei_vfat.c | 1 + 4 files changed, 23 insertions(+)
fs/fat/fat.h +3 -0
@@ -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); +extern 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);
fs/fat/file.c +18 -0
@@ -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,22 @@ 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 do not preserve case: stored names are +* uppercased. They are case-insensitive by default, but +* MSDOS supports a 'nocase' mount option for case-sensitive +* behavior. +*/ + fa->case_insensitive = !sbi->options.nocase; + fa->case_preserving = false; +return 0 ; +} +EXPORT_SYMBOL_GPL (fat_fileattr_get); +int fat_getattr (struct mnt_idmap *idmap,const struct path *path,struct kstat *stat,u32 request_mask,unsigned int flags) {
@@ -574,5 +591,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, };
fs/fat/namei_msdos.c +1 -0
@@ -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, };
fs/fat/namei_vfat.c +1 -0
@@ -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, };
Signature · 1 line
2.52.0
Re: [PATCH v3 02/16] fat: Implement fileattr_get for case sensitivity
Quoted 1 line
+extern int
fat_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
No need for "extern" for function prototypes.
fs/fat/file.c void fat_truncate_blocks(struct inode *inode, loff_t offset) · line 404
Quoted 6 lines
fs/fat/file.c +6
-0+int fat_fileattr_get (struct dentry *dentry,struct file_kattr *fa) +{ +struct msdos_sb_info *sbi =MSDOS_SB (dentry->d_sb); + +/* +* FAT filesystems do not preserve case: stored names are
Is that actually true? It's been a while since I deal with them, but IIRC at least vfat is case preserving.
Chuck Lever
maintainerPATCH v3 3/16 exfat: Implement fileattr_get for case sensitivity
In reply to Chuck LeverFrom: Chuck Lever <[email protected]>
Report exFAT's case sensitivity behavior via the file_kattr boolean fields. exFAT is always case-insensitive (using an upcase table for comparison) and always preserves case at rest.
--- fs/exfat/exfat_fs.h | 2 ++ fs/exfat/file.c | 17 +++++++++++++++-- fs/exfat/namei.c | 1 + 3 files changed, 18 insertions(+), 2 deletions(-)
fs/exfat/exfat_fs.h +2 -0
@@ -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,
fs/exfat/file.c +15 -2
@@ -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,17 @@ 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) and +* always preserves case at rest. +*/ + fa->case_insensitive = true; + fa->case_preserving = true; +return 0 ; +} +int exfat_setattr (struct mnt_idmap *idmap,struct dentry *dentry,struct iattr *attr) {
@@ -775,6 +787,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, };
fs/exfat/namei.c +1 -0
@@ -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, };
Signature · 1 line
2.52.0
Re: [PATCH v3 03/16] exfat: Implement fileattr_get for case sensitivity
Quoted 8 lines · Chuck Lever
From: Chuck Lever <[email protected]>
Report exFAT's case sensitivity behavior via the
file_kattrboolean fields. exFAT is always case-insensitive (using an upcase table for comparison) and always preserves case at rest.Signed-off-by Chuck Lever <[email protected]>
Thanks!
Chuck Lever
maintainerPATCH v3 4/16 ntfs3: Implement fileattr_get for case sensitivity
In reply to Chuck LeverFrom: Chuck Lever <[email protected]>
Report NTFS case sensitivity behavior via the file_kattr boolean fields. NTFS always preserves case at rest.
Case sensitivity depends on mount options: with "nocase", NTFS is case-insensitive; otherwise it is case-sensitive.
--- 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(+)
fs/ntfs3/file.c +23 -0
@@ -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. Case sensitivity depends on mount options: +* with "nocase" mount option, NTFS is case-insensitive; +* otherwise it is case-sensitive. +*/ + fa->case_insensitive = sbi->options && sbi->options->nocase; + fa->case_preserving = true; +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 = {
fs/ntfs3/inode.c +1 -0
@@ -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 = {
fs/ntfs3/namei.c +2 -0
@@ -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 = {
fs/ntfs3/ntfs_fs.h +1 -0
@@ -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,
Signature · 1 line
2.52.0
Chuck Lever
maintainerPATCH v3 5/16 hfs: Implement fileattr_get for case sensitivity
In reply to Chuck LeverFrom: Chuck Lever <[email protected]>
Report HFS case sensitivity behavior via the file_kattr boolean fields. HFS is always case-insensitive (using Mac OS Roman case folding) and always preserves case at rest.
--- fs/hfs/dir.c | 1 + fs/hfs/hfs_fs.h | 2 ++ fs/hfs/inode.c | 13 +++++++++++++ 3 files changed, 16 insertions(+)
fs/hfs/dir.c +1 -0
@@ -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, };
fs/hfs/hfs_fs.h +2 -0
@@ -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);
fs/hfs/inode.c +13 -0
@@ -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) +{ +/* +* HFS is always case-insensitive (using Mac OS Roman case +* folding) and always preserves case at rest. +*/ + fa->case_insensitive = true; + fa->case_preserving = true; +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, };
Signature · 1 line
2.52.0
Re: [PATCH v3 05/16] hfs: Implement fileattr_get for case sensitivity
Quoted 67 lines · Chuck Lever
From: Chuck Lever <[email protected]>
Report HFS case sensitivity behavior via the
file_kattrboolean fields. HFS is always case-insensitive (using Mac OS Roman case folding) and always preserves case at rest.Signed-off-by Chuck Lever <[email protected]>--- fs/hfs/dir.c | 1 + fs/hfs/hfs_fs.h | 2 ++ fs/hfs/inode.c | 13 +++++++++++++ 3 files changed, 16 insertions(+)fs/hfs/dir.c +1
-0@@ -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, };fs/hfs/hfs_fs.h +2
-0@@ -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);fs/hfs/inode.c +12
-0@@ -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) +{ +/* +* HFS is always case-insensitive (using Mac OS Roman case +* folding) and always preserves case at rest. +*/ + fa->case_insensitive = true; + fa->case_preserving = true; +return 0 ; +} +static const struct file_operations hfs_file_operations = { .llseek = generic_file_llseek, .read_iter = generic_file_read_iter,
fs/hfs/inode.c static const struct inode_operations hfs_file_inode_operations = { · line 730
Quoted 5 lines
fs/hfs/inode.c +1
-0@@ -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, };
Looks good.
Thanks,
Slava.
Chuck Lever
maintainerPATCH v3 6/16 hfsplus: Report case sensitivity in fileattr_get
In reply to Chuck LeverFrom: Chuck Lever <[email protected]>
Add case sensitivity reporting to the existing hfsplus_fileattr_get() function. 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.
--- fs/hfsplus/inode.c | 9 +++++++++ 1 file changed, 9 insertions(+)
fs/hfsplus/inode.c +9 -0
@@ -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,14 @@ int hfsplus_fileattr_get(struct dentry *dentry, struct file_kattr *fa)fileattr_fill_flags (fa, flags); +/* +* HFS+ always preserves case. Case sensitivity depends on how +* the filesystem was formatted: HFSX volumes may be either +* case-sensitive or case-insensitive. +*/ + fa->case_insensitive =test_bit (HFSPLUS_SB_CASEFOLD , &sbi->flags); + fa->case_preserving = true; +return 0 ; }
Signature · 1 line
2.52.0
Re: [PATCH v3 06/16] hfsplus: Report case sensitivity in fileattr_get
Quoted 31 lines · Chuck Lever
From: Chuck Lever <[email protected]>
Add case sensitivity reporting to the existing
hfsplus_fileattr_get()function. 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_CASEFOLDsuperblock flag.Signed-off-by Chuck Lever <[email protected]>--- fs/hfsplus/inode.c | 9 +++++++++ 1 file changed, 9 insertions(+)fs/hfsplus/inode.c +2
-0@@ -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,14 @@ int hfsplus_fileattr_get(struct dentry *dentry, struct file_kattr *fa)fileattr_fill_flags (fa, flags); +/*
fs/hfsplus/inode.c int hfsplus_fileattr_get(struct dentry *dentry, struct file_kattr *fa) · line 719
Quoted 10 lines
fs/hfsplus/inode.c +7
-0+* HFS+ always preserves case. Case sensitivity depends on how +* the filesystem was formatted: HFSX volumes may be either +* case-sensitive or case-insensitive. +*/ + fa->case_insensitive =test_bit (HFSPLUS_SB_CASEFOLD , &sbi->flags); + fa->case_preserving = true; +return 0 ; }
Looks good.
Thanks,
Slava.
Chuck Lever
maintainerPATCH v3 7/16 ext4: Report case sensitivity in fileattr_get
In reply to Chuck LeverFrom: Chuck Lever <[email protected]>
Report ext4's case sensitivity behavior via file_kattr boolean fields. 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).
--- fs/ext4/ioctl.c | 8 ++++++++ 1 file changed, 8 insertions(+)
fs/ext4/ioctl.c +8 -0
@@ -996,6 +996,14 @@ 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); +/* +* ext4 always preserves case. If this inode is a casefolded +* directory, report case-insensitive; otherwise report +* case-sensitive (standard POSIX behavior). +*/ + fa->case_insensitive =IS_CASEFOLDED (inode); + fa->case_preserving = true; +return 0 ; }
Signature · 1 line
2.52.0
Re: [PATCH v3 07/16] ext4: Report case sensitivity in fileattr_get
Quoted 10 lines · Chuck Lever
From: Chuck Lever <[email protected]>
Report ext4's case sensitivity behavior via
file_kattrboolean fields. 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).
Signed-off-by Chuck Lever <[email protected]>
Looks good. Feel free to add:
Honza
Quoted 26 lines
--- fs/ext4/ioctl.c | 8 ++++++++ 1 file changed, 8 insertions(+)fs/ext4/ioctl.c +8
-0@@ -996,6 +996,14 @@ 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); +/* +* ext4 always preserves case. If this inode is a casefolded +* directory, report case-insensitive; otherwise report +* case-sensitive (standard POSIX behavior). +*/ + fa->case_insensitive =IS_CASEFOLDED (inode); + fa->case_preserving = true; +return 0 ; }Signature · 1 line
2.52.0
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Chuck Lever
maintainerPATCH v3 8/16 xfs: Report case sensitivity in fileattr_get
In reply to Chuck LeverFrom: Chuck Lever <[email protected]>
Upper layers such as NFSD need to query whether a filesystem is case-sensitive. Populate the case_insensitive and case_preserving fields 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.
--- fs/xfs/xfs_ioctl.c | 7 +++++++ 1 file changed, 7 insertions(+)
fs/xfs/xfs_ioctl.c +7 -0
@@ -516,6 +516,13 @@ xfs_fileattr_get(xfs_fill_fsxattr (ip,XFS_DATA_FORK , fa);xfs_iunlock (ip,XFS_ILOCK_SHARED ); +/* +* XFS is case-sensitive by default, but can be formatted with +* ASCII case-insensitive mode enabled. +*/ + fa->case_insensitive =xfs_has_asciici (ip->i_mount); + fa->case_preserving = true; +return 0 ; }
Signature · 1 line
2.52.0
Re: [PATCH v3 08/16] xfs: Report case sensitivity in fileattr_get
Quoted 9 lines · Chuck Lever
From: Chuck Lever <[email protected]>
Upper layers such as NFSD need to query whether a filesystem is case-sensitive. Populate the
case_insensitiveandcase_preservingfields inxfs_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.Signed-off-by Chuck Lever <[email protected]>
Well as a pure binary statement of xfs' capabilities, this is correct so:
[add ngompa]
But the next obvious question I would have as a userspace programmer is "case insensitive how, exactly?", which was the topic of the previous revision. Somewhere out there there's a program / emulation layer that will want to know the exact transformation when doing a non-memcmp lookup. Probably Winderz casefolding has behaved differently every release since the start of NTFS, etc.
I don't know how to solve that, other than the fs compiles its case-flattening code into a bpf program and exports that where someone can read() it and run/analyze/reverse engineer it. But ugh, Linus is right that this area is a mess. :/
--D
Quoted 26 lines
--- fs/xfs/xfs_ioctl.c | 7 +++++++ 1 file changed, 7 insertions(+)fs/xfs/xfs_ioctl.c +7
-0@@ -516,6 +516,13 @@ xfs_fileattr_get(xfs_fill_fsxattr (ip,XFS_DATA_FORK , fa);xfs_iunlock (ip,XFS_ILOCK_SHARED ); +/* +* XFS is case-sensitive by default, but can be formatted with +* ASCII case-insensitive mode enabled. +*/ + fa->case_insensitive =xfs_has_asciici (ip->i_mount); + fa->case_preserving = true; +return 0 ; }Signature · 1 line
2.52.0
Re: [PATCH v3 08/16] xfs: Report case sensitivity in fileattr_get
Quoted 15 lines · Darrick J. Wong
Quoted 9 lines · Chuck Lever
From: Chuck Lever <[email protected]>
Upper layers such as NFSD need to query whether a filesystem is case-sensitive. Populate the
case_insensitiveandcase_preservingfields inxfs_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.Signed-off-by Chuck Lever <[email protected]>Well as a pure binary statement of xfs' capabilities, this is correct so:
Reviewed-by "Darrick J. Wong" <[email protected]>
Quoted 9 lines
[add ngompa]
But the next obvious question I would have as a userspace programmer is "case insensitive how, exactly?", which was the topic of the previous revision. Somewhere out there there's a program / emulation layer that will want to know the exact transformation when doing a non-memcmp lookup. Probably Winderz casefolding has behaved differently every release since the start of NTFS, etc.
NTFS itself is case preserving and has a namespace for Win32k entries (case-insensitive) and SFU/SUA/LXSS entries (case-sensitive). I'm not entirely certain of the nature of *how* those entries are managed, but I *believe* it's from the personalities themselves.
Quoted 5 lines
I don't know how to solve that, other than the fs compiles its case-flattening code into a bpf program and exports that where someone can
read()it and run/analyze/reverse engineer it. But ugh, Linus is right that this area is a mess. :/
The biggie is that it has to be NLS aware. That's where it gets complicated since there are different case rules for different languages.
Signature · 1 line
真実はいつも一つ!/ Always, there's only one truth!
Chuck Lever
maintainerPATCH v3 9/16 cifs: Implement fileattr_get for case sensitivity
In reply to Chuck LeverFrom: Chuck Lever <[email protected]>
Upper layers such as NFSD need a way to query whether a filesystem handles filenames in a case-sensitive manner. The file_kattr structure now provides case_insensitive and case_preserving fields for this purpose, but CIFS does not yet report its case sensitivity behavior through this interface.
Implement cifs_fileattr_get() to report CIFS/SMB case handling behavior. 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 case_preserving field is always set to true since SMB servers preserve filename case at rest.
The callback is registered in all three inode_operations structures (directory, file, and symlink) to ensure consistent reporting across all inode types.
--- fs/smb/client/cifsfs.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
fs/smb/client/cifsfs.c +19 -0
@@ -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,21 @@ 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); + +/* +* CIFS/SMB servers are typically case-insensitive but +* case-preserving. The nocase mount option reflects what +* the client expects from the server. +*/ + fa->case_insensitive = tcon->nocase; + fa->case_preserving = true; +return 0 ; +} +const struct inode_operations cifs_dir_inode_ops = { .create = cifs_create, .atomic_open = cifs_atomic_open,
@@ -1210,6 +1226,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 +1237,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 +1272,7 @@ const struct inode_operations cifs_symlink_inode_ops = { .setattr = cifs_setattr, .permission = cifs_permission, .listxattr = cifs_listxattr, + .fileattr_get = cifs_fileattr_get, };/*
Signature · 1 line
2.52.0
Chuck Lever
maintainerPATCH v3 10/16 nfs: Implement fileattr_get for case sensitivity
In reply to Chuck LeverFrom: Chuck Lever <[email protected]>
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 case_insensitive and case_preserving flags in file_kattr. NFSv2 lacks PATHCONF support, so mounts using that protocol version default to standard POSIX behavior: case-sensitive and case- preserving.
--- fs/nfs/client.c | 9 +++++++-- fs/nfs/inode.c | 18 ++++++++++++++++++ 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, 45 insertions(+), 4 deletions(-)
fs/nfs/client.c +7 -2
@@ -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 &&
fs/nfs/inode.c +18 -0
@@ -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"
@@ -1100,6 +1101,23 @@ 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); + + fa->case_insensitive =nfs_server_capable (inode,NFS_CAP_CASE_INSENSITIVE ); + fa->case_preserving =nfs_server_capable (inode,NFS_CAP_CASE_PRESERVING ); +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 );
fs/nfs/internal.h +3 -0
@@ -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 {
fs/nfs/nfs3proc.c +2 -0
@@ -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,
fs/nfs/nfs3xdr.c +5 -2
@@ -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 ; }
fs/nfs/nfs4proc.c +2 -0
@@ -11041,6 +11041,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 = {
@@ -11048,6 +11049,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,
fs/nfs/proc.c +3 -0
@@ -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 = {
fs/nfs/symlink.c +3 -0
@@ -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, };
include/linux/nfs_xdr.h +2 -0
@@ -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 {
Signature · 1 line
2.52.0
Chuck Lever
maintainerPATCH v3 11/16 f2fs: Add case sensitivity reporting to fileattr_get
In reply to Chuck LeverFrom: Chuck Lever <[email protected]>
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 file_kattr boolean fields. Like ext4, f2fs supports per-directory case folding via the casefold flag (IS_CASEFOLDED). Files are always case-preserving.
--- fs/f2fs/file.c | 8 ++++++++ 1 file changed, 8 insertions(+)
fs/f2fs/file.c +8 -0
@@ -3439,6 +3439,14 @@ 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 always preserves case. If this inode is a casefolded +* directory, report case-insensitive; otherwise report +* case-sensitive (standard POSIX behavior). +*/ + fa->case_insensitive =IS_CASEFOLDED (inode); + fa->case_preserving = true; +return 0 ; }
Signature · 1 line
2.52.0
Re: [PATCH v3 11/16] f2fs: Add case sensitivity reporting to fileattr_get
Quoted 8 lines · Chuck Lever
From: Chuck Lever <[email protected]>
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.
Quoted 6 lines
Report f2fs case sensitivity behavior via the
file_kattrboolean fields. Like ext4, f2fs supports per-directory case folding via the casefold flag (IS_CASEFOLDED). Files are always case-preserving.Signed-off-by Chuck Lever <[email protected]>
Thanks,
Chuck Lever
maintainerPATCH v3 12/16 vboxsf: Implement fileattr_get for case sensitivity
In reply to Chuck LeverFrom: Chuck Lever <[email protected]>
Upper layers such as NFSD need a way to query whether a filesystem handles filenames in a case-sensitive manner. The file_kattr structure now provides case_insensitive and case_preserving fields for this purpose, but vboxsf does not yet report its case sensitivity behavior through this interface.
Implement vboxsf_fileattr_get() to report the case handling behavior of VirtualBox shared folders. 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.
--- 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(-)
fs/vboxsf/dir.c +1 -0
@@ -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, };
fs/vboxsf/file.c +4 -2
@@ -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, };
fs/vboxsf/super.c +4 -0
@@ -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 ;
fs/vboxsf/utils.c +31 -0
@@ -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); + + fa->case_insensitive = sbi->case_insensitive; +/* +* VirtualBox shared folders always preserve filename case +* exactly as provided by the guest. The host interface does +* not expose a case_preserving property. +*/ + fa->case_preserving = true; +return 0 ; +}
fs/vboxsf/vfsmod.h +6 -0
@@ -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 );
Signature · 1 line
2.52.0
Chuck Lever
maintainerPATCH v3 13/16 isofs: Implement fileattr_get for case sensitivity
In reply to Chuck LeverFrom: Chuck Lever <[email protected]>
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. The 'check=r' (relaxed) mount option enables case-insensitive lookups, and this setting determines the value reported through the file_kattr structure. 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.
--- fs/isofs/dir.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
fs/isofs/dir.c +11 -0
@@ -12,6 +12,7 @@* isofs directory handling functions */ #include <linux/gfp.h> +#include <linux/fileattr.h> #include "isofs.h" int isofs_name_translate (struct iso_directory_record *de,char *new,struct inode *inode)
@@ -266,6 +267,15 @@ 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); + + fa->case_insensitive = sbi->s_check =='r' ; + fa->case_preserving = true; +return 0 ; +} +const struct file_operations isofs_dir_operations = { .llseek = generic_file_llseek,
@@ -279,6 +289,7 @@ const struct file_operations isofs_dir_operations =const struct inode_operations isofs_dir_inode_operations = { .lookup = isofs_lookup, + .fileattr_get = isofs_fileattr_get, };
Signature · 1 line
2.52.0
Re: [PATCH v3 13/16] isofs: Implement fileattr_get for case sensitivity
Quoted 17 lines · Chuck Lever
From: Chuck Lever <[email protected]>
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. The 'check=r' (relaxed) mount option enables case-insensitive lookups, and this setting determines the value reported through thefile_kattrstructure. 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.
Quoted 5 lines
The callback is registered only on
isofs_dir_inode_operationsbecause isofs has no custominode_operationsfor regular files, and symlinks use the genericpage_symlink_inode_operations.Signed-off-by Chuck Lever <[email protected]>
Looks good. Feel free to add:
Honza
Quoted 43 lines
--- fs/isofs/dir.c | 11 +++++++++++ 1 file changed, 11 insertions(+)fs/isofs/dir.c +11
-0@@ -12,6 +12,7 @@* isofs directory handling functions */ #include <linux/gfp.h> +#include <linux/fileattr.h> #include "isofs.h" int isofs_name_translate (struct iso_directory_record *de,char *new,struct inode *inode)@@ -266,6 +267,15 @@ 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); + + fa->case_insensitive = sbi->s_check =='r' ; + fa->case_preserving = true; +return 0 ; +} +const struct file_operations isofs_dir_operations = { .llseek = generic_file_llseek,@@ -279,6 +289,7 @@ const struct file_operations isofs_dir_operations =const struct inode_operations isofs_dir_inode_operations = { .lookup = isofs_lookup, + .fileattr_get = isofs_fileattr_get, };Signature · 1 line
2.52.0
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Chuck Lever
maintainerPATCH v3 14/16 nfsd: Report export case-folding via NFSv3 PATHCONF
In reply to Chuck LeverFrom: Chuck Lever <[email protected]>
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.
--- fs/nfsd/nfs3proc.c | 18 ++++++++++-------- fs/nfsd/vfs.c | 25 +++++++++++++++++++++++++ fs/nfsd/vfs.h | 2 ++ 3 files changed, 37 insertions(+), 8 deletions(-)
fs/nfsd/nfs3proc.c +10 -8
@@ -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; } }
fs/nfsd/vfs.c +25 -0
@@ -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.case_insensitive; + *case_preserving = fa.case_preserving; +return nfs_ok; +}
fs/nfsd/vfs.h +2 -0
@@ -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);
Signature · 1 line
2.52.0
Chuck Lever
maintainerPATCH v3 15/16 nfsd: Implement NFSv4 FATTR4_CASE_INSENSITIVE and FATTR4_CASE_PRESERVING
In reply to Chuck LeverFrom: Chuck Lever <[email protected]>
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.
--- fs/nfsd/nfs4xdr.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-)
fs/nfsd/nfs4xdr.c +26 -4
@@ -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,13 @@ 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) + goto out; + }if (attrmask[0 ] &FATTR4_WORD0_ACL ) { err =nfsd4_get_nfs4_acl (rqstp, dentry, &args.acl);
Signature · 1 line
2.52.0
Chuck Lever
maintainerPATCH v3 16/16 ksmbd: Report filesystem case sensitivity via FS_ATTRIBUTE_INFORMATION
In reply to Chuck LeverFrom: Chuck Lever <[email protected]>
ksmbd hard-codes FILE_CASE_SENSITIVE_SEARCH and FILE_CASE_PRESERVED_NAMES in FS_ATTRIBUTE_INFORMATION responses, incorrectly indicating all exports are case-sensitive. This breaks clients accessing case-insensitive filesystems like exFAT or ext4/f2fs directories with casefold enabled.
Query actual case behavior via vfs_fileattr_get() and report accurate attributes to SMB clients. Filesystems without ->fileattr_get continue reporting default POSIX behavior (case-sensitive, case-preserving).
SMB's FS_ATTRIBUTE_INFORMATION reports per-share attributes from the share root, not per-file. Shares mixing casefold and non-casefold directories report the root directory's behavior.
--- fs/smb/server/smb2pdu.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-)
fs/smb/server/smb2pdu.c +24 -6
@@ -13,6 +13,7 @@#include <linux/falloc.h> #include <linux/mount.h> #include <linux/filelock.h> +#include <linux/fileattr.h> #include "glob.h" #include "smbfsctl.h"
@@ -5486,16 +5487,33 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,case FS_ATTRIBUTE_INFORMATION : {FILE_SYSTEM_ATTRIBUTE_INFO *info; +struct file_kattr fa = {};size_t sz; +u32 attrs; +int err; info = (FILE_SYSTEM_ATTRIBUTE_INFO *)rsp->Buffer; - info->Attributes =cpu_to_le32 (FILE_SUPPORTS_OBJECT_IDS | -FILE_PERSISTENT_ACLS | -FILE_UNICODE_ON_DISK | -FILE_CASE_PRESERVED_NAMES | -FILE_CASE_SENSITIVE_SEARCH | -FILE_SUPPORTS_BLOCK_REFCOUNTING ); + attrs =FILE_SUPPORTS_OBJECT_IDS | +FILE_PERSISTENT_ACLS | +FILE_UNICODE_ON_DISK | +FILE_SUPPORTS_BLOCK_REFCOUNTING ; + err =vfs_fileattr_get (path.dentry, &fa); +if (err && err != -ENOIOCTLCMD ) { +path_put (&path); +return err; + } +if (err == -ENOIOCTLCMD ) { +/* Default POSIX: case-sensitive and case-preserving */ + fa.case_insensitive = false; + fa.case_preserving = true; + } +if (!fa.case_insensitive) + attrs |=FILE_CASE_SENSITIVE_SEARCH ; +if (fa.case_preserving) + attrs |=FILE_CASE_PRESERVED_NAMES ; + + info->Attributes =cpu_to_le32 (attrs); info->Attributes |=cpu_to_le32 (server_conf.share_fake_fscaps); if (test_share_config_flag(work->tcon->share_conf,
Signature · 1 line
2.52.0
Re: [PATCH v3 16/16] ksmbd: Report filesystem case sensitivity via FS_ATTRIBUTE_INFORMATION
Quoted 13 lines · Chuck Lever
From: Chuck Lever <[email protected]>
ksmbd hard-codes
FILE_CASE_SENSITIVE_SEARCHandFILE_CASE_PRESERVED_NAMESinFS_ATTRIBUTE_INFORMATIONresponses, incorrectly indicating all exports are case-sensitive. This breaks clients accessing case-insensitive filesystems like exFAT or ext4/f2fs directories with casefold enabled.Query actual case behavior via
vfs_fileattr_get()and report accurate attributes to SMB clients. Filesystems without ->fileattr_get continue reporting default POSIX behavior (case-sensitive, case-preserving).
Quoted 5 lines
SMB's
FS_ATTRIBUTE_INFORMATIONreports per-share attributes from the share root, not per-file. Shares mixing casefold and non-casefold directories report the root directory's behavior.Signed-off-by Chuck Lever <[email protected]>
Thanks!
Christian Brauner
maintainerQuoted 21 lines · Chuck Lever
From: Chuck Lever <[email protected]>
Following on from
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-preserving = trueThe case-insensitivity and case-preserving booleans can be consumed immediately by NFSD. These two booleans have been part of the NFSv3 and NFSv4 protocols for decades, in order to support NFS clients on non-POSIX systems.
Quoted 4 lines
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.
This all looks good to me.
Just one question: This reads like you are exposing the new file attr bits via userspace but I can only see changes to the kernel internal headers not the uapi headers. So are you intentionally not exposing this as a new uapi extension to file attr or is this an accident?
Chuck Lever
maintainerQuoted 27 lines · Christian Brauner
Quoted 21 lines · Chuck Lever
From: Chuck Lever <[email protected]>
Following on from
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-preserving = trueThe case-insensitivity and case-preserving booleans can be consumed immediately by NFSD. These two booleans have been part of the NFSv3 and NFSv4 protocols for decades, in order to support NFS clients on non-POSIX systems.
Quoted 4 lines
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.
Quoted 5 lines
This all looks good to me.
Just one question: This reads like you are exposing the new file attr bits via userspace but I can only see changes to the kernel internal headers not the uapi headers. So are you intentionally not exposing this as a new uapi extension to file attr or is this an accident?
The intention is to expose the new bits to user space. IIRC those got removed from uapi headers when I converted from using statx. I can fix that up and post a v4.
Signature · 1 line
Chuck Lever