Linux EXT4 FS development
 help / color / mirror / Atom feed
* [PATCH v10 05/17] ntfs3: Implement fileattr_get for case sensitivity
From: Chuck Lever @ 2026-04-23 13:12 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: <20260423-case-sensitivity-v10-0-c385d674a6cf@oracle.com>

From: Chuck Lever <chuck.lever@oracle.com>

Report NTFS case sensitivity behavior via the FS_XFLAG_CASEFOLD
flag. NTFS always preserves case at rest.

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 b041639ab406..bb3b3a89204d 100644
--- a/fs/ntfs3/file.c
+++ b/fs/ntfs3/file.c
@@ -180,6 +180,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->nocase)
+		fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
+	return 0;
+}
+
 /*
  * ntfs_getattr - inode_operations::getattr
  */
@@ -1547,6 +1569,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 42af1abe17f8..a5ff04c2efd3 100644
--- a/fs/ntfs3/inode.c
+++ b/fs/ntfs3/inode.c
@@ -2095,6 +2095,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 b2af8f695e60..eb241d7796ba 100644
--- a/fs/ntfs3/namei.c
+++ b/fs/ntfs3/namei.c
@@ -518,6 +518,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 = {
@@ -526,6 +527,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 bbf3b6a1dcbe..41db22d652c4 100644
--- a/fs/ntfs3/ntfs_fs.h
+++ b/fs/ntfs3/ntfs_fs.h
@@ -529,6 +529,7 @@ bool dir_is_empty(struct inode *dir);
 extern const struct file_operations ntfs_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.53.0


^ permalink raw reply related

* [PATCH v10 04/17] exfat: Implement fileattr_get for case sensitivity
From: Chuck Lever @ 2026-04-23 13:12 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: <20260423-case-sensitivity-v10-0-c385d674a6cf@oracle.com>

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     | 17 +++++++++++++++--
 fs/exfat/namei.c    |  1 +
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index 89ef5368277f..aff4dcd4e75a 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -496,6 +496,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 354bdcfe4abc..8af829ef54c4 100644
--- a/fs/exfat/file.c
+++ b/fs/exfat/file.c
@@ -14,6 +14,7 @@
 #include <linux/writeback.h>
 #include <linux/filelock.h>
 #include <linux/falloc.h>
+#include <linux/fileattr.h>
 
 #include "exfat_raw.h"
 #include "exfat_fs.h"
@@ -323,6 +324,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 compares filenames through an upcase table, so lookup
+	 * is always case-insensitive. Long names are stored in UTF-16
+	 * with case intact; CASENONPRESERVING stays clear.
+	 */
+	fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
+	return 0;
+}
+
 int exfat_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
 		  struct iattr *attr)
 {
@@ -817,6 +829,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 2c5636634b4a..94002e43db08 100644
--- a/fs/exfat/namei.c
+++ b/fs/exfat/namei.c
@@ -1311,4 +1311,5 @@ const struct inode_operations exfat_dir_inode_operations = {
 	.rename		= exfat_rename,
 	.setattr	= exfat_setattr,
 	.getattr	= exfat_getattr,
+	.fileattr_get	= exfat_fileattr_get,
 };

-- 
2.53.0


^ permalink raw reply related

* [PATCH v10 03/17] fat: Implement fileattr_get for case sensitivity
From: Chuck Lever @ 2026-04-23 13:12 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: <20260423-case-sensitivity-v10-0-c385d674a6cf@oracle.com>

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.

Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/fat/fat.h         |  3 +++
 fs/fat/file.c        | 23 +++++++++++++++++++++++
 fs/fat/namei_msdos.c |  1 +
 fs/fat/namei_vfat.c  |  1 +
 4 files changed, 28 insertions(+)

diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 5a58f0bf8ce8..99ed9228a677 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
  */
@@ -408,6 +410,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 becccdd2e501..34d8588fcd3f 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -17,6 +17,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,
@@ -398,6 +399,27 @@ 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)
+			fa->fsx_xflags |= FS_XFLAG_CASENONPRESERVING;
+	}
+	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)
 {
@@ -575,5 +597,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 4cc65f330fb7..0fd2971ad4b1 100644
--- a/fs/fat/namei_msdos.c
+++ b/fs/fat/namei_msdos.c
@@ -644,6 +644,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 918b3756674c..e909447873e3 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -1185,6 +1185,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.53.0


^ permalink raw reply related

* [PATCH v10 02/17] fs: Add case sensitivity flags to file_kattr
From: Chuck Lever @ 2026-04-23 13:12 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: <20260423-case-sensitivity-v10-0-c385d674a6cf@oracle.com>

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. Both flags are added to FS_XFLAG_RDONLY_MASK so
FS_IOC_FSSETXATTR silently strips them, keeping the new xflags
strictly a reporting interface. Callers that want to toggle
casefolding continue to use FS_IOC_SETFLAGS with FS_CASEFOLD_FL,
the established UAPI on filesystems that support the operation
(ext4 and f2fs on empty directories).

Case sensitivity information is exported to userspace via the
fa_xflags field in the FS_IOC_FSGETXATTR ioctl and file_getattr()
system call.

Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/file_attr.c           | 4 ++++
 include/linux/fileattr.h | 3 ++-
 include/uapi/linux/fs.h  | 7 +++++++
 3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/fs/file_attr.c b/fs/file_attr.c
index f429da66a317..bfb00d256dd5 100644
--- a/fs/file_attr.c
+++ b/fs/file_attr.c
@@ -37,6 +37,8 @@ void fileattr_fill_xflags(struct file_kattr *fa, u32 xflags)
 		fa->flags |= FS_PROJINHERIT_FL;
 	if (fa->fsx_xflags & FS_XFLAG_VERITY)
 		fa->flags |= FS_VERITY_FL;
+	if (fa->fsx_xflags & FS_XFLAG_CASEFOLD)
+		fa->flags |= FS_CASEFOLD_FL;
 }
 EXPORT_SYMBOL(fileattr_fill_xflags);
 
@@ -67,6 +69,8 @@ void fileattr_fill_flags(struct file_kattr *fa, u32 flags)
 		fa->fsx_xflags |= FS_XFLAG_PROJINHERIT;
 	if (fa->flags & FS_VERITY_FL)
 		fa->fsx_xflags |= FS_XFLAG_VERITY;
+	if (fa->flags & FS_CASEFOLD_FL)
+		fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
 }
 EXPORT_SYMBOL(fileattr_fill_flags);
 
diff --git a/include/linux/fileattr.h b/include/linux/fileattr.h
index 3780904a63a6..58044b598016 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_VERITY)
+	(FS_XFLAG_PREALLOC | FS_XFLAG_HASATTR | FS_XFLAG_VERITY | \
+	 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 13f71202845e..2ea4c81df08f 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -254,6 +254,13 @@ struct file_attr {
 #define FS_XFLAG_DAX		0x00008000	/* use DAX for IO */
 #define FS_XFLAG_COWEXTSIZE	0x00010000	/* CoW extent size allocator hint */
 #define FS_XFLAG_VERITY		0x00020000	/* fs-verity enabled */
+/*
+ * Case handling flags (read-only, cannot be set via ioctl).
+ * Default (neither set) indicates POSIX semantics: case-sensitive
+ * lookups and case-preserving storage.
+ */
+#define FS_XFLAG_CASEFOLD	0x00040000	/* case-insensitive lookups */
+#define FS_XFLAG_CASENONPRESERVING 0x00080000	/* 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.53.0


^ permalink raw reply related

* [PATCH v10 01/17] fs: Move file_kattr initialization to callers
From: Chuck Lever @ 2026-04-23 13:12 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: <20260423-case-sensitivity-v10-0-c385d674a6cf@oracle.com>

From: Chuck Lever <chuck.lever@oracle.com>

fileattr_fill_xflags() and fileattr_fill_flags() memset the
entire file_kattr struct before populating select fields, so
callers cannot pre-set fields in fa->fsx_xflags without having
their values clobbered. Darrick Wong noted that a function
named "fill_xflags" touching more than xflags forces callers
to know implementation details beyond its apparent scope.

Drop the memset from both fill functions and initialize at the
entry points instead: ioctl_setflags(), ioctl_fssetxattr(),
the file_setattr() syscall, and xfs_ioc_fsgetxattra() now
declare fa with an aggregate initializer. ioctl_getflags(),
ioctl_fsgetxattr(), and the file_getattr() syscall already
aggregate-initialize fa to pass flags_valid/fsx_valid hints
into vfs_fileattr_get().

Subsequent patches rely on this so that ->fileattr_get()
handlers can set case-sensitivity flags (FS_XFLAG_CASEFOLD,
FS_XFLAG_CASENONPRESERVING) in fa->fsx_xflags before the fill
functions run.

Suggested-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/file_attr.c     | 12 ++++--------
 fs/xfs/xfs_ioctl.c |  2 +-
 2 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/fs/file_attr.c b/fs/file_attr.c
index da983e105d70..f429da66a317 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)
@@ -48,11 +46,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)
@@ -325,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;
 
@@ -357,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);
@@ -431,7 +427,7 @@ SYSCALL_DEFINE5(file_setattr, int, dfd, const char __user *, filename,
 	struct path filepath __free(path_put) = {};
 	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 46e234863644..ed9b4846c05f 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -517,7 +517,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);

-- 
2.53.0


^ permalink raw reply related

* [PATCH v10 00/17] Exposing case folding behavior
From: Chuck Lever @ 2026-04-23 13:12 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, Steve French

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 = false

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.

[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 v9:
- nfs: always probe PATHCONF for case caps. Default to case-
  preserving when the server does not report case_preserving
- nfsd, ksmbd: tolerate -ENOTTY from vfs_fileattr_get() so
  overlayfs exports on backing filesystems without fileattr_get
  do not fail the RPC
- xfs: map FS_XFLAG_CASEFOLD inside xfs_ip2xflags() so BULKSTAT
  and FS_IOC_FSGETXATTR report the flag consistently
- vboxsf: reject a short host reply to SHFL_INFO_VOLUME before
  trusting volinfo.properties.case_sensitive

Changes since v8:
- Rebase on v7.0-rc1

Changes since v7:
- Split file_attr initialization changes into a separate patch

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 (17):
      fs: Move file_kattr initialization to callers
      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                | 17 +++++++++++++++--
 fs/exfat/namei.c               |  1 +
 fs/ext4/ioctl.c                |  7 +++++++
 fs/f2fs/file.c                 |  8 ++++++++
 fs/fat/fat.h                   |  3 +++
 fs/fat/file.c                  | 23 +++++++++++++++++++++++
 fs/fat/namei_msdos.c           |  1 +
 fs/fat/namei_vfat.c            |  1 +
 fs/file_attr.c                 | 16 ++++++++--------
 fs/hfs/dir.c                   |  1 +
 fs/hfs/hfs_fs.h                |  2 ++
 fs/hfs/inode.c                 | 13 +++++++++++++
 fs/hfsplus/inode.c             | 10 ++++++++++
 fs/isofs/dir.c                 | 11 +++++++++++
 fs/nfs/client.c                | 15 ++++++++++-----
 fs/nfs/inode.c                 | 21 +++++++++++++++++++++
 fs/nfs/internal.h              |  3 +++
 fs/nfs/nfs3proc.c              |  2 ++
 fs/nfs/nfs3xdr.c               |  7 +++++--
 fs/nfs/nfs4proc.c              |  7 +++++--
 fs/nfs/proc.c                  |  3 +++
 fs/nfs/symlink.c               |  3 +++
 fs/nfsd/nfs3proc.c             | 18 ++++++++++--------
 fs/nfsd/nfs4xdr.c              | 25 +++++++++++++++++++++++--
 fs/nfsd/vfs.c                  | 29 +++++++++++++++++++++++++++++
 fs/nfsd/vfs.h                  |  3 +++
 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              |  7 +++++++
 fs/vboxsf/utils.c              | 28 ++++++++++++++++++++++++++++
 fs/vboxsf/vfsmod.h             |  6 ++++++
 fs/xfs/libxfs/xfs_inode_util.c |  2 ++
 fs/xfs/xfs_ioctl.c             |  2 +-
 include/linux/fileattr.h       |  3 ++-
 include/linux/nfs_fs_sb.h      |  2 +-
 include/linux/nfs_xdr.h        |  2 ++
 include/uapi/linux/fs.h        |  7 +++++++
 44 files changed, 350 insertions(+), 40 deletions(-)
---
base-commit: 6596a02b207886e9e00bb0161c7fd59fea53c081
change-id: 20260422-case-sensitivity-5cbffc8f1558

Best regards,
--  
Chuck Lever


^ permalink raw reply

* Re: [PATCH v9 00/17] Exposing case folding behavior
From: Christian Brauner @ 2026-04-23 11:52 UTC (permalink / raw)
  To: Chuck Lever
  Cc: Christian Brauner, Al Viro, Jan Kara, 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, Darrick J. Wong
In-Reply-To: <20260422-case-sensitivity-v9-0-be023cc070e2@oracle.com>

On Wed, 22 Apr 2026 19:29:54 -0400, Chuck Lever wrote:
> 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:
> 
> [...]

Applied to the vfs-7.2.casefold branch of the vfs/vfs.git tree.
Patches in the vfs-7.2.casefold branch should appear in linux-next soon.

Please report any outstanding bugs that were missed during review in a
new review to the original patch series allowing us to drop it.

It's encouraged to provide Acked-bys and Reviewed-bys even though the
patch has now been applied. If possible patch trailers will be updated.

Note that commit hashes shown below are subject to change due to rebase,
trailer updates or similar. If in doubt, please check the listed branch.

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
branch: master

[01/17] fs: Move file_kattr initialization to callers
        https://git.kernel.org/vfs/vfs/c/a46401c7dc2f
[02/17] fs: Add case sensitivity flags to file_kattr
        https://git.kernel.org/vfs/vfs/c/1dd697879cf2
[03/17] fat: Implement fileattr_get for case sensitivity
        https://git.kernel.org/vfs/vfs/c/2b124bb86cdb
[04/17] exfat: Implement fileattr_get for case sensitivity
        https://git.kernel.org/vfs/vfs/c/9b8b66549c8e
[05/17] ntfs3: Implement fileattr_get for case sensitivity
        https://git.kernel.org/vfs/vfs/c/7d0fbb53b0c2
[06/17] hfs: Implement fileattr_get for case sensitivity
        https://git.kernel.org/vfs/vfs/c/024b4a69abaf
[07/17] hfsplus: Report case sensitivity in fileattr_get
        https://git.kernel.org/vfs/vfs/c/22a319bfe8b8
[08/17] ext4: Report case sensitivity in fileattr_get
        https://git.kernel.org/vfs/vfs/c/75fd84cb0922
[09/17] xfs: Report case sensitivity in fileattr_get
        https://git.kernel.org/vfs/vfs/c/29323822bece
[10/17] cifs: Implement fileattr_get for case sensitivity
        https://git.kernel.org/vfs/vfs/c/4444c82e69a6
[11/17] nfs: Implement fileattr_get for case sensitivity
        https://git.kernel.org/vfs/vfs/c/6f3f50885bd9
[12/17] f2fs: Add case sensitivity reporting to fileattr_get
        https://git.kernel.org/vfs/vfs/c/e8d671306a8f
[13/17] vboxsf: Implement fileattr_get for case sensitivity
        https://git.kernel.org/vfs/vfs/c/f5e334b94179
[14/17] isofs: Implement fileattr_get for case sensitivity
        https://git.kernel.org/vfs/vfs/c/764609f76826
[15/17] nfsd: Report export case-folding via NFSv3 PATHCONF
        https://git.kernel.org/vfs/vfs/c/06726ac88bb5
[16/17] nfsd: Implement NFSv4 FATTR4_CASE_INSENSITIVE and FATTR4_CASE_PRESERVING
        https://git.kernel.org/vfs/vfs/c/d129f0419eb3
[17/17] ksmbd: Report filesystem case sensitivity via FS_ATTRIBUTE_INFORMATION
        https://git.kernel.org/vfs/vfs/c/8179d08606e8

^ permalink raw reply

* Re: [PATCH] fscrypt: add software key support for filesystem-managed data
From: Liao Yuanhong @ 2026-04-23 10:41 UTC (permalink / raw)
  To: Eric Biggers
  Cc: tytso, jaegeuk, linux-fscrypt, linux-kernel, linux-ext4,
	linux-f2fs-devel
In-Reply-To: <20260422232747.GD2226@sol>

On 4/23/2026 7:27 AM, Eric Biggers wrote:

> I don't have time for a super detailed review at the moment, but here
> are my initial thoughts:
>
> - This needs to be sent along with the code that actually uses it in
>    ext4 and f2fs.  Please also Cc the mailing lists for those
>    filesystems.
>
> - This is going to require an "incompat" filesystem feature flag.  After
>    all, once a filesystem contains files that use this scheme, older
>    kernels won't understand it.
>
> - UBIFS and CephFS already use fs/crypto/ but don't support blk-crypto
>    (inline encryption).  This new code feels duplicative of that.  It
>    should be possible to reuse the existing code instead.  That would
>    include, for example, reusing the existing en/decryption functions and
>    the existing struct ci_enc_key field.  This would keep the changes
>    limited mainly to how the key is being set up.
>
> - Supporting all the different IV generation methods doesn't make sense
>    when a per-file key is always used.
>
> - The fact that this is incompatible with hardware-wrapped keys greatly
>    limits the usefulness of this.  (Note that technically, it could be
>    supported in combination with them anyway.  But the security models
>    would be inconsistent, which I assume is what you have in mind.)
>
> Hope this is helpful,
>
> - Eric

Thanks for the comments. They are very helpful.

I agree that the fscrypt changes should stay much closer to the
existing filesystem-layer encryption code.  I will rework this so
that the fscrypt side is mainly limited to key setup: when
blk-crypto is used for normal file contents, fscrypt can also
prepare the existing software contents crypto state for
filesystem-managed regions that cannot go through bio/blk-crypto.

I will also drop the separate key object / key-selection path, and
try to reuse the existing contents key and software encryption
functions as much as possible.

I agree that supporting all IV generation methods is unnecessary
here.  For the first version, I plan to limit this to the normal v2
per-file-key case.

Regarding hardware-wrapped keys: it may be technically possible to
make this work in some cases, but using a software crypto key for
these regions seems to conflict with the expected hardware-wrapped
key security model.  What would you prefer for the initial version:
should this combination be disallowed, or is there another approach
you would recommend?

Thanks,
Liao Yuanhong

^ permalink raw reply

* Re: [PATCH] ext4: prevent out-of-bounds read in ext4_read_inline_data()
From: Jan Kara @ 2026-04-23  9:46 UTC (permalink / raw)
  To: Junjie Cao
  Cc: Jan Kara, tytso, adilger.kernel, libaokun, ojaswin, ritesh.list,
	yi.zhang, linux-ext4, linux-kernel, stable,
	syzbot+26c4a8cab92d0cda3e3b
In-Reply-To: <20260423170527.129423-1-junjie.cao@intel.com>

On Fri 24-04-26 01:05:26, Junjie Cao wrote:
> Thanks for the review, Jan.
> 
> You're right that v1 failed to identify why the buffer changes.  I dug
> into the syzbot reproducer ??? the corruption path is:
> 
>   1. Mount a crafted ext4 image on a loop device
>   2. Bind-mount the loop device, open + mmap it MAP_SHARED|PROT_WRITE
>   3. Write through the mapping ??? this overwrites the inline xattr
>      entry directly in the bdev page cache

Ah, interesting. I had a look at the syzbot bug and all the reproductions
are actually only on quite old Android kernel (5.15). That kernel doesn't
have infrastructure to block writes to mounted devices - in newer kernels
syzbot sets

CONFIG_BLK_DEV_WRITE_MOUNTED=n

which blocks reproducers like this one.

> The inode buffer_head stays uptodate throughout, so no re-validation
> ever triggers ??? xattr_check_inode() at iget time is thorough but only
> runs once, leaving subsequent in-place corruption of the page cache
> undetected.

Yes, writing to buffer cache through the mapping is equivalent to poking
to your memory. You can do a lot of damage if you are not careful.
Filesystems have no sensible way to protect against such things and in
general it is root-restricted corruption vector so not really interesting
from security perspective.

> However, ext4_xattr_ibody_get() already guards against this with a
> bounds check before its memcpy (xattr.c:674).  ext4_read_inline_data()
> lacks the same check because it indexes via the cached i_inline_off,
> bypassing xattr_find_entry() entirely.  I think aligning the two paths
> is worthwhile, and it would also clear this syzbot report.
> 
> Would a v2 with this framing be acceptable to you?

No, I don't think there a problem to fix. The additional checks will
complicate the code, will be racy anyway, and will cost some performance.
There is no good reason to have them to protect from sysadmin doing stupid
stuff...

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply

* Re: [PATCH] ext4: prevent out-of-bounds read in ext4_read_inline_data()
From: Junjie Cao @ 2026-04-23 17:05 UTC (permalink / raw)
  To: Jan Kara
  Cc: tytso, adilger.kernel, libaokun, ojaswin, ritesh.list, yi.zhang,
	linux-ext4, linux-kernel, stable, syzbot+26c4a8cab92d0cda3e3b,
	junjie.cao
In-Reply-To: <ulfo7ut5ziqvrjy24besb4jtobijunycglvmqki7cwfzsancwi@5ycrwypubh56>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=us-ascii, Size: 1021 bytes --]

Thanks for the review, Jan.

You're right that v1 failed to identify why the buffer changes.  I dug
into the syzbot reproducer — the corruption path is:

  1. Mount a crafted ext4 image on a loop device
  2. Bind-mount the loop device, open + mmap it MAP_SHARED|PROT_WRITE
  3. Write through the mapping — this overwrites the inline xattr
     entry directly in the bdev page cache

The inode buffer_head stays uptodate throughout, so no re-validation
ever triggers — xattr_check_inode() at iget time is thorough but only
runs once, leaving subsequent in-place corruption of the page cache
undetected.

However, ext4_xattr_ibody_get() already guards against this with a
bounds check before its memcpy (xattr.c:674).  ext4_read_inline_data()
lacks the same check because it indexes via the cached i_inline_off,
bypassing xattr_find_entry() entirely.  I think aligning the two paths
is worthwhile, and it would also clear this syzbot report.

Would a v2 with this framing be acceptable to you?

Many thanks,
Junjie

^ permalink raw reply

* Re: [PATCHBOMB v5] fuse/libfuse/e2fsprogs/etc: containerize ext4 for safer operation
From: Amir Goldstein @ 2026-04-23  8:44 UTC (permalink / raw)
  To: Darrick J. Wong
  Cc: linux-fsdevel, linux-ext4, fuse-devel, Miklos Szeredi,
	Bernd Schubert, Joanne Koong, Theodore Ts'o, Neal Gompa,
	Christian Brauner, demiobenour, Naoki MATSUMOTO
In-Reply-To: <20260422231518.GA7717@frogsfrogsfrogs>

On Thu, Apr 23, 2026 at 1:15 AM Darrick J. Wong <djwong@kernel.org> wrote:
>
> Hi everyone,
>
> This *would have been* the eight public draft of the gigantic patchset
> to connect the Linux fuse driver to fs-iomap for regular file IO
> operations to and from files whose contents persist to locally attached
> storage devices.
>
> However, the previous submission was too large, and I didn't even send
> half the patches!  I have therefore split the work into two sections.
> This first section covers setting up fuse servers to run as contained
> systemd services; I previously sent only the libfuse changes, without
> any of the surrounding pieces.  Now I'm ready to send them all.
>
> To summarize this patchbomb: fuse servers can now run as non-root users,
> with no privilege, no access to the network or hardware, etc.  The only
> connection to the outside is an ephemeral AF_UNIX socket.  The process
> on the other end is a helper program that acquires resources and calls
> fsmount().
>
> Why would you want to do that?  Most filesystem drivers are seriously
> vulnerable to metadata parsing attacks, as syzbot has shown repeatedly
> over almost a decade of its existence.  Faulty code can lead to total
> kernel compromise, and I think there's a very strong incentive to move
> all that parsing out to userspace where we can containerize the fuse
> server process.  Runtime filesystem metadata parsing is no longer a
> privileged (== risky) operation.
>
> The consequences of a crashed driver is a dead mount, instead of a
> crashed or corrupt OS kernel.
>
> Note that contained fuse filesystem servers are no faster than regular
> fuse.  The redesign of the fuse IO path via iomap will be the subject of
> the second patchbomb.  The containerization code only requires changes
> to libfuse and is ready to go today.
>
> Since the seventh submission, I have made the following changes:
>
> 1) Added a couple of simple fuse service drivers to the example code
>
> 2) Adapted fuservicemount to be runnable as a setuid program so that
> unprivileged users can start up a containerized filesystem driver
>
> 3) Fixed some endianness handling errors in the socket protocol between
> the new mount helper and the fuse server
>
> 4) Added a high level fuse_main function so that fuse servers that use
> the high level api can containerize without a total rewrite
>
> 5) Adapted mount.fuse to call the new mount helper code so that mount -t
> fuse.XXX can try to start up a contained server
>
> 6) Cleaned up a lot of cppcheck complaints and refactored a bunch of
> repetitious code
>
> 7) Started using codex to try to find bugs and security problems with
> the new mount helper
>
> There are a few unanswered questions:
>
> a. How to integrate with the SYNC_INIT patches that Bernd is working on
> merging into libfuse
>
> b. If /any/ of the new fsopen/fsconfig/fsmount/move_mount calls fail,
> do we fall back to the old mount syscall?  Even after printing errors?
>
> c. Are there any Linux systems where some inetd implementation can
> actually handle AF_UNIX sockets?  Does it make sense to try to do the
> service isolation without the convenience of systemd directives?

A large part of the world is running container workloads on kubernetes
and my understanding is that k8s does not mix well with systemd.

We have successfully used the fusetmount3-proxy [1] approach by Naoki
MATSUMOTO as a way for unprivileged containers to delegate fuse mount
by a (non-systemd) service, running in another container.

[1] https://github.com/pfnet-research/meta-fuse-csi-plugin#fusermount3-proxy-modified-fusermount3-approach

The README says that sshfs, s3fs and other high profile fuse fs have been
tested with this approach and they do not require any rebuild.

So it bears the question...

>
> d. meson/autoconf/cmake are a pain to deal with, hopefully the changes I
> made are correct
>
> I have also converted a handful more fuse servers (fat, exfat, iso,
> http) to the new service architecture so that I can run a (virtual)
> Debian system with EFI completely off of containerized fuse servers.
> These will be sent at the end.
>

... what is the added value of rebuilding those packages with systemd
service support?

I am not implying that there is no added value, I just am not well versed
in the world of container and system services.

Thanks,
Amir.

^ permalink raw reply

* Re: [PATCH v2 3/3] ext4: derive f_fsid from block device to avoid collisions
From: Christoph Hellwig @ 2026-04-23  5:08 UTC (permalink / raw)
  To: Anand Jain
  Cc: Christoph Hellwig, Theodore Tso, Darrick J. Wong, linux-ext4,
	linux-btrfs, linux-xfs, Anand Jain, dsterba
In-Reply-To: <cd9c0147-18cf-464d-86e2-12342a992ebc@gmail.com>

On Wed, Apr 22, 2026 at 07:39:57PM +0800, Anand Jain wrote:
> > No, T10 does not actually mandate unique identifiers, NVMe does, but the
> > implementations are often totally broken.
> 
> Right. Newer SPC-3 (and above) compliant devices must support
> the Inquiry CDB EVPD flag and provide page 0x83 for identification,
> which is what we typically use for multipathing.

But there is no requirement for it to contain something useful.

> These are globally unique. And, we can overlook legacy
> drives, as they've probably been past their EOSL for a while now.

We have absolutely no useful identifiers for most USB devices.
NVMe devices have broken identifiers all the time as well.

So no, you can't.


^ permalink raw reply

* Re: [moderation] KCSAN: data-race in filemap_read / filemap_splice_read (3)
From: syzbot @ 2026-04-23  5:05 UTC (permalink / raw)
  To: adilger.kernel, akpm, almaz.alexandrovich, baolin.wang, hughd,
	jack, jiayuan.chen, jiayuan.chen, linux-ext4, linux-fsdevel,
	linux-kernel, linux-mm, linux-trace-kernel, mathieu.desnoyers,
	mhiramat, ntfs3, rostedt, syzkaller-upstream-moderation, tytso,
	willy
In-Reply-To: <699fd494.050a0220.2fcbed.0000.GAE@google.com>

Auto-closing this bug as obsolete.
Crashes did not happen for a while, no reproducer and no activity.

^ permalink raw reply

* Re: [PATCH] generic/790: test post-EOF gap zeroing persistence
From: Zhang Yi @ 2026-04-23  1:41 UTC (permalink / raw)
  To: Brian Foster
  Cc: fstests, zlang, linux-ext4, linux-fsdevel, jack, yi.zhang,
	yizhang089, yangerkun
In-Reply-To: <aejLp-m2-0h6q0RE@bfoster>

On 4/22/2026 9:22 PM, Brian Foster wrote:
> On Wed, Apr 22, 2026 at 09:52:46AM +0800, Zhang Yi wrote:
>> From: Zhang Yi <yi.zhang@huawei.com>
>>
>> Test that extending a file past a non-block-aligned EOF correctly
>> zero-fills the gap [old_EOF, block_boundary), and that this zeroing
>> persists through a filesystem shutdown+remount cycle.
>>
>> Stale data beyond EOF can persist on disk when append write data blocks
>> are flushed before the i_size metadata update, or when concurrent append
>> writeback and mmap writes persist non-zero data past EOF. Subsequent
>> post-EOF operations (append write, fallocate, truncate up) must
>> zero-fill and persist the gap to prevent exposing stale data.
>>
>> The test pollutes the file's last physical block (via FIEMAP + raw
>> device write) with a sentinel pattern beyond i_size, then performs each
>> extend operation and verifies the gap is zeroed both in memory and on
>> disk.
>>
>> Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
>> ---
>> This is the case Jan Kara pointed out during my work on the ext4
>> buffered I/O to iomap conversion. This case is similar to generic/363,
>> but generic/363 doesn't provide persistent testing. For details:
>>
>>  https://lore.kernel.org/linux-ext4/jgotl7vzzuzm6dvz5zfgk6haodxvunb4hq556pzh4hqqwvnhxq@lr3jiedhqh7c/
>>
>>  tests/generic/790     | 155 ++++++++++++++++++++++++++++++++++++++++++
>>  tests/generic/790.out |   4 ++
>>  2 files changed, 159 insertions(+)
>>  create mode 100755 tests/generic/790
>>  create mode 100644 tests/generic/790.out
>>
>> diff --git a/tests/generic/790 b/tests/generic/790
>> new file mode 100755
>> index 00000000..5d8f61f9
>> --- /dev/null
>> +++ b/tests/generic/790
>> @@ -0,0 +1,155 @@
>> +#! /bin/bash
>> +# SPDX-License-Identifier: GPL-2.0
>> +# Copyright (c) 2026 Huawei.  All Rights Reserved.
>> +#
>> +# FS QA Test No. 790
>> +#
>> +# Test that extending a file past a non-block-aligned EOF correctly zero-fills
>> +# the gap [old_EOF, block_boundary), and that this zeroing persists through a
>> +# filesystem shutdown+remount cycle.
>> +#
> 
> Nice test! This is a great idea.
> 
>> +# Stale data beyond EOF can persist on disk when:
>> +# 1) append write data blocks are flushed before the i_size metadata update,
>> +#    and the system crashes in this window.
> 
> Maybe it's wording or I'm missing something, but how would "append write
> data blocks" be flushed before i_size updates? Wouldn't writeback toss
> them or zero the post-eof range of a folio? Do you mean to refer to
> "on-disk size update" specifically (where I'm reading it as
> inode->i_isize)?

It's wording, I mean the "on-disk file size update", sorry for confusing.

> 
>> +# 2) concurrent append writeback and mmap writes persist non-zero data past EOF.
>> +#
>> +# Subsequent post-EOF operations (append write, fallocate, truncate up) must
>> +# zero-fill and persist the gap to prevent exposing stale data.
>> +#
>> +# The test pollutes the file's last physical block (via FIEMAP + raw device
>> +# write) with a sentinel pattern beyond i_size, then performs each extend
>> +# operation and verifies the gap is zeroed both in memory and on disk.
>> +#
> ...
>> +_test_eof_zeroing()
>> +{
>> +	local test_name="$1"
>> +	local extend_cmd="$2"
>> +	local file=$SCRATCH_MNT/testfile_${test_name}
>> +
>> +	echo "$test_name" | tee -a $seqres.full
>> +
>> +	# Compute non-block-aligned EOF offset
>> +	local gap_bytes=16
>> +	local eof_offset=$((blksz - gap_bytes))
>> +
>> +	# Step 1: Write one full block to ensure the filesystem allocates a
>> +	#         physical block for the file instead of using inline data.
>> +	$XFS_IO_PROG -f -c "pwrite -S 0x5a 0 $blksz" -c fsync \
>> +		"$file" >> $seqres.full 2>&1
>> +
>> +	# Step 2: Get physical block offset on device via FIEMAP
>> +	local phys_offset
>> +	phys_offset=$(_get_phys_offset "$file")
>> +	if [ -z "$phys_offset" ]; then
>> +		_fail "$test_name: failed to get physical block offset via fiemap"
>> +	fi
>> +
>> +	# Step 3: Truncate file to non-block-aligned size and fsync.
>> +	#         The on-disk region [eof_offset, blksz) may or may not be
>> +	#         zeroed by the filesystem at this point.
>> +	$XFS_IO_PROG -c "truncate $eof_offset" -c fsync \
>> +		"$file" >> $seqres.full 2>&1
>> +
>> +	# Step 4: Unmount and restore the physical block to all-0x5a on disk.
>> +	#         This bypasses the kernel's pagecache EOF-zeroing to ensure
>> +	#         the stale pattern is present on disk. Then remount.
>> +	_scratch_unmount
>> +	$XFS_IO_PROG -d -c "pwrite -S 0x5a $phys_offset $blksz" \
>> +		$SCRATCH_DEV >> $seqres.full 2>&1
>> +	_scratch_mount >> $seqres.full 2>&1
>> +
>> +	# Verify file size is still eof_offset after remount
>> +	local sz
>> +	sz=$(stat -c %s "$file")
>> +	if [ "$sz" -ne "$eof_offset" ]; then
>> +		_fail "$test_name: file size wrong after remount: $sz != $eof_offset"
>> +	fi
> 
> I was initially curious why we'd want to do this, but after further
> thought I wonder if it might make more sense to check file size against
> the extended size after the shutdown/mount cycle below (but before
> checking the gap range). That way we know the size update was
> logged/recovered correctly and we're about to read from a file range
> within eof. Hm?

Yeah, this check should be more necessary after the shutdown/mount
cycle.

> 
> Those couple nits aside this all looks pretty good to me.

Thank you for the review.

Best Regards,
Yi.

> 
> Brian
> 
>> +
>> +	# Step 5: Execute the extend operation.
>> +	$XFS_IO_PROG -c "$extend_cmd" "$file" >> $seqres.full 2>&1
>> +
>> +	# Step 6: Verify gap [eof_offset, blksz) is zeroed BEFORE shutdown
>> +	_check_gap_zero "$file" $eof_offset $gap_bytes "before shutdown" || return 1
>> +
>> +	# Step 7: Sync the extended range and shutdown the filesystem with
>> +	#         journal flush. This persists the file size extending, and
>> +	#         the filesystem should persist the zeroed data in the gap
>> +	#         range as well.
>> +	if [ "$extend_cmd" != "${extend_cmd#pwrite}" ]; then
>> +		$XFS_IO_PROG -c "sync_range -w $blksz $blksz" \
>> +			"$file" >> $seqres.full 2>&1
>> +	fi
>> +	_scratch_shutdown -f
>> +
>> +	# Step 8: Remount and verify gap is still zeroed
>> +	_scratch_cycle_mount
>> +	_check_gap_zero "$file" $eof_offset $gap_bytes "after shutdown+remount" || return 1
>> +}
>> +
>> +_scratch_mkfs >> $seqres.full 2>&1
>> +_scratch_mount
>> +
>> +blksz=$(_get_block_size $SCRATCH_MNT)
>> +
>> +# Test three variants of EOF-extending operations
>> +_test_eof_zeroing "append_write" "pwrite -S 0x42 $blksz $blksz"
>> +_test_eof_zeroing "truncate_up" "truncate $((blksz * 2))"
>> +_test_eof_zeroing "fallocate" "falloc $blksz $blksz"
>> +
>> +# success, all done
>> +status=0
>> +exit
>> diff --git a/tests/generic/790.out b/tests/generic/790.out
>> new file mode 100644
>> index 00000000..e5e2cc09
>> --- /dev/null
>> +++ b/tests/generic/790.out
>> @@ -0,0 +1,4 @@
>> +QA output created by 790
>> +append_write
>> +truncate_up
>> +fallocate
>> -- 
>> 2.52.0
>>
>>


^ permalink raw reply

* Re: [PATCH v9 10/17] cifs: Implement fileattr_get for case sensitivity
From: Chuck Lever @ 2026-04-23  1:35 UTC (permalink / raw)
  To: Steve French
  Cc: Alexander Viro, Christian Brauner, Jan Kara, linux-fsdevel,
	linux-ext4, linux-xfs, linux-cifs, linux-nfs, linux-api,
	linux-f2fs-devel, OGAWA Hirofumi, Namjae Jeon, Sungjong Seo,
	Yuezhang Mo, almaz.alexandrovich, Viacheslav Dubeyko,
	John Paul Adrian 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
In-Reply-To: <CAH2r5muvUVY8FD6ZM+ARecM8evjejB15n0Ea9Z=GGn=i5aKFNA@mail.gmail.com>


On Wed, Apr 22, 2026, at 8:59 PM, Steve French wrote:
> Acked-by: Steve French <stfrench@microsoft.com>
>
> Do you know which xfstests this would enable?  IIRC a few of them
> depend on the fs supporting fileattr_get

Thanks for the Ack.

I checked the current xfstests tree and couldn’t find a test that flips
from notrun to run on cifs just from adding ->fileattr_get. generic/556
is the existing case-folding test, but _has_casefold_kernel_support in
common/casefold hard-codes ext4/f2fs/tmpfs. Enabling it on cifs would
need a new mechanism in common/casefold plus a mount-option-driven
variant (the cifs reporting keys off nocase, not a per-inode flag), so
that's a separate piece of work.

The practical effect on the existing suite is that fsstress's getattr_f
now returns success instead of ENOTTY on cifs, which quiets some noise
but doesn't gate any test. To actually exercise the new FS_XFLAG_CASEFOLD
reporting I think a new test (or a generalization of generic/556) would
have to be written.


-- 
Chuck Lever

^ permalink raw reply

* Re: [PATCH v9 10/17] cifs: Implement fileattr_get for case sensitivity
From: Steve French @ 2026-04-23  0:59 UTC (permalink / raw)
  To: Chuck Lever
  Cc: Al Viro, Christian Brauner, Jan Kara, 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: <20260422-case-sensitivity-v9-10-be023cc070e2@oracle.com>

Acked-by: Steve French <stfrench@microsoft.com>

Do you know which xfstests this would enable?  IIRC a few of them
depend on the fs supporting fileattr_get

On Wed, Apr 22, 2026 at 6:34 PM Chuck Lever <cel@kernel.org> wrote:
>
> 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 2025739f070a..9b70ffa3e01d 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"
> @@ -1199,6 +1200,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);
> +
> +       /*
> +        * The nocase mount option installs case-insensitive dentry
> +        * operations on this superblock. SMB preserves case on the
> +        * wire and at rest, so the mount matches FS_XFLAG_CASEFOLD
> +        * semantics: case-folded lookup, verbatim storage.
> +        */
> +       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,
> @@ -1217,6 +1234,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 = {
> @@ -1227,6 +1245,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,
> @@ -1261,6 +1280,7 @@ const struct inode_operations cifs_symlink_inode_ops = {
>         .setattr = cifs_setattr,
>         .permission = cifs_permission,
>         .listxattr = cifs_listxattr,
> +       .fileattr_get = cifs_fileattr_get,
>  };
>
>  /*
>
> --
> 2.53.0
>
>


-- 
Thanks,

Steve

^ permalink raw reply

* Re: [PATCH v9 01/17] fs: Move file_kattr initialization to callers
From: Darrick J. Wong @ 2026-04-22 23:38 UTC (permalink / raw)
  To: Chuck Lever
  Cc: Al Viro, Christian Brauner, Jan Kara, 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: <20260422-case-sensitivity-v9-1-be023cc070e2@oracle.com>

On Wed, Apr 22, 2026 at 07:29:55PM -0400, Chuck Lever wrote:
> From: Chuck Lever <chuck.lever@oracle.com>
> 
> fileattr_fill_xflags() and fileattr_fill_flags() memset the
> entire file_kattr struct before populating select fields, so
> callers cannot pre-set fields in fa->fsx_xflags without having
> their values clobbered. Darrick Wong noted that a function
> named "fill_xflags" touching more than xflags forces callers
> to know implementation details beyond its apparent scope.
> 
> Drop the memset from both fill functions and initialize at the
> entry points instead: ioctl_setflags(), ioctl_fssetxattr(),
> the file_setattr() syscall, and xfs_ioc_fsgetxattra() now
> declare fa with an aggregate initializer. ioctl_getflags(),
> ioctl_fsgetxattr(), and the file_getattr() syscall already
> aggregate-initialize fa to pass flags_valid/fsx_valid hints
> into vfs_fileattr_get().
> 
> Subsequent patches rely on this so that ->fileattr_get()
> handlers can set case-sensitivity flags (FS_XFLAG_CASEFOLD,
> FS_XFLAG_CASENONPRESERVING) in fa->fsx_xflags before the fill
> functions run.
> 
> Suggested-by: Darrick J. Wong <djwong@kernel.org>
> Reviewed-by: Jan Kara <jack@suse.cz>
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>

Heh, I never did review this one so 
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>

--D

> ---
>  fs/file_attr.c     | 12 ++++--------
>  fs/xfs/xfs_ioctl.c |  2 +-
>  2 files changed, 5 insertions(+), 9 deletions(-)
> 
> diff --git a/fs/file_attr.c b/fs/file_attr.c
> index da983e105d70..f429da66a317 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)
> @@ -48,11 +46,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)
> @@ -325,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;
>  
> @@ -357,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);
> @@ -431,7 +427,7 @@ SYSCALL_DEFINE5(file_setattr, int, dfd, const char __user *, filename,
>  	struct path filepath __free(path_put) = {};
>  	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 46e234863644..ed9b4846c05f 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -517,7 +517,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);
> 
> -- 
> 2.53.0
> 
> 

^ permalink raw reply

* [RFC PATCH 4/4] httpdirfs: enable fuse systemd service mode
From: Darrick J. Wong @ 2026-04-22 23:32 UTC (permalink / raw)
  To: linux-fsdevel, linux-ext4, fuse-devel
  Cc: Miklos Szeredi, Bernd Schubert, Joanne Koong, Theodore Ts'o,
	Neal Gompa, Amir Goldstein, Christian Brauner, demiobenour
In-Reply-To: <20260422231518.GA7717@frogsfrogsfrogs>

From: Darrick J. Wong <djwong@kernel.org>

Enable use of httpdirfs as a contained systemd service.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 src/fuse_local.h          |    2 +
 meson.build               |   26 ++++++++++++
 src/fuse_local.c          |   62 ++++++++++++++++++++++++++++
 src/httpdirfs.socket.in   |   16 +++++++
 src/httpdirfs@.service.in |   99 +++++++++++++++++++++++++++++++++++++++++++++
 src/main.c                |    7 +++
 6 files changed, 210 insertions(+), 2 deletions(-)
 create mode 100644 src/httpdirfs.socket.in
 create mode 100644 src/httpdirfs@.service.in

diff --git a/src/fuse_local.h b/src/fuse_local.h
index 9f459c1e1a8151..69157cd3fa7883 100644
--- a/src/fuse_local.h
+++ b/src/fuse_local.h
@@ -9,4 +9,6 @@
 /* Initialise fuse */
 int fuse_local_init(int argc, char **argv);
 
+int fuse_local_main(int argc, char *argv[], int (*main)(int argc, char **argv));
+
 #endif
diff --git a/meson.build b/meson.build
index 431a1547b20bfc..5d7c4721bb756c 100644
--- a/meson.build
+++ b/meson.build
@@ -41,6 +41,32 @@ expat_dep = dependency('expat')
 openssl_dep = dependency('openssl')
 execinfo_dep = cc.find_library('execinfo', required: false)
 
+# Check for systemd support
+systemd_dep = dependency('systemd', required: false)
+if systemd_dep.found()
+   systemd_system_unit_dir = systemd_dep.get_variable(pkgconfig: 'systemd_system_unit_dir', default_value: '')
+   libfuse_service_socket_dir = fuse_dep.get_variable(pkgconfig: 'service_socket_dir', default_value: '')
+   libfuse_service_socket_perms = fuse_dep.get_variable(pkgconfig: 'service_socket_perms', default_value: '')
+endif
+
+private_cfg = configuration_data()
+if systemd_system_unit_dir == '' or libfuse_service_socket_dir == ''
+  warning('systemd service support will not be built')
+else
+   private_cfg.set('SYSTEMD_SYSTEM_UNIT_DIR', systemd_system_unit_dir)
+   private_cfg.set('LIBFUSE_SERVICE_SOCKET_DIR', libfuse_service_socket_dir)
+   private_cfg.set('LIBFUSE_SERVICE_SOCKET_PERMS', libfuse_service_socket_perms)
+   private_cfg.set('BINDIR', get_option('bindir'))
+   c_args += [ '-DHAVE_HTTPDIR_FUSE_SERVICE' ]
+
+   configure_file(input: 'src/httpdirfs@.service.in',
+                  output: 'httpdirfs@.service',
+                  configuration: private_cfg)
+   configure_file(input: 'src/httpdirfs.socket.in',
+                  output: 'httpdirfs.socket',
+                  configuration: private_cfg)
+endif
+
 httpdirfs = executable('httpdirfs',
     srcs,
     dependencies : [gumbo_dep, libcurl_dep, fuse_dep, uuid_dep, expat_dep, openssl_dep, execinfo_dep],
diff --git a/src/fuse_local.c b/src/fuse_local.c
index ae9778f84e6ef3..c373bd67214335 100644
--- a/src/fuse_local.c
+++ b/src/fuse_local.c
@@ -6,13 +6,58 @@
 /*
  * must be included before including <fuse.h>
  */
-#define FUSE_USE_VERSION 30
+#define FUSE_USE_VERSION 319
 #include <fuse.h>
 
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
 
+#ifdef HAVE_HTTPDIR_FUSE_SERVICE
+# include <sys/mount.h>
+# include <fuse_service.h>
+
+static struct fuse_service *service;
+
+static inline bool fs_is_service(void)
+{
+	return fuse_service_accepted(service);
+}
+
+static int fs_service_connect(struct fuse_args *args)
+{
+	int ret;
+
+	ret = fuse_service_accept(&service);
+	if (ret)
+		return ret;
+
+	if (fuse_service_accepted(service))
+		return fuse_service_append_args(service, args);
+
+	return 0;
+}
+
+static int fs_service_run(int argc, char **argv,
+			  const struct fuse_operations *fs_oper)
+{
+	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+	int exitcode;
+
+	fuse_service_expect_mount_format(service, S_IFDIR);
+	exitcode = fuse_service_main(service, &args, fs_oper, NULL);
+
+	fuse_service_send_goodbye(service, exitcode);
+	fuse_service_destroy(&service);
+
+	return fuse_service_exit(exitcode);
+}
+#else
+# define fs_is_service(...)		(false)
+# define fs_service_connect(...)	(0)
+# define fs_service_run(...)		(1)
+#endif /* HAVE_HTTPDIR_FUSE_SERVICE */
+
 static void *fs_init(struct fuse_conn_info *conn, struct fuse_config *cfg)
 {
     (void) conn;
@@ -183,5 +228,20 @@ static struct fuse_operations fs_oper = {
 
 int fuse_local_init(int argc, char **argv)
 {
+    if (fs_is_service())
+        return fs_service_run(argc, argv, &fs_oper);
+
     return fuse_main(argc, argv, &fs_oper, NULL);
 }
+
+int fuse_local_main(int argc, char *argv[], int (*main)(int argc, char **argv))
+{
+	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+	int ret;
+
+	ret = fs_service_connect(&args);
+	if (ret)
+		return ret;
+
+	return main(args.argc, args.argv);
+}
diff --git a/src/httpdirfs.socket.in b/src/httpdirfs.socket.in
new file mode 100644
index 00000000000000..ae587646ad707e
--- /dev/null
+++ b/src/httpdirfs.socket.in
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2026 Oracle.  All Rights Reserved.
+# Author: Darrick J. Wong <djwong@kernel.org>
+[Unit]
+Description=Socket for httpdirfs Service
+
+[Socket]
+ListenSequentialPacket=@LIBFUSE_SERVICE_SOCKET_DIR@/http
+ListenSequentialPacket=@LIBFUSE_SERVICE_SOCKET_DIR@/https
+Accept=yes
+SocketMode=@LIBFUSE_SERVICE_SOCKET_PERMS@
+RemoveOnStop=yes
+
+[Install]
+WantedBy=sockets.target
diff --git a/src/httpdirfs@.service.in b/src/httpdirfs@.service.in
new file mode 100644
index 00000000000000..d808feca3238d7
--- /dev/null
+++ b/src/httpdirfs@.service.in
@@ -0,0 +1,99 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2026 Oracle.  All Rights Reserved.
+# Author: Darrick J. Wong <djwong@kernel.org>
+[Unit]
+Description=httpdirfs Service
+
+# Don't leave failed units behind, systemd does not clean them up!
+CollectMode=inactive-or-failed
+
+[Service]
+Type=exec
+ExecStart=/@BINDIR@/httpdirfs
+
+# Try to capture core dumps
+LimitCORE=infinity
+
+SyslogIdentifier=%N
+
+# No realtime CPU scheduling
+RestrictRealtime=true
+
+# Don't let us see anything in the regular system, and don't run as root
+DynamicUser=true
+ProtectSystem=strict
+ProtectHome=true
+PrivateTmp=true
+PrivateDevices=true
+PrivateUsers=true
+
+# Some network access
+ProtectHostname=true
+
+# Don't let the program mess with the kernel configuration at all
+ProtectKernelLogs=true
+ProtectKernelModules=true
+ProtectKernelTunables=true
+ProtectControlGroups=true
+ProtectProc=invisible
+RestrictNamespaces=true
+RestrictFileSystems=
+
+# Hide everything in /proc, even /proc/mounts
+ProcSubset=pid
+
+# Only allow the default personality Linux
+LockPersonality=true
+
+# No writable memory pages
+MemoryDenyWriteExecute=true
+
+# Don't let our mounts leak out to the host
+PrivateMounts=true
+
+# Restrict system calls to the native arch and only enough to get things going
+SystemCallArchitectures=native
+SystemCallFilter=@system-service
+#SystemCallFilter=~@privileged	# not sure why this breaks http??
+SystemCallFilter=~@resources
+
+SystemCallFilter=~@clock
+SystemCallFilter=~@cpu-emulation
+SystemCallFilter=~@debug
+SystemCallFilter=~@module
+SystemCallFilter=~@reboot
+SystemCallFilter=~@swap
+
+SystemCallFilter=~@mount
+
+# libfuse io_uring wants to pin cores and memory
+SystemCallFilter=mbind
+SystemCallFilter=sched_setaffinity
+
+# Leave a breadcrumb if we get whacked by the system call filter
+SystemCallErrorNumber=EL3RST
+
+# Log to the kernel dmesg, just like an in-kernel ext4 driver
+StandardOutput=append:/dev/ttyprintk
+StandardError=append:/dev/ttyprintk
+
+# Run with no capabilities at all
+CapabilityBoundingSet=
+AmbientCapabilities=
+NoNewPrivileges=true
+
+# fuse4fs doesn't create files
+UMask=7777
+
+# No access to hardware /dev files at all
+ProtectClock=true
+DevicePolicy=closed
+
+# Don't mess with set[ug]id anything.
+RestrictSUIDSGID=true
+
+# Don't let OOM kills of processes in this containment group kill the whole
+# service, because we don't want filesystem drivers to go down.
+OOMPolicy=continue
+OOMScoreAdjust=-1000
diff --git a/src/main.c b/src/main.c
index c93162a9bf4129..4c23d4e5d4419f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -16,7 +16,7 @@ void parse_config_file(char ***argv, int *argc);
 
 static char *config_path = NULL;
 
-int main(int argc, char **argv)
+static int __main(int argc, char **argv)
 {
     /*
      * Automatically print help if not enough arguments are supplied
@@ -114,6 +114,11 @@ activate Sonic mode.\n");
     return 0;
 }
 
+int main(int argc, char *argv[])
+{
+	return fuse_local_main(argc, argv, __main);
+}
+
 static char *get_XDG_CONFIG_HOME(void)
 {
     const char *default_config_subdir = "/.config";

^ permalink raw reply related

* [RFC PATCH 3/4] fuseiso: enable systemd service mode
From: Darrick J. Wong @ 2026-04-22 23:32 UTC (permalink / raw)
  To: linux-fsdevel, linux-ext4, fuse-devel
  Cc: Miklos Szeredi, Bernd Schubert, Joanne Koong, Theodore Ts'o,
	Neal Gompa, Amir Goldstein, Christian Brauner, demiobenour
In-Reply-To: <20260422231518.GA7717@frogsfrogsfrogs>

From: Darrick J. Wong <djwong@kernel.org>

Enable use of fuseiso as a contained fuse service.  This is a patch
against the Debian package, which was ported to fuse3.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
 src/isofs.h             |    2 -
 configure.in            |  148 +++++++++++++++++++++++++++++++++++++++++++++++
 src/Makefile.am         |   16 +++++
 src/fuseiso.c           |  134 +++++++++++++++++++++++++++++++++++++------
 src/fuseiso.socket.in   |   16 +++++
 src/fuseiso@.service.in |  102 ++++++++++++++++++++++++++++++++
 6 files changed, 398 insertions(+), 20 deletions(-)
 create mode 100644 src/fuseiso.socket.in
 create mode 100644 src/fuseiso@.service.in

diff --git a/src/isofs.h b/src/isofs.h
index 3755e886c9ccc2..b765baf209d77e 100644
--- a/src/isofs.h
+++ b/src/isofs.h
@@ -25,7 +25,7 @@
 #include <linux/iso_fs.h>
 #include <linux/rock.h>
 
-#define FUSE_USE_VERSION 314
+#define FUSE_USE_VERSION 319
 #include <fuse.h>
 
 typedef struct _isofs_context {
diff --git a/configure.in b/configure.in
index 9692dc114bfd73..30e2726cea8f2f 100644
--- a/configure.in
+++ b/configure.in
@@ -7,7 +7,153 @@ AC_LANG_C
 AC_PROG_CC
 AM_PROG_LIBTOOL
 
-PKG_CHECK_MODULES([FUSE],[fuse3 >= 3.14.0],[],[AC_MSG_ERROR([libfuse3 is required])])
+PKG_CHECK_MODULES([FUSE],[fuse3 >= 3.19.0],[have_fuse3_pkg=yes],[AC_MSG_ERROR([libfuse3 is required])])
 PKG_CHECK_MODULES([GLIB],[glib-2.0],[],[AC_MSG_ERROR([glib-2.0 is required])])
 
+dnl
+dnl Check if the FUSE library tells us where to put fs service sockets
+dnl
+have_fuse_service=
+fuse_service_socket_dir=
+if test -n "$have_fuse3_pkg"
+then
+	AC_ARG_WITH([fuse_service_socket_dir],
+	  [AS_HELP_STRING([--with-fuse-service-socket-dir@<:@=DIR@:>@],
+		  [Create fuse3 filesystem service sockets in DIR.])],
+	  [],
+	  [with_fuse_service_socket_dir=yes])
+	AS_IF([test "x${with_fuse_service_socket_dir}" != "xno"],
+	  [
+		AS_IF([test "x${with_fuse_service_socket_dir}" = "xyes"],
+		  [
+			AS_IF([test "x$have_fuse3_pkg" = "xyes" ],
+			  [
+				with_fuse_service_socket_dir="$($PKG_CONFIG --variable=service_socket_dir fuse3)"
+			  ], [
+				with_fuse_service_socket_dir=""
+			  ])
+		  ])
+		AC_MSG_CHECKING([for fuse3 service socket dir])
+		fuse_service_socket_dir="${with_fuse_service_socket_dir}"
+		AS_IF([test -n "${fuse_service_socket_dir}"],
+		  [
+			AC_MSG_RESULT(${fuse_service_socket_dir})
+		  ],
+		  [
+			AC_MSG_RESULT(no)
+		  ])
+	  ],
+	  [])
+	AC_ARG_WITH([fuse_service_socket_perms],
+	  [AS_HELP_STRING([--with-fuse-service-socket-perms@<:@=MODE@:>@],
+		  [Create fuse3 filesystem service socket with these permissions.])],
+	  [],
+	  [with_fuse_service_socket_perms=yes])
+	AS_IF([test "x${with_fuse_service_socket_perms}" != "xno"],
+	  [
+		AS_IF([test "x${with_fuse_service_socket_perms}" = "xyes"],
+		  [
+			AS_IF([test "x$have_fuse3_pkg" = "xyes" ],
+			  [
+				with_fuse_service_socket_perms="$($PKG_CONFIG --variable=service_socket_perms fuse3)"
+			  ], [
+				with_fuse_service_socket_perms=""
+			  ])
+		  ])
+		fuse_service_socket_perms="${with_fuse_service_socket_perms}"
+	  ],
+	  [])
+
+	AC_MSG_CHECKING([for fuse_service_accept in libfuse])
+	old_cflags="$CFLAGS"
+	CFLAGS="$CFLAGS $FUSE_CFLAGS"
+	AC_LINK_IFELSE(
+	[	AC_LANG_PROGRAM([[
+	#define _GNU_SOURCE
+	#define _FILE_OFFSET_BITS	64
+	#define FUSE_USE_VERSION	319
+	#include <fuse_lowlevel.h>
+	#include <fuse_service.h>
+		]], [[
+	struct fuse_service *moo;
+	fuse_service_accepted(moo);
+		]])
+	], have_fuse_service_accept=yes
+	   AC_MSG_RESULT(yes),
+	   AC_MSG_RESULT(no))
+	CFLAGS="$old_cflags"
+
+	AC_MSG_CHECKING([for fuse3 service support])
+	AS_IF([test -n "${fuse_service_socket_dir}" && test "${have_fuse_service_accept}" = "yes"],
+	  [
+		AC_MSG_RESULT(yes)
+		have_fuse_service="yes"
+	  ],
+	  [
+		AC_MSG_RESULT(no)
+	  ])
+fi
+AC_SUBST(have_fuse_service)
+AC_SUBST(fuse_service_socket_dir)
+AC_SUBST(fuse_service_socket_perms)
+if test "$have_fuse_service" = yes
+then
+	AC_DEFINE(HAVE_FUSE_SERVICE, 1, [Define to 1 if fuse supports service])
+fi
+
+dnl
+dnl Where do systemd services go?
+dnl
+AC_ARG_WITH([systemd_unit_dir],
+  [AS_HELP_STRING([--with-systemd-unit-dir@<:@=DIR@:>@],
+	[Install systemd system units into DIR.])],
+  [],
+  [with_systemd_unit_dir=yes])
+AS_IF([test "x${with_systemd_unit_dir}" != "xno"],
+  [
+	AS_IF([test "x${with_systemd_unit_dir}" = "xyes"],
+	  [
+		PKG_CHECK_MODULES([systemd], [systemd],
+		  [
+			with_systemd_unit_dir="$($PKG_CONFIG --variable=systemdsystemunitdir systemd)"
+		  ], [
+			with_systemd_unit_dir=""
+		  ])
+		m4_pattern_allow([^PKG_(MAJOR|MINOR|BUILD|REVISION)$])
+	  ])
+	AC_MSG_CHECKING([for systemd system unit dir])
+	systemd_system_unit_dir="${with_systemd_unit_dir}"
+	AS_IF([test -n "${systemd_system_unit_dir}"],
+	  [
+		AC_MSG_RESULT(${systemd_system_unit_dir})
+		have_systemd="yes"
+	  ],
+	  [
+		AC_MSG_RESULT(no)
+		have_systemd="no"
+	  ])
+  ],
+  [
+	have_systemd="disabled"
+  ])
+AC_SUBST(have_systemd)
+AC_SUBST(systemd_system_unit_dir)
+
+AC_MSG_CHECKING([for fuseiso service support and systemd])
+AS_IF([test "${FUSE4FS_CMT}${have_fuse_service}${have_systemd}" = "yesyes"],
+      [
+           AC_MSG_RESULT(yes)
+           AC_DEFINE(HAVE_FUSEISO_FUSE_SERVICE, 1,
+                     [Define to 1 if fuseiso should be built with fuse service support])
+           have_fuseiso_fuse_service=yes
+           AM_CONDITIONAL(HAVE_FUSEISO_FUSE_SERVICE, [true])
+      ],
+      [
+           AC_MSG_RESULT(no)
+           AM_CONDITIONAL(HAVE_FUSEISO_FUSE_SERVICE, [false])
+           have_fuseiso_fuse_service=no
+      ]
+)
+AC_SUBST(have_fuseiso_service)
+
 AC_OUTPUT(Makefile src/Makefile zAppRun/Makefile)
diff --git a/src/Makefile.am b/src/Makefile.am
index cb05da8cd1653c..97cded13a71c96 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -8,4 +8,20 @@ INCLUDES= $(all_includes)
 fuseiso_LDFLAGS = $(all_libraries) $(FUSE_LIBS) $(GLIB_LIBS) -lz
 noinst_HEADERS = isofs.h
 
+if HAVE_FUSEISO_FUSE_SERVICE
+bin_SCRIPTS = fuseiso.socket fuseiso@.service
+endif
+
+fuseiso.socket: fuseiso.socket.in
+	sed \
+		-e "s|@FUSE3_SERVICE_SOCKET_DIR@|$(fuse_service_socket_dir)|g" \
+		-e "s|@FUSE3_SERVICE_SOCKET_PERMS@|$(fuse_service_socket_perms)|g" \
+		< $< > $@
+
+fuseiso@.service: fuseiso@.service.in
+	sed -e "s|@BINDIR@|$(bindir)|g" \
+		   < $< > $@
+
+EXTRA_PROGRAMS=$(SERVICE_FILES)
+
 AM_CFLAGS = -D_FILE_OFFSET_BITS=64 $(FUSE_CFLAGS) $(GLIB_CFLAGS) -Wall
diff --git a/src/fuseiso.c b/src/fuseiso.c
index 47b94c72161c5f..46b2a61429074b 100644
--- a/src/fuseiso.c
+++ b/src/fuseiso.c
@@ -38,12 +38,16 @@
 
 #include <linux/iso_fs.h>
 
-#define FUSE_USE_VERSION 314
+#define FUSE_USE_VERSION 319
 #include <fuse.h>
 
 #include <zlib.h>
 #include <locale.h>
 #include <langinfo.h>
+#ifdef HAVE_FUSEISO_FUSE_SERVICE
+# include <sys/mount.h>
+# include <fuse_service.h>
+#endif
 
 #include "isofs.h"
 
@@ -61,6 +65,78 @@ int maintain_mount_point;
 int maintain_mtab;
 char* iocharset;
 
+#ifdef HAVE_FUSEISO_FUSE_SERVICE
+static struct fuse_service *service;
+
+static inline bool isofs_is_service(void)
+{
+    return fuse_service_accepted(service);
+}
+
+static int isofs_service_connect(struct fuse_args *args)
+{
+    int ret;
+
+    ret = fuse_service_accept(&service);
+    if (ret)
+        return ret;
+
+    if (fuse_service_accepted(service))
+        return fuse_service_append_args(service, args);
+
+    return 0;
+}
+
+static int isofs_service_get_config(const char *device, int *fdp)
+{
+    int fd;
+    int ret;
+
+    ret = fuse_service_request_file(service, device, O_RDONLY, 0, 0);
+    if (ret)
+        return ret;
+
+    ret = fuse_service_receive_file(service, device, &fd);
+    if (ret)
+        return ret;
+
+    if (fd < 0) {
+        fprintf(stderr, "%s opening device: %s.\n", device,
+                strerror(-fd));
+        return -1;
+    }
+    *fdp = fd;
+
+    return fuse_service_finish_file_requests(service);
+}
+
+static int isofs_service_main(int fuseopts_cnt, char **fuseopts,
+                              const struct fuse_operations *ops)
+{
+    struct fuse_args args = FUSE_ARGS_INIT(fuseopts_cnt, fuseopts);
+
+    fuse_service_expect_mount_format(service, S_IFDIR);
+    return fuse_service_main(service, &args, ops, NULL);
+}
+
+static int isofs_service_finish(int exitcode)
+{
+    if (!isofs_is_service())
+        return exitcode;
+
+    fuse_service_send_goodbye(service, exitcode);
+    fuse_service_destroy(&service);
+
+    return fuse_service_exit(exitcode);
+}
+#else
+# define isofs_is_service(...)		(false)
+# define isofs_service_connect(...)	(0)
+# define isofs_service_get_config(...)	(EOPNOTSUPP)
+# define isofs_service_main(...)	(1)
+# define isofs_service_finish(ret)	(ret)
+#endif /* HAVE_FUSEISO_FUSE_SERVICE */
+
 char* normalize_name(const char* fname) {
     char* abs_fname = (char *) malloc(PATH_MAX);
     realpath(fname, abs_fname);
@@ -305,6 +381,8 @@ void usage(const char* prog) {
 
 int main(int argc, char *argv[])
 {
+    struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+
     setlocale(LC_ALL, ""); // set current locale for proper iocharset
     
     // defaults
@@ -315,10 +393,15 @@ int main(int argc, char *argv[])
     char **fuseopts = reallocarray(NULL, 1, sizeof(*fuseopts));
     fuseopts[0] = argv[0];
     size_t fuseopts_cnt = 1;
+    int rc;
+
+    rc = isofs_service_connect(&args);
+    if (rc)
+        exit(EXIT_FAILURE);
     
     int c;
     char *s;
-    while((c = getopt(argc, argv, "+npc:ho:sfdV")) > 0) {
+    while((c = getopt(args.argc, args.argv, "+npc:ho:sfdV")) > 0) {
         switch((char)c) {
             case 'n':
                 maintain_mtab = 0;
@@ -361,26 +444,35 @@ int main(int argc, char *argv[])
         };
     };
     
-    if((argc - optind) < 2) {
+    if((args.argc - optind) < 2) {
         usage(argv[0]);
         exit(EXIT_FAILURE);
     };
     
-    imagefile = normalize_name(argv[optind++]);
+    imagefile = normalize_name(args.argv[optind++]);
+
+    if (isofs_is_service()) {
+        maintain_mtab = 0;
+        maintain_mount_point = 0;
+
+        rc = isofs_service_get_config(imagefile, &image_fd);
+        if (rc || image_fd < 0)
+            exit(EXIT_FAILURE);
+    } else {
+        image_fd = open(imagefile, O_RDONLY);
+        if(image_fd == -1) {
+            fprintf(stderr, "Supplied image file name: \"%s\"\n", imagefile);
+            perror("Can`t open image file");
+            exit(EXIT_FAILURE);
+        };
+    }
     
-    image_fd = open(imagefile, O_RDONLY);
-    if(image_fd == -1) {
-        fprintf(stderr, "Supplied image file name: \"%s\"\n", imagefile);
-        perror("Can`t open image file");
-        exit(EXIT_FAILURE);
-    };
+    mount_point = normalize_name(args.argv[optind]);
     
-    mount_point = normalize_name(argv[optind]);
+    fuseopts = reallocarray(fuseopts, fuseopts_cnt + args.argc - optind, sizeof(*fuseopts));
     
-    fuseopts = reallocarray(fuseopts, fuseopts_cnt + argc - optind, sizeof(*fuseopts));
-    
-    while(optind < argc) {
-        fuseopts[fuseopts_cnt++] = argv[optind++];
+    while(optind < args.argc) {
+        fuseopts[fuseopts_cnt++] = args.argv[optind++];
     };
     
     if(!iocharset) {
@@ -395,7 +487,6 @@ int main(int argc, char *argv[])
         };
     };
     
-    int rc;
     if(maintain_mount_point) {
         rc = check_mount_point();
         if(rc != 0) {
@@ -412,6 +503,13 @@ int main(int argc, char *argv[])
     
     // will exit in case of failure
     rc = isofs_real_preinit(imagefile, image_fd);
-    
-    return fuse_main(fuseopts_cnt, fuseopts, &isofs_oper, NULL);
+    if (rc)
+        exit(EXIT_FAILURE);
+
+    if (isofs_is_service())
+        rc = isofs_service_main(fuseopts_cnt, fuseopts, &isofs_oper);
+    else
+        rc = fuse_main(fuseopts_cnt, fuseopts, &isofs_oper, NULL);
+
+    return isofs_service_finish(rc);
 };
diff --git a/src/fuseiso.socket.in b/src/fuseiso.socket.in
new file mode 100644
index 00000000000000..a2ea11e408fa81
--- /dev/null
+++ b/src/fuseiso.socket.in
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2026 Oracle.  All Rights Reserved.
+# Author: Darrick J. Wong <djwong@kernel.org>
+[Unit]
+Description=Socket for fuseiso Service
+
+[Socket]
+ListenSequentialPacket=@FUSE3_SERVICE_SOCKET_DIR@/isofs
+ListenSequentialPacket=@FUSE3_SERVICE_SOCKET_DIR@/iso9660
+Accept=yes
+SocketMode=@FUSE3_SERVICE_SOCKET_PERMS@
+RemoveOnStop=yes
+
+[Install]
+WantedBy=sockets.target
diff --git a/src/fuseiso@.service.in b/src/fuseiso@.service.in
new file mode 100644
index 00000000000000..7f2d8977ccf6a9
--- /dev/null
+++ b/src/fuseiso@.service.in
@@ -0,0 +1,102 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2026 Oracle.  All Rights Reserved.
+# Author: Darrick J. Wong <djwong@kernel.org>
+[Unit]
+Description=fuseiso Service
+
+# Don't leave failed units behind, systemd does not clean them up!
+CollectMode=inactive-or-failed
+
+[Service]
+Type=exec
+ExecStart=/@BINDIR@/fuseiso
+
+# Try to capture core dumps
+LimitCORE=infinity
+
+SyslogIdentifier=%N
+
+# No realtime CPU scheduling
+RestrictRealtime=true
+
+# Don't let us see anything in the regular system, and don't run as root
+DynamicUser=true
+ProtectSystem=strict
+ProtectHome=true
+PrivateTmp=true
+PrivateDevices=true
+PrivateUsers=true
+
+# No network access
+PrivateNetwork=true
+ProtectHostname=true
+RestrictAddressFamilies=none
+IPAddressDeny=any
+
+# Don't let the program mess with the kernel configuration at all
+ProtectKernelLogs=true
+ProtectKernelModules=true
+ProtectKernelTunables=true
+ProtectControlGroups=true
+ProtectProc=invisible
+RestrictNamespaces=true
+RestrictFileSystems=
+
+# Hide everything in /proc, even /proc/mounts
+ProcSubset=pid
+
+# Only allow the default personality Linux
+LockPersonality=true
+
+# No writable memory pages
+MemoryDenyWriteExecute=true
+
+# Don't let our mounts leak out to the host
+PrivateMounts=true
+
+# Restrict system calls to the native arch and only enough to get things going
+SystemCallArchitectures=native
+SystemCallFilter=@system-service
+SystemCallFilter=~@privileged
+SystemCallFilter=~@resources
+
+SystemCallFilter=~@clock
+SystemCallFilter=~@cpu-emulation
+SystemCallFilter=~@debug
+SystemCallFilter=~@module
+SystemCallFilter=~@reboot
+SystemCallFilter=~@swap
+
+SystemCallFilter=~@mount
+
+# libfuse io_uring wants to pin cores and memory
+SystemCallFilter=mbind
+SystemCallFilter=sched_setaffinity
+
+# Leave a breadcrumb if we get whacked by the system call filter
+SystemCallErrorNumber=EL3RST
+
+# Log to the kernel dmesg, just like an in-kernel ext4 driver
+StandardOutput=append:/dev/ttyprintk
+StandardError=append:/dev/ttyprintk
+
+# Run with no capabilities at all
+CapabilityBoundingSet=
+AmbientCapabilities=
+NoNewPrivileges=true
+
+# fuse4fs doesn't create files
+UMask=7777
+
+# No access to hardware /dev files at all
+ProtectClock=true
+DevicePolicy=closed
+
+# Don't mess with set[ug]id anything.
+RestrictSUIDSGID=true
+
+# Don't let OOM kills of processes in this containment group kill the whole
+# service, because we don't want filesystem drivers to go down.
+OOMPolicy=continue
+OOMScoreAdjust=-1000

^ permalink raw reply related

* [PATCH v9 17/17] ksmbd: Report filesystem case sensitivity via FS_ATTRIBUTE_INFORMATION
From: Chuck Lever @ 2026-04-22 23:30 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: <20260422-case-sensitivity-v9-0-be023cc070e2@oracle.com>

From: Chuck Lever <chuck.lever@oracle.com>

FS_ATTRIBUTE_INFORMATION responses have always reported
FILE_CASE_SENSITIVE_SEARCH and FILE_CASE_PRESERVED_NAMES
unconditionally. Case-insensitive filesystems like exFAT, and
casefolded directories on ext4 or f2fs, have no way to signal
their actual semantics to SMB clients.

Now that filesystems expose case behavior through ->fileattr_get,
query it via vfs_fileattr_get() and translate the FS_XFLAG_CASEFOLD
and FS_XFLAG_CASENONPRESERVING flags into the corresponding SMB
attributes. 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.

Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/smb/server/smb2pdu.c | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index ee32e61b6d3c..7e91b578ca28 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -14,6 +14,7 @@
 #include <linux/falloc.h>
 #include <linux/mount.h>
 #include <linux/filelock.h>
+#include <linux/fileattr.h>
 
 #include "glob.h"
 #include "smbfsctl.h"
@@ -5541,16 +5542,28 @@ 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 (!(fa.fsx_xflags & FS_XFLAG_CASEFOLD))
+			attrs |= FILE_CASE_SENSITIVE_SEARCH;
+		if (!(fa.fsx_xflags & FS_XFLAG_CASENONPRESERVING))
+			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,

-- 
2.53.0


^ permalink raw reply related

* [PATCH v9 16/17] nfsd: Implement NFSv4 FATTR4_CASE_INSENSITIVE and FATTR4_CASE_PRESERVING
From: Chuck Lever @ 2026-04-22 23:30 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: <20260422-case-sensitivity-v9-0-be023cc070e2@oracle.com>

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 | 25 +++++++++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 2a0946c630e1..961cd59756fb 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3158,6 +3158,8 @@ struct nfsd4_fattr_args {
 	u32			rdattr_err;
 	bool			contextsupport;
 	bool			ignore_crossmnt;
+	bool			case_insensitive;
+	bool			case_preserving;
 };
 
 typedef __be32(*nfsd4_enc_attr)(struct xdr_stream *xdr,
@@ -3356,6 +3358,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)
 {
@@ -3748,8 +3762,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,
@@ -3968,6 +3982,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(dentry, &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);

-- 
2.53.0


^ permalink raw reply related

* [PATCH v9 15/17] nfsd: Report export case-folding via NFSv3 PATHCONF
From: Chuck Lever @ 2026-04-22 23:30 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: <20260422-case-sensitivity-v9-0-be023cc070e2@oracle.com>

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 depends on commit ("fat: Implement fileattr_get for
case sensitivity"), 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      | 29 +++++++++++++++++++++++++++++
 fs/nfsd/vfs.h      |  3 +++
 3 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 42adc5461db0..7b094c5908f1 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.fh_dentry,
+						  &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 eafdf7b7890f..6a7c6a691f2a 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"
 
@@ -2891,3 +2892,31 @@ 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 dentry
+ * @dentry: dentry to query
+ * @case_insensitive: output, true if the filesystem is case-insensitive
+ * @case_preserving: output, true if the filesystem preserves case
+ *
+ * Filesystems without ->fileattr_get report POSIX defaults
+ * (case-sensitive, case-preserving). Outputs are unmodified on
+ * failure.
+ *
+ * Returns nfs_ok on success, or an nfserr on failure.
+ */
+__be32
+nfsd_get_case_info(struct dentry *dentry, bool *case_insensitive,
+		   bool *case_preserving)
+{
+	struct file_kattr fa = {};
+	int err;
+
+	err = vfs_fileattr_get(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 702a844f2106..abf33389ee81 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -156,6 +156,9 @@ __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 dentry *dentry,
+				   bool *case_insensitive,
+				   bool *case_preserving);
 
 __be32		nfsd_permission(struct svc_cred *cred, struct svc_export *exp,
 				struct dentry *dentry, int acc);

-- 
2.53.0


^ permalink raw reply related

* [PATCH v9 14/17] isofs: Implement fileattr_get for case sensitivity
From: Chuck Lever @ 2026-04-22 23:30 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: <20260422-case-sensitivity-v9-0-be023cc070e2@oracle.com>

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
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 | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 2fd9948d606e..bca3de5a235d 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -14,6 +14,7 @@
 #include <linux/gfp.h>
 #include <linux/filelock.h>
 #include "isofs.h"
+#include <linux/fileattr.h>
 
 int isofs_name_translate(struct iso_directory_record *de, char *new, struct inode *inode)
 {
@@ -267,6 +268,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);
+
+	if (sbi->s_check == 'r')
+		fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
+	return 0;
+}
+
 const struct file_operations isofs_dir_operations =
 {
 	.llseek = generic_file_llseek,
@@ -281,6 +291,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.53.0


^ permalink raw reply related

* [PATCH v9 13/17] vboxsf: Implement fileattr_get for case sensitivity
From: Chuck Lever @ 2026-04-22 23:30 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: <20260422-case-sensitivity-v9-0-be023cc070e2@oracle.com>

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
separate case-preserving property; leaving
FS_XFLAG_CASENONPRESERVING unset reports the POSIX-default
case-preserving behavior, which matches vboxsf semantics.

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  |  7 +++++++
 fs/vboxsf/utils.c  | 26 ++++++++++++++++++++++++++
 fs/vboxsf/vfsmod.h |  6 ++++++
 5 files changed, 44 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 7a7a3fbb2651..943953867e18 100644
--- a/fs/vboxsf/file.c
+++ b/fs/vboxsf/file.c
@@ -222,7 +222,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)
@@ -389,5 +390,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 a618cb093e00..a61fbab51d37 100644
--- a/fs/vboxsf/super.c
+++ b/fs/vboxsf/super.c
@@ -185,6 +185,13 @@ static int vboxsf_fill_super(struct super_block *sb, struct fs_context *fc)
 	if (err)
 		goto fail_unmap;
 
+	/*
+	 * A failed query leaves sbi->case_insensitive false, so the
+	 * mount defaults to reporting case-sensitive behavior. Do not
+	 * fail the mount over an advisory attribute.
+	 */
+	vboxsf_query_case_sensitive(sbi);
+
 	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 440e8c50629d..647a0ecb334a 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,28 @@ 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);
+
+	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.53.0


^ permalink raw reply related

* [RFC PATCH 2/4] exfat: enable fuse systemd service mode
From: Darrick J. Wong @ 2026-04-22 23:30 UTC (permalink / raw)
  To: linux-fsdevel, linux-ext4, fuse-devel
  Cc: Miklos Szeredi, Bernd Schubert, Joanne Koong, Theodore Ts'o,
	Neal Gompa, Amir Goldstein, Christian Brauner, demiobenour
In-Reply-To: <20260422231518.GA7717@frogsfrogsfrogs>

From: Darrick J. Wong <djwong@kernel.org>

Enable use of exfat as a contained systemd service.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
 libexfat/exfat.h       |    3 +
 configure.ac           |  150 ++++++++++++++++++++++++++++++++++++++++++++++++
 fuse/Makefile.am       |   16 +++++
 fuse/exfat.socket.in   |   15 +++++
 fuse/exfat@.service.in |  102 +++++++++++++++++++++++++++++++++
 fuse/main.c            |  131 ++++++++++++++++++++++++++++++++++++++++--
 libexfat/io.c          |   21 ++++++-
 libexfat/mount.c       |   19 +++++-
 8 files changed, 447 insertions(+), 10 deletions(-)
 create mode 100644 fuse/exfat.socket.in
 create mode 100644 fuse/exfat@.service.in

diff --git a/libexfat/exfat.h b/libexfat/exfat.h
index 9b9a682844c093..3023ecd53acd5b 100644
--- a/libexfat/exfat.h
+++ b/libexfat/exfat.h
@@ -147,6 +147,7 @@ void exfat_warn(const char* format, ...) PRINTF;
 void exfat_debug(const char* format, ...) PRINTF;
 
 struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode);
+struct exfat_dev* exfat_fdopen(int fd, const char* spec, enum exfat_mode mode);
 int exfat_close(struct exfat_dev* dev);
 int exfat_fsync(struct exfat_dev* dev);
 enum exfat_mode exfat_get_mode(const struct exfat_dev* dev);
@@ -225,6 +226,8 @@ int exfat_set_label(struct exfat* ef, const char* label);
 
 int exfat_soil_super_block(const struct exfat* ef);
 int exfat_mount(struct exfat* ef, const char* spec, const char* options);
+int exfat_mount_from(struct exfat* ef, int fd, const char* spec,
+		     const char* options);
 void exfat_unmount(struct exfat* ef);
 
 time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec,
diff --git a/configure.ac b/configure.ac
index ee62b88931b738..63e7327f7ee651 100644
--- a/configure.ac
+++ b/configure.ac
@@ -32,7 +32,7 @@ AM_PROG_AR
 AC_SYS_LARGEFILE
 AC_CANONICAL_HOST
 PKG_CHECK_MODULES([FUSE3], [fuse3],
-  [AC_DEFINE([FUSE_USE_VERSION], [30], [Required FUSE API version.])],
+  [have_fuse3_pkg=yes ; AC_DEFINE([FUSE_USE_VERSION], [319], [Required FUSE API version.])],
   [PKG_CHECK_MODULES([FUSE2], [fuse >= 2.6],
     [AC_DEFINE([FUSE_USE_VERSION], [26], [Required FUSE API version.])])])
 AC_MSG_CHECKING([whether host-specific configuration is needed for $host_os])
@@ -55,6 +55,154 @@ case "$host_os" in
     AC_MSG_RESULT([no])
 	;;
 esac
+
+
+dnl
+dnl Check if the FUSE library tells us where to put fs service sockets
+dnl
+have_fuse_service=
+fuse_service_socket_dir=
+if test -n "$have_fuse3_pkg"
+then
+	AC_ARG_WITH([fuse_service_socket_dir],
+	  [AS_HELP_STRING([--with-fuse-service-socket-dir@<:@=DIR@:>@],
+		  [Create fuse3 filesystem service sockets in DIR.])],
+	  [],
+	  [with_fuse_service_socket_dir=yes])
+	AS_IF([test "x${with_fuse_service_socket_dir}" != "xno"],
+	  [
+		AS_IF([test "x${with_fuse_service_socket_dir}" = "xyes"],
+		  [
+			AS_IF([test "x$have_fuse3_pkg" = "xyes" ],
+			  [
+				with_fuse_service_socket_dir="$($PKG_CONFIG --variable=service_socket_dir fuse3)"
+			  ], [
+				with_fuse_service_socket_dir=""
+			  ])
+		  ])
+		AC_MSG_CHECKING([for fuse3 service socket dir])
+		fuse_service_socket_dir="${with_fuse_service_socket_dir}"
+		AS_IF([test -n "${fuse_service_socket_dir}"],
+		  [
+			AC_MSG_RESULT(${fuse_service_socket_dir})
+		  ],
+		  [
+			AC_MSG_RESULT(no)
+		  ])
+	  ],
+	  [])
+	AC_ARG_WITH([fuse_service_socket_perms],
+	  [AS_HELP_STRING([--with-fuse-service-socket-perms@<:@=MODE@:>@],
+		  [Create fuse3 filesystem service socket with these permissions.])],
+	  [],
+	  [with_fuse_service_socket_perms=yes])
+	AS_IF([test "x${with_fuse_service_socket_perms}" != "xno"],
+	  [
+		AS_IF([test "x${with_fuse_service_socket_perms}" = "xyes"],
+		  [
+			AS_IF([test "x$have_fuse3_pkg" = "xyes" ],
+			  [
+				with_fuse_service_socket_perms="$($PKG_CONFIG --variable=service_socket_perms fuse3)"
+			  ], [
+				with_fuse_service_socket_perms=""
+			  ])
+		  ])
+		fuse_service_socket_perms="${with_fuse_service_socket_perms}"
+	  ],
+	  [])
+
+	AC_MSG_CHECKING([for fuse_service_accept in libfuse])
+	old_cflags="$CFLAGS"
+	CFLAGS="$CFLAGS $FUSE3_CFLAGS"
+	AC_LINK_IFELSE(
+	[	AC_LANG_PROGRAM([[
+	#define _GNU_SOURCE
+	#define _FILE_OFFSET_BITS	64
+	#define FUSE_USE_VERSION	319
+	#include <fuse_lowlevel.h>
+	#include <fuse_service.h>
+		]], [[
+	struct fuse_service *moo;
+	fuse_service_accepted(moo);
+		]])
+	], have_fuse_service_accept=yes
+	   AC_MSG_RESULT(yes),
+	   AC_MSG_RESULT(no))
+	CFLAGS="$old_cflags"
+
+	AC_MSG_CHECKING([for fuse3 service support])
+	AS_IF([test -n "${fuse_service_socket_dir}" && test "${have_fuse_service_accept}" = "yes"],
+	  [
+		AC_MSG_RESULT(yes)
+		have_fuse_service="yes"
+	  ],
+	  [
+		AC_MSG_RESULT(no)
+	  ])
+fi
+AC_SUBST(have_fuse_service)
+AC_SUBST(fuse_service_socket_dir)
+AC_SUBST(fuse_service_socket_perms)
+if test "$have_fuse_service" = yes
+then
+	AC_DEFINE(HAVE_FUSE_SERVICE, 1, [Define to 1 if fuse supports service])
+fi
+
+dnl
+dnl Where do systemd services go?
+dnl
+AC_ARG_WITH([systemd_unit_dir],
+  [AS_HELP_STRING([--with-systemd-unit-dir@<:@=DIR@:>@],
+	[Install systemd system units into DIR.])],
+  [],
+  [with_systemd_unit_dir=yes])
+AS_IF([test "x${with_systemd_unit_dir}" != "xno"],
+  [
+	AS_IF([test "x${with_systemd_unit_dir}" = "xyes"],
+	  [
+		PKG_CHECK_MODULES([systemd], [systemd],
+		  [
+			with_systemd_unit_dir="$($PKG_CONFIG --variable=systemdsystemunitdir systemd)"
+		  ], [
+			with_systemd_unit_dir=""
+		  ])
+		m4_pattern_allow([^PKG_(MAJOR|MINOR|BUILD|REVISION)$])
+	  ])
+	AC_MSG_CHECKING([for systemd system unit dir])
+	systemd_system_unit_dir="${with_systemd_unit_dir}"
+	AS_IF([test -n "${systemd_system_unit_dir}"],
+	  [
+		AC_MSG_RESULT(${systemd_system_unit_dir})
+		have_systemd="yes"
+	  ],
+	  [
+		AC_MSG_RESULT(no)
+		have_systemd="no"
+	  ])
+  ],
+  [
+	have_systemd="disabled"
+  ])
+AC_SUBST(have_systemd)
+AC_SUBST(systemd_system_unit_dir)
+
+AC_MSG_CHECKING([for exfat-fuse service support and systemd])
+AS_IF([test "${FUSE4FS_CMT}${have_fuse_service}${have_systemd}" = "yesyes"],
+      [
+           AC_MSG_RESULT(yes)
+           AC_DEFINE(HAVE_EXFAT_FUSE_SERVICE, 1,
+                     [Define to 1 if exfat should be built with fuse service support])
+           have_exfat_service=yes
+           AM_CONDITIONAL(HAVE_EXFAT_FUSE_SERVICE, [true])
+      ],
+      [
+           AC_MSG_RESULT(no)
+           AM_CONDITIONAL(HAVE_EXFAT_FUSE_SERVICE, [false])
+           have_exfat_service=no
+      ]
+)
+AC_SUBST(have_exfat_service)
+
 AC_CONFIG_HEADERS([libexfat/config.h])
 AC_CONFIG_FILES([
 	libexfat/Makefile
diff --git a/fuse/Makefile.am b/fuse/Makefile.am
index 09c8cac9f5d0ec..660b23ce1965fc 100644
--- a/fuse/Makefile.am
+++ b/fuse/Makefile.am
@@ -27,6 +27,22 @@ mount_exfat_fuse_CPPFLAGS = -imacros $(top_srcdir)/libexfat/config.h
 mount_exfat_fuse_CFLAGS = $(FUSE2_CFLAGS) $(FUSE3_CFLAGS) $(UBLIO_CFLAGS)
 mount_exfat_fuse_LDADD = $(top_srcdir)/libexfat/libexfat.a $(FUSE2_LIBS) $(FUSE3_LIBS) $(UBLIO_LIBS)
 
+if HAVE_EXFAT_FUSE_SERVICE
+bin_SCRIPTS = exfat.socket exfat@.service
+endif
+
+exfat.socket: exfat.socket.in
+	sed \
+		-e "s|@FUSE3_SERVICE_SOCKET_DIR@|$(fuse_service_socket_dir)|g" \
+		-e "s|@FUSE3_SERVICE_SOCKET_PERMS@|$(fuse_service_socket_perms)|g" \
+		< $< > $@
+
+exfat@.service: exfat@.service.in
+	sed -e "s|@SBINDIR@|$(sbindir)|g" \
+		   < $< > $@
+
+EXTRA_PROGRAMS=$(SERVICE_FILES)
+
 install-exec-hook:
 	ln -sf $(sbin_PROGRAMS) $(DESTDIR)$(sbindir)/mount.exfat
 
diff --git a/fuse/exfat.socket.in b/fuse/exfat.socket.in
new file mode 100644
index 00000000000000..8a957ad700fc16
--- /dev/null
+++ b/fuse/exfat.socket.in
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2026 Oracle.  All Rights Reserved.
+# Author: Darrick J. Wong <djwong@kernel.org>
+[Unit]
+Description=Socket for exfat Service
+
+[Socket]
+ListenSequentialPacket=@FUSE3_SERVICE_SOCKET_DIR@/exfat
+Accept=yes
+SocketMode=@FUSE3_SERVICE_SOCKET_PERMS@
+RemoveOnStop=yes
+
+[Install]
+WantedBy=sockets.target
diff --git a/fuse/exfat@.service.in b/fuse/exfat@.service.in
new file mode 100644
index 00000000000000..9b7855fe524de6
--- /dev/null
+++ b/fuse/exfat@.service.in
@@ -0,0 +1,102 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2026 Oracle.  All Rights Reserved.
+# Author: Darrick J. Wong <djwong@kernel.org>
+[Unit]
+Description=exfat Service
+
+# Don't leave failed units behind, systemd does not clean them up!
+CollectMode=inactive-or-failed
+
+[Service]
+Type=exec
+ExecStart=/@SBINDIR@/mount.exfat-fuse
+
+# Try to capture core dumps
+LimitCORE=infinity
+
+SyslogIdentifier=%N
+
+# No realtime CPU scheduling
+RestrictRealtime=true
+
+# Don't let us see anything in the regular system, and don't run as root
+DynamicUser=true
+ProtectSystem=strict
+ProtectHome=true
+PrivateTmp=true
+PrivateDevices=true
+PrivateUsers=true
+
+# No network access
+PrivateNetwork=true
+ProtectHostname=true
+RestrictAddressFamilies=none
+IPAddressDeny=any
+
+# Don't let the program mess with the kernel configuration at all
+ProtectKernelLogs=true
+ProtectKernelModules=true
+ProtectKernelTunables=true
+ProtectControlGroups=true
+ProtectProc=invisible
+RestrictNamespaces=true
+RestrictFileSystems=
+
+# Hide everything in /proc, even /proc/mounts
+ProcSubset=pid
+
+# Only allow the default personality Linux
+LockPersonality=true
+
+# No writable memory pages
+MemoryDenyWriteExecute=true
+
+# Don't let our mounts leak out to the host
+PrivateMounts=true
+
+# Restrict system calls to the native arch and only enough to get things going
+SystemCallArchitectures=native
+SystemCallFilter=@system-service
+SystemCallFilter=~@privileged
+SystemCallFilter=~@resources
+
+SystemCallFilter=~@clock
+SystemCallFilter=~@cpu-emulation
+SystemCallFilter=~@debug
+SystemCallFilter=~@module
+SystemCallFilter=~@reboot
+SystemCallFilter=~@swap
+
+SystemCallFilter=~@mount
+
+# libfuse io_uring wants to pin cores and memory
+SystemCallFilter=mbind
+SystemCallFilter=sched_setaffinity
+
+# Leave a breadcrumb if we get whacked by the system call filter
+SystemCallErrorNumber=EL3RST
+
+# Log to the kernel dmesg, just like an in-kernel ext4 driver
+StandardOutput=append:/dev/ttyprintk
+StandardError=append:/dev/ttyprintk
+
+# Run with no capabilities at all
+CapabilityBoundingSet=
+AmbientCapabilities=
+NoNewPrivileges=true
+
+# fuse4fs doesn't create files
+UMask=7777
+
+# No access to hardware /dev files at all
+ProtectClock=true
+DevicePolicy=closed
+
+# Don't mess with set[ug]id anything.
+RestrictSUIDSGID=true
+
+# Don't let OOM kills of processes in this containment group kill the whole
+# service, because we don't want filesystem drivers to go down.
+OOMPolicy=continue
+OOMScoreAdjust=-1000
diff --git a/fuse/main.c b/fuse/main.c
index cf1033a543f038..d7aa8d21db62e3 100644
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -34,6 +34,10 @@
 #include <sys/types.h>
 #include <pwd.h>
 #include <unistd.h>
+#ifdef HAVE_EXFAT_FUSE_SERVICE
+# include <sys/mount.h>
+# include <fuse_service.h>
+#endif
 
 #ifndef DEBUG
 	#define exfat_debug(format, ...) do {} while (0)
@@ -45,6 +49,102 @@
 
 struct exfat ef;
 
+#ifdef HAVE_EXFAT_FUSE_SERVICE
+static struct fuse_service *service;
+static int bdev_fd = -1;
+
+static inline bool fuse_exfat_is_service(void)
+{
+	return fuse_service_accepted(service);
+}
+
+static int fuse_exfat_service_connect(struct fuse_args *args)
+{
+	int ret;
+
+	ret = fuse_service_accept(&service);
+	if (ret)
+		return ret;
+
+	if (fuse_service_accepted(service))
+		return fuse_service_append_args(service, args);
+
+	return 0;
+}
+
+static int fuse_exfat_service_get_config(const char *device, bool ro)
+{
+	int open_flags = 0; /* fuseblk server means we can't open exclusive */
+	int fd;
+	int ret;
+
+	if (ro)
+		open_flags |= O_RDONLY;
+	else
+		open_flags |= O_SYNC | O_RDWR;
+
+	ret = fuse_service_request_file(service, device, open_flags, 0, 0);
+	if (ret)
+		return ret;
+
+	ret = fuse_service_receive_file(service, device, &fd);
+	if (ret)
+		return ret;
+
+	if (fd < 0) {
+		fprintf(stderr, "%s opening device: %s.\n", device,
+			   strerror(-fd));
+		return -1;
+	}
+	bdev_fd = fd;
+
+	return fuse_service_finish_file_requests(service);
+}
+
+static int fuse_exfat_service_mount(struct exfat *ef, const char *spec,
+				    const char *exfat_options)
+{
+	const int is_ro = exfat_match_option(exfat_options, "ro");
+	int rc;
+
+	rc = fuse_exfat_service_get_config(spec, is_ro);
+	if (rc)
+		return EXIT_FAILURE;
+
+	return exfat_mount_from(ef, bdev_fd, spec, exfat_options);
+}
+
+static int fuse_exfat_service_main(char **argv,
+				   const struct fuse_operations *ops)
+{
+	struct fuse_args args = FUSE_ARGS_INIT(0, argv);
+	char **p = argv;
+
+	while (*(p++) != NULL)
+		args.argc++;
+
+	fuse_service_expect_mount_format(service, S_IFDIR);
+	return fuse_service_main(service, &args, ops, NULL);
+}
+
+static int fuse_exfat_service_finish(int exitcode)
+{
+	if (!fuse_exfat_is_service())
+		return exitcode;
+
+	fuse_service_send_goodbye(service, exitcode);
+	fuse_service_destroy(&service);
+
+	return fuse_service_exit(exitcode);
+}
+#else
+# define fuse_exfat_is_service(...)		(false)
+# define fuse_exfat_service_connect(...)	(0)
+# define fuse_exfat_service_mount(...)		(1)
+# define fuse_exfat_service_main(...)		(1)
+# define fuse_exfat_service_finish(ret)		(ret)
+#endif /* HAVE_EXFAT_FUSE_SERVICE */
+
 static struct exfat_node* get_node(const struct fuse_file_info* fi)
 {
 	return (struct exfat_node*) (size_t) fi->fh;
@@ -529,6 +629,12 @@ static char* add_user_option(char* options)
 
 	if (getuid() == 0)
 		return options;
+	if (fuse_exfat_is_service()) {
+		options = add_option(options, "uid", "0");
+		if (!options)
+			return NULL;
+		return add_option(options, "gid", "0");
+	}
 
 	pw = getpwuid(getuid());
 	if (pw == NULL || pw->pw_name == NULL)
@@ -601,12 +707,17 @@ static char* add_passthrough_fuse_options(char* fuse_options,
 static int fuse_exfat_main(char* mount_options, char* mount_point)
 {
 	char* argv[] = {"exfat", "-s", "-o", mount_options, mount_point, NULL};
+
+	if (fuse_exfat_is_service())
+		return fuse_exfat_service_main(argv, &fuse_exfat_ops);
+
 	return fuse_main(sizeof(argv) / sizeof(argv[0]) - 1, argv,
 			&fuse_exfat_ops, NULL);
 }
 
 int main(int argc, char* argv[])
 {
+	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
 	const char* spec = NULL;
 	char* mount_point = NULL;
 	char* fuse_options;
@@ -633,7 +744,11 @@ int main(int argc, char* argv[])
 		return 1;
 	}
 
-	while ((opt = getopt(argc, argv, "dno:Vv")) != -1)
+	rc = fuse_exfat_service_connect(&args);
+	if (rc)
+		exit(EXIT_FAILURE);
+
+	while ((opt = getopt(args.argc, args.argv, "dno:Vv")) != -1)
 	{
 		switch (opt)
 		{
@@ -675,16 +790,20 @@ int main(int argc, char* argv[])
 			break;
 		}
 	}
-	if (argc - optind != 2)
+	if (args.argc - optind != 2)
 	{
 		free(exfat_options);
 		free(fuse_options);
 		usage(argv[0]);
 	}
-	spec = argv[optind];
-	mount_point = argv[optind + 1];
+	spec = args.argv[optind];
+	mount_point = args.argv[optind + 1];
 
-	if (exfat_mount(&ef, spec, exfat_options) != 0)
+	if (fuse_exfat_is_service())
+		rc = fuse_exfat_service_mount(&ef, spec, exfat_options);
+	else
+		rc = exfat_mount(&ef, spec, exfat_options);
+	if (rc != 0)
 	{
 		free(exfat_options);
 		free(fuse_options);
@@ -704,5 +823,5 @@ int main(int argc, char* argv[])
 	rc = fuse_exfat_main(fuse_options, mount_point);
 
 	free(fuse_options);
-	return rc;
+	return fuse_exfat_service_finish(rc);
 }
diff --git a/libexfat/io.c b/libexfat/io.c
index 7af5316da70b4b..2a4c823979a9a8 100644
--- a/libexfat/io.c
+++ b/libexfat/io.c
@@ -86,7 +86,8 @@ static int open_rw(const char* spec)
 	return fd;
 }
 
-struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)
+static struct exfat_dev* __exfat_open(int fd, const char* spec,
+				      enum exfat_mode mode)
 {
 	struct exfat_dev* dev;
 	struct stat stbuf;
@@ -119,6 +120,10 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)
 		return NULL;
 	}
 
+	dev->fd = fd;
+	if (dev->fd >= 0)
+		goto opened;
+
 	switch (mode)
 	{
 	case EXFAT_MODE_RO:
@@ -162,6 +167,7 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)
 		return NULL;
 	}
 
+opened:
 	if (fstat(dev->fd, &stbuf) != 0)
 	{
 		close(dev->fd);
@@ -284,6 +290,19 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)
 	return dev;
 }
 
+struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)
+{
+	return __exfat_open(-1, spec, mode);
+}
+
+struct exfat_dev* exfat_fdopen(int fd, const char* spec, enum exfat_mode mode)
+{
+	if (fd < 0)
+		return NULL;
+
+	return __exfat_open(fd, spec, mode);
+}
+
 int exfat_close(struct exfat_dev* dev)
 {
 	int rc = 0;
diff --git a/libexfat/mount.c b/libexfat/mount.c
index 86fb84db2445f5..dd6cf707d2ebbc 100644
--- a/libexfat/mount.c
+++ b/libexfat/mount.c
@@ -180,7 +180,8 @@ static void exfat_free(struct exfat* ef)
 	ef->sb = NULL;
 }
 
-int exfat_mount(struct exfat* ef, const char* spec, const char* options)
+static int __exfat_mount(struct exfat* ef, int fd, const char* spec,
+			 const char* options)
 {
 	int rc;
 	enum exfat_mode mode;
@@ -196,7 +197,10 @@ int exfat_mount(struct exfat* ef, const char* spec, const char* options)
 		mode = EXFAT_MODE_ANY;
 	else
 		mode = EXFAT_MODE_RW;
-	ef->dev = exfat_open(spec, mode);
+	if (fd >= 0)
+		ef->dev = exfat_fdopen(fd, spec, mode);
+	else
+		ef->dev = exfat_open(spec, mode);
 	if (ef->dev == NULL)
 		return -ENODEV;
 	if (exfat_get_mode(ef->dev) == EXFAT_MODE_RO)
@@ -340,6 +344,17 @@ int exfat_mount(struct exfat* ef, const char* spec, const char* options)
 	return -EIO;
 }
 
+int exfat_mount_from(struct exfat* ef, int fd, const char* spec,
+		     const char* options)
+{
+	return __exfat_mount(ef, fd, spec, options);
+}
+
+int exfat_mount(struct exfat* ef, const char* spec, const char* options)
+{
+	return __exfat_mount(ef, -1, spec, options);
+}
+
 static void finalize_super_block(struct exfat* ef)
 {
 	if (ef->ro)

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox