public inbox for linux-fsdevel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] fat: Add FS_IOC_GETFSLABEL / FS_IOC_SETFSLABEL ioctls
@ 2026-02-17 23:06 Ethan Ferguson
  2026-02-17 23:06 ` [PATCH v2 1/2] fat: Add FS_IOC_GETFSLABEL ioctl Ethan Ferguson
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Ethan Ferguson @ 2026-02-17 23:06 UTC (permalink / raw)
  To: hirofumi; +Cc: linux-fsdevel, linux-kernel, Ethan Ferguson

Add support for reading / writing to the volume label of a FAT filesystem
via the FS_IOC_GETFSLABEL and FS_IOC_SETFSLABEL ioctls.

Volume label changes are persisted in the volume label dentry in the root
directory as well as the bios parameter block.

v2:
* Create volume label dentry if not present
* Respect msdos shortname rules
* Add locking
* Fixed bugs (EFAULT from copy_to_user, uninitialized buffer_head)

Ethan Ferguson (2):
  fat: Add FS_IOC_GETFSLABEL ioctl
  fat: Add FS_IOC_SETFSLABEL ioctl

 fs/fat/dir.c         | 51 ++++++++++++++++++++++++++++
 fs/fat/fat.h         |  7 ++++
 fs/fat/file.c        | 79 ++++++++++++++++++++++++++++++++++++++++++++
 fs/fat/inode.c       | 26 +++++++++++++--
 fs/fat/namei_msdos.c |  4 +--
 5 files changed, 163 insertions(+), 4 deletions(-)

base-commit: 9f2693489ef8558240d9e80bfad103650daed0af
-- 
2.43.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 1/2] fat: Add FS_IOC_GETFSLABEL ioctl
  2026-02-17 23:06 [PATCH v2 0/2] fat: Add FS_IOC_GETFSLABEL / FS_IOC_SETFSLABEL ioctls Ethan Ferguson
@ 2026-02-17 23:06 ` Ethan Ferguson
  2026-02-17 23:06 ` [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl Ethan Ferguson
  2026-02-18  8:46 ` [syzbot ci] Re: fat: Add FS_IOC_GETFSLABEL / FS_IOC_SETFSLABEL ioctls syzbot ci
  2 siblings, 0 replies; 11+ messages in thread
From: Ethan Ferguson @ 2026-02-17 23:06 UTC (permalink / raw)
  To: hirofumi; +Cc: linux-fsdevel, linux-kernel, Ethan Ferguson

Add support for reading the volume label of a FAT filesystem via the
FS_IOC_GETFSLABEL ioctl.

Signed-off-by: Ethan Ferguson <ethan.ferguson@zetier.com>
---
 fs/fat/fat.h   |  1 +
 fs/fat/file.c  | 16 ++++++++++++++++
 fs/fat/inode.c | 11 +++++++++--
 3 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 0d269dba897b..4350c00dba34 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -89,6 +89,7 @@ struct msdos_sb_info {
 	int dir_per_block;	      /* dir entries per block */
 	int dir_per_block_bits;	      /* log2(dir_per_block) */
 	unsigned int vol_id;		/*volume ID*/
+	char vol_label[MSDOS_NAME];           /* volume label */
 
 	int fatent_shift;
 	const struct fatent_operations *fatent_ops;
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 124d9c5431c8..029b1750d1ec 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -153,6 +153,20 @@ static int fat_ioctl_fitrim(struct inode *inode, unsigned long arg)
 	return 0;
 }
 
+static int fat_ioctl_get_volume_label(struct super_block *sb, char __user *arg)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	int ret;
+
+	mutex_lock(&sbi->s_lock);
+	ret = copy_to_user(arg, sbi->vol_label, MSDOS_NAME);
+	mutex_unlock(&sbi->s_lock);
+	if (ret)
+		return -EFAULT;
+
+	return 0;
+}
+
 long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	struct inode *inode = file_inode(filp);
@@ -165,6 +179,8 @@ long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 		return fat_ioctl_set_attributes(filp, user_attr);
 	case FAT_IOCTL_GET_VOLUME_ID:
 		return fat_ioctl_get_volume_id(inode, user_attr);
+	case FS_IOC_GETFSLABEL:
+		return fat_ioctl_get_volume_label(inode->i_sb, (char __user *) arg);
 	case FITRIM:
 		return fat_ioctl_fitrim(inode, arg);
 	default:
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 59fa90617b5b..6f9a8cc1ad2a 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -53,12 +53,14 @@ struct fat_bios_param_block {
 
 	u8	fat16_state;
 	u32	fat16_vol_id;
+	u8	fat16_vol_label[MSDOS_NAME];
 
 	u32	fat32_length;
 	u32	fat32_root_cluster;
 	u16	fat32_info_sector;
 	u8	fat32_state;
 	u32	fat32_vol_id;
+	u8	fat32_vol_label[MSDOS_NAME];
 };
 
 static int fat_default_codepage = CONFIG_FAT_DEFAULT_CODEPAGE;
@@ -1406,12 +1408,14 @@ static int fat_read_bpb(struct super_block *sb, struct fat_boot_sector *b,
 
 	bpb->fat16_state = b->fat16.state;
 	bpb->fat16_vol_id = get_unaligned_le32(b->fat16.vol_id);
+	memcpy(bpb->fat16_vol_label, b->fat16.vol_label, MSDOS_NAME);
 
 	bpb->fat32_length = le32_to_cpu(b->fat32.length);
 	bpb->fat32_root_cluster = le32_to_cpu(b->fat32.root_cluster);
 	bpb->fat32_info_sector = le16_to_cpu(b->fat32.info_sector);
 	bpb->fat32_state = b->fat32.state;
 	bpb->fat32_vol_id = get_unaligned_le32(b->fat32.vol_id);
+	memcpy(bpb->fat32_vol_label, b->fat32.vol_label, MSDOS_NAME);
 
 	/* Validate this looks like a FAT filesystem BPB */
 	if (!bpb->fat_reserved) {
@@ -1708,10 +1712,13 @@ int fat_fill_super(struct super_block *sb, struct fs_context *fc,
 	}
 
 	/* interpret volume ID as a little endian 32 bit integer */
-	if (is_fat32(sbi))
+	if (is_fat32(sbi)) {
 		sbi->vol_id = bpb.fat32_vol_id;
-	else /* fat 16 or 12 */
+		memcpy(sbi->vol_label, bpb.fat32_vol_label, MSDOS_NAME);
+	} else { /* fat 16 or 12 */
 		sbi->vol_id = bpb.fat16_vol_id;
+		memcpy(sbi->vol_label, bpb.fat16_vol_label, MSDOS_NAME);
+	}
 
 	__le32 vol_id_le = cpu_to_le32(sbi->vol_id);
 	super_set_uuid(sb, (void *) &vol_id_le, sizeof(vol_id_le));
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl
  2026-02-17 23:06 [PATCH v2 0/2] fat: Add FS_IOC_GETFSLABEL / FS_IOC_SETFSLABEL ioctls Ethan Ferguson
  2026-02-17 23:06 ` [PATCH v2 1/2] fat: Add FS_IOC_GETFSLABEL ioctl Ethan Ferguson
@ 2026-02-17 23:06 ` Ethan Ferguson
  2026-02-18  6:50   ` kernel test robot
                     ` (4 more replies)
  2026-02-18  8:46 ` [syzbot ci] Re: fat: Add FS_IOC_GETFSLABEL / FS_IOC_SETFSLABEL ioctls syzbot ci
  2 siblings, 5 replies; 11+ messages in thread
From: Ethan Ferguson @ 2026-02-17 23:06 UTC (permalink / raw)
  To: hirofumi; +Cc: linux-fsdevel, linux-kernel, Ethan Ferguson

Add support for writing to the volume label of a FAT filesystem via the
FS_IOC_SETFSLABEL ioctl.

Signed-off-by: Ethan Ferguson <ethan.ferguson@zetier.com>
---
 fs/fat/dir.c         | 51 +++++++++++++++++++++++++++++++++++
 fs/fat/fat.h         |  6 +++++
 fs/fat/file.c        | 63 ++++++++++++++++++++++++++++++++++++++++++++
 fs/fat/inode.c       | 15 +++++++++++
 fs/fat/namei_msdos.c |  4 +--
 5 files changed, 137 insertions(+), 2 deletions(-)

diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 07d95f1442c8..1b11713309ae 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -1425,3 +1425,54 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
 	return err;
 }
 EXPORT_SYMBOL_GPL(fat_add_entries);
+
+static int fat_create_volume_label_dentry(struct super_block *sb, char *vol_label)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct inode *root_inode = sb->s_root->d_inode;
+	struct msdos_dir_entry de;
+	struct fat_slot_info sinfo;
+	struct timespec64 ts = current_time(root_inode);
+	__le16 date, time;
+	u8 time_cs;
+
+	memcpy(de.name, vol_label, MSDOS_NAME);
+	de.attr = ATTR_VOLUME;
+	de.starthi = de.start = de.size = de.lcase = 0;
+
+	fat_time_unix2fat(sbi, &ts, &time, &date, &time_cs);
+	de.time = time;
+	de.date = date;
+	if (sbi->options.isvfat) {
+		de.cdate = de.adate = date;
+		de.ctime = time;
+		de.ctime_cs = time_cs;
+	} else
+		de.cdate = de.adate = de.ctime = de.ctime_cs = 0;
+
+	return fat_add_entries(root_inode, &de, 1, &sinfo);
+}
+
+int fat_rename_volume_label_dentry(struct super_block *sb, char *vol_label)
+{
+	struct inode *root_inode = sb->s_root->d_inode;
+	struct buffer_head *bh = NULL;
+	struct msdos_dir_entry *de;
+	loff_t cpos = 0;
+	int err = 0;
+
+	while (1) {
+		if (fat_get_entry(root_inode, &cpos, &bh, &de) == -1)
+			return fat_create_volume_label_dentry(sb, vol_label);
+
+		if (de->attr == ATTR_VOLUME) {
+			memcpy(de->name, vol_label, MSDOS_NAME);
+			mark_buffer_dirty_inode(bh, root_inode);
+			if (IS_DIRSYNC(root_inode))
+				err = sync_dirty_buffer(bh);
+			brelse(bh);
+			return err;
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(fat_rename_volume_label_dentry);
diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 4350c00dba34..3b75223fbe76 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -341,6 +341,8 @@ extern int fat_alloc_new_dir(struct inode *dir, struct timespec64 *ts);
 extern int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
 			   struct fat_slot_info *sinfo);
 extern int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo);
+extern int fat_rename_volume_label_dentry(struct super_block *sb,
+					  char *vol_label);
 
 /* fat/fatent.c */
 struct fat_entry {
@@ -480,6 +482,10 @@ extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs);
 int fat_cache_init(void);
 void fat_cache_destroy(void);
 
+/* fat/namei/msdos.c */
+int msdos_format_name(const unsigned char *name, int len,
+		      unsigned char *res, struct fat_mount_options *opts);
+
 /* fat/nfs.c */
 extern const struct export_operations fat_export_ops;
 extern const struct export_operations fat_export_ops_nostale;
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 029b1750d1ec..5d445c2d8657 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -167,6 +167,67 @@ static int fat_ioctl_get_volume_label(struct super_block *sb, char __user *arg)
 	return 0;
 }
 
+static int fat_convert_volume_label_str(struct msdos_sb_info *sbi, char *in,
+					char *out)
+{
+	int ret, in_len = max(strnlen(in, FSLABEL_MAX), 11);
+	char *needle;
+
+	/*
+	 * '.' is not included in any bad_chars list in this driver,
+	 * but it is specifically not allowed for volume labels
+	 */
+	for (needle = in; needle - in < in_len; needle++)
+		if (*needle == '.')
+			return -EINVAL;
+
+	ret = msdos_format_name(in, in_len, out, &sbi->options);
+	if (ret)
+		return ret;
+
+	/*
+	 * msdos_format_name assumes we're translating an 8.3 name, but
+	 * we can handle 11 chars
+	 */
+	if (in_len > 8)
+		ret = msdos_format_name(in + 8, in_len - 8, out + 8,
+					&sbi->options);
+	return ret;
+}
+
+static int fat_ioctl_set_volume_label(struct super_block *sb, char __user *arg)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct inode *root_inode = sb->s_root->d_inode;
+	char from_user[FSLABEL_MAX];
+	char new_vol_label[MSDOS_NAME];
+	int ret;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (sb_rdonly(sb))
+		return -EROFS;
+
+	if (copy_from_user(from_user, arg, FSLABEL_MAX))
+		return -EFAULT;
+
+	ret = fat_convert_volume_label_str(sbi, from_user, new_vol_label);
+	if (ret)
+		return ret;
+
+	inode_lock(root_inode);
+	ret = fat_rename_volume_label_dentry(sb, new_vol_label);
+	inode_unlock(root_inode);
+	if (ret)
+		return ret;
+
+	mutex_lock(&sbi->s_lock);
+	memcpy(sbi->vol_label, new_vol_label, MSDOS_NAME);
+	mutex_unlock(&sbi->s_lock);
+	return 0;
+}
+
 long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	struct inode *inode = file_inode(filp);
@@ -181,6 +242,8 @@ long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 		return fat_ioctl_get_volume_id(inode, user_attr);
 	case FS_IOC_GETFSLABEL:
 		return fat_ioctl_get_volume_label(inode->i_sb, (char __user *) arg);
+	case FS_IOC_SETFSLABEL:
+		return fat_ioctl_set_volume_label(inode->i_sb, (char __user *) arg);
 	case FITRIM:
 		return fat_ioctl_fitrim(inode, arg);
 	default:
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 6f9a8cc1ad2a..a7528937383b 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -736,6 +736,21 @@ static void delayed_free(struct rcu_head *p)
 static void fat_put_super(struct super_block *sb)
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
+	struct buffer_head *bh = NULL;
+	struct fat_boot_sector *bs;
+
+	bh = sb_bread(sb, 0);
+	if (bh == NULL)
+		fat_msg(sb, KERN_ERR, "unable to read boot sector");
+	else if (!sb_rdonly(sb)) {
+		bs = (struct fat_boot_sector *)bh->b_data;
+		if (is_fat32(sbi))
+			memcpy(bs->fat32.vol_label, sbi->vol_label, MSDOS_NAME);
+		else
+			memcpy(bs->fat16.vol_label, sbi->vol_label, MSDOS_NAME);
+		mark_buffer_dirty(bh);
+	}
+	brelse(bh);
 
 	fat_set_state(sb, 0, 0);
 
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
index ba0152ed0810..92b5d387f88e 100644
--- a/fs/fat/namei_msdos.c
+++ b/fs/fat/namei_msdos.c
@@ -16,8 +16,8 @@ static unsigned char bad_chars[] = "*?<>|\"";
 static unsigned char bad_if_strict[] = "+=,; ";
 
 /***** Formats an MS-DOS file name. Rejects invalid names. */
-static int msdos_format_name(const unsigned char *name, int len,
-			     unsigned char *res, struct fat_mount_options *opts)
+int msdos_format_name(const unsigned char *name, int len, unsigned char *res,
+		      struct fat_mount_options *opts)
 	/*
 	 * name is the proposed name, len is its length, res is
 	 * the resulting name, opts->name_check is either (r)elaxed,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl
  2026-02-17 23:06 ` [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl Ethan Ferguson
@ 2026-02-18  6:50   ` kernel test robot
  2026-02-18  7:21   ` kernel test robot
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: kernel test robot @ 2026-02-18  6:50 UTC (permalink / raw)
  To: Ethan Ferguson, hirofumi
  Cc: oe-kbuild-all, linux-fsdevel, linux-kernel, Ethan Ferguson

Hi Ethan,

kernel test robot noticed the following build errors:

[auto build test ERROR on 9f2693489ef8558240d9e80bfad103650daed0af]

url:    https://github.com/intel-lab-lkp/linux/commits/Ethan-Ferguson/fat-Add-FS_IOC_GETFSLABEL-ioctl/20260218-071019
base:   9f2693489ef8558240d9e80bfad103650daed0af
patch link:    https://lore.kernel.org/r/20260217230628.719475-3-ethan.ferguson%40zetier.com
patch subject: [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl
config: arm-vexpress_defconfig (https://download.01.org/0day-ci/archive/20260218/202602181429.zMfoW0eg-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260218/202602181429.zMfoW0eg-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602181429.zMfoW0eg-lkp@intel.com/

All errors (new ones prefixed by >>):

   arm-linux-gnueabi-ld: fs/fat/file.o: in function `fat_convert_volume_label_str':
   fs/fat/file.c:184:(.text+0x14c): undefined reference to `msdos_format_name'
>> arm-linux-gnueabi-ld: fs/fat/file.c:193:(.text+0x168): undefined reference to `msdos_format_name'

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl
  2026-02-17 23:06 ` [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl Ethan Ferguson
  2026-02-18  6:50   ` kernel test robot
@ 2026-02-18  7:21   ` kernel test robot
  2026-02-18  7:22   ` OGAWA Hirofumi
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: kernel test robot @ 2026-02-18  7:21 UTC (permalink / raw)
  To: Ethan Ferguson, hirofumi
  Cc: oe-kbuild-all, linux-fsdevel, linux-kernel, Ethan Ferguson

Hi Ethan,

kernel test robot noticed the following build errors:

[auto build test ERROR on 9f2693489ef8558240d9e80bfad103650daed0af]

url:    https://github.com/intel-lab-lkp/linux/commits/Ethan-Ferguson/fat-Add-FS_IOC_GETFSLABEL-ioctl/20260218-071019
base:   9f2693489ef8558240d9e80bfad103650daed0af
patch link:    https://lore.kernel.org/r/20260217230628.719475-3-ethan.ferguson%40zetier.com
patch subject: [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl
config: i386-randconfig-014-20260218 (https://download.01.org/0day-ci/archive/20260218/202602181513.zGRm1yrD-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260218/202602181513.zGRm1yrD-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602181513.zGRm1yrD-lkp@intel.com/

All errors (new ones prefixed by >>):

   ld: fs/fat/file.o: in function `fat_convert_volume_label_str':
   fs/fat/file.c:184:(.text+0x108): undefined reference to `msdos_format_name'
>> ld: fs/fat/file.c:193:(.text+0x12a): undefined reference to `msdos_format_name'

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl
  2026-02-17 23:06 ` [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl Ethan Ferguson
  2026-02-18  6:50   ` kernel test robot
  2026-02-18  7:21   ` kernel test robot
@ 2026-02-18  7:22   ` OGAWA Hirofumi
  2026-02-18 10:22   ` kernel test robot
  2026-02-18 16:26   ` kernel test robot
  4 siblings, 0 replies; 11+ messages in thread
From: OGAWA Hirofumi @ 2026-02-18  7:22 UTC (permalink / raw)
  To: Ethan Ferguson; +Cc: linux-fsdevel, linux-kernel

Ethan Ferguson <ethan.ferguson@zetier.com> writes:

> Add support for writing to the volume label of a FAT filesystem via the
> FS_IOC_SETFSLABEL ioctl.
>
> Signed-off-by: Ethan Ferguson <ethan.ferguson@zetier.com>
> ---
>  fs/fat/dir.c         | 51 +++++++++++++++++++++++++++++++++++
>  fs/fat/fat.h         |  6 +++++
>  fs/fat/file.c        | 63 ++++++++++++++++++++++++++++++++++++++++++++
>  fs/fat/inode.c       | 15 +++++++++++
>  fs/fat/namei_msdos.c |  4 +--
>  5 files changed, 137 insertions(+), 2 deletions(-)
>
> diff --git a/fs/fat/dir.c b/fs/fat/dir.c
> index 07d95f1442c8..1b11713309ae 100644
> --- a/fs/fat/dir.c
> +++ b/fs/fat/dir.c
> @@ -1425,3 +1425,54 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
>  	return err;
>  }
>  EXPORT_SYMBOL_GPL(fat_add_entries);
> +
> +static int fat_create_volume_label_dentry(struct super_block *sb, char *vol_label)
> +{
> +	struct msdos_sb_info *sbi = MSDOS_SB(sb);
> +	struct inode *root_inode = sb->s_root->d_inode;
> +	struct msdos_dir_entry de;
> +	struct fat_slot_info sinfo;
> +	struct timespec64 ts = current_time(root_inode);
> +	__le16 date, time;
> +	u8 time_cs;
> +
> +	memcpy(de.name, vol_label, MSDOS_NAME);
> +	de.attr = ATTR_VOLUME;
> +	de.starthi = de.start = de.size = de.lcase = 0;
> +
> +	fat_time_unix2fat(sbi, &ts, &time, &date, &time_cs);
> +	de.time = time;
> +	de.date = date;
> +	if (sbi->options.isvfat) {
> +		de.cdate = de.adate = date;
> +		de.ctime = time;
> +		de.ctime_cs = time_cs;
> +	} else
> +		de.cdate = de.adate = de.ctime = de.ctime_cs = 0;
> +
> +	return fat_add_entries(root_inode, &de, 1, &sinfo);
> +}
> +
> +int fat_rename_volume_label_dentry(struct super_block *sb, char *vol_label)
> +{
> +	struct inode *root_inode = sb->s_root->d_inode;
> +	struct buffer_head *bh = NULL;
> +	struct msdos_dir_entry *de;
> +	loff_t cpos = 0;
> +	int err = 0;
> +
> +	while (1) {
> +		if (fat_get_entry(root_inode, &cpos, &bh, &de) == -1)
> +			return fat_create_volume_label_dentry(sb, vol_label);
> +
> +		if (de->attr == ATTR_VOLUME) {
> +			memcpy(de->name, vol_label, MSDOS_NAME);
> +			mark_buffer_dirty_inode(bh, root_inode);
> +			if (IS_DIRSYNC(root_inode))
> +				err = sync_dirty_buffer(bh);
> +			brelse(bh);
> +			return err;
> +		}
> +	}

I didn't check how to know the label though, the label is only if
ATTR_VOLUME? IOW, any other attributes are disallowed?

What if label is marked as deleted?

I'm not sure though, no need to update timestamps? (need to investigate
spec or windows behavior)

> +static int fat_convert_volume_label_str(struct msdos_sb_info *sbi, char *in,
> +					char *out)
> +{
> +	int ret, in_len = max(strnlen(in, FSLABEL_MAX), 11);
> +	char *needle;

Silently truncate is the common way for this ioctl?

> +	/*
> +	 * '.' is not included in any bad_chars list in this driver,
> +	 * but it is specifically not allowed for volume labels
> +	 */
> +	for (needle = in; needle - in < in_len; needle++)
> +		if (*needle == '.')
> +			return -EINVAL;

memchr() or such?

> +	ret = msdos_format_name(in, in_len, out, &sbi->options);
> +	if (ret)
> +		return ret;

> +	/*
> +	 * msdos_format_name assumes we're translating an 8.3 name, but
> +	 * we can handle 11 chars
> +	 */
> +	if (in_len > 8)
> +		ret = msdos_format_name(in + 8, in_len - 8, out + 8,
> +					&sbi->options);
> +	return ret;

fat module should not import msdos module.

> +static int fat_ioctl_set_volume_label(struct super_block *sb, char __user *arg)
> +{
> +	struct msdos_sb_info *sbi = MSDOS_SB(sb);
> +	struct inode *root_inode = sb->s_root->d_inode;
> +	char from_user[FSLABEL_MAX];
> +	char new_vol_label[MSDOS_NAME];
> +	int ret;
> +
> +	if (!capable(CAP_SYS_ADMIN))
> +		return -EPERM;
> +
> +	if (sb_rdonly(sb))
> +		return -EROFS;
> +
> +	if (copy_from_user(from_user, arg, FSLABEL_MAX))
> +		return -EFAULT;
> +
> +	ret = fat_convert_volume_label_str(sbi, from_user, new_vol_label);
> +	if (ret)
> +		return ret;
> +
> +	inode_lock(root_inode);
> +	ret = fat_rename_volume_label_dentry(sb, new_vol_label);
> +	inode_unlock(root_inode);
> +	if (ret)
> +		return ret;

This rename will have to take same or similar locks with rename(2)?

> diff --git a/fs/fat/inode.c b/fs/fat/inode.c
> index 6f9a8cc1ad2a..a7528937383b 100644
> --- a/fs/fat/inode.c
> +++ b/fs/fat/inode.c
> @@ -736,6 +736,21 @@ static void delayed_free(struct rcu_head *p)
>  static void fat_put_super(struct super_block *sb)
>  {
>  	struct msdos_sb_info *sbi = MSDOS_SB(sb);
> +	struct buffer_head *bh = NULL;
> +	struct fat_boot_sector *bs;
> +
> +	bh = sb_bread(sb, 0);
> +	if (bh == NULL)
> +		fat_msg(sb, KERN_ERR, "unable to read boot sector");
> +	else if (!sb_rdonly(sb)) {
> +		bs = (struct fat_boot_sector *)bh->b_data;
> +		if (is_fat32(sbi))
> +			memcpy(bs->fat32.vol_label, sbi->vol_label, MSDOS_NAME);
> +		else
> +			memcpy(bs->fat16.vol_label, sbi->vol_label, MSDOS_NAME);
> +		mark_buffer_dirty(bh);
> +	}
> +	brelse(bh);

Why this unconditionally update the vol_label at unmount?

Thanks.
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [syzbot ci] Re: fat: Add FS_IOC_GETFSLABEL / FS_IOC_SETFSLABEL ioctls
  2026-02-17 23:06 [PATCH v2 0/2] fat: Add FS_IOC_GETFSLABEL / FS_IOC_SETFSLABEL ioctls Ethan Ferguson
  2026-02-17 23:06 ` [PATCH v2 1/2] fat: Add FS_IOC_GETFSLABEL ioctl Ethan Ferguson
  2026-02-17 23:06 ` [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl Ethan Ferguson
@ 2026-02-18  8:46 ` syzbot ci
  2 siblings, 0 replies; 11+ messages in thread
From: syzbot ci @ 2026-02-18  8:46 UTC (permalink / raw)
  To: ethan.ferguson, hirofumi, linux-fsdevel, linux-kernel
  Cc: syzbot, syzkaller-bugs

syzbot ci has tested the following series

[v2] fat: Add FS_IOC_GETFSLABEL / FS_IOC_SETFSLABEL ioctls
https://lore.kernel.org/all/20260217230628.719475-1-ethan.ferguson@zetier.com
* [PATCH v2 1/2] fat: Add FS_IOC_GETFSLABEL ioctl
* [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl

and found the following issue:
KASAN: stack-out-of-bounds Write in msdos_format_name

Full report is available here:
https://ci.syzbot.org/series/da73a18c-15c6-438b-8ee3-f34978d4930c

***

KASAN: stack-out-of-bounds Write in msdos_format_name

tree:      bpf-next
URL:       https://kernel.googlesource.com/pub/scm/linux/kernel/git/bpf/bpf-next.git
base:      9f2693489ef8558240d9e80bfad103650daed0af
arch:      amd64
compiler:  Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8
config:    https://ci.syzbot.org/builds/972e08c3-3f0c-4dc8-b311-d7aec3efb56b/config
C repro:   https://ci.syzbot.org/findings/f100bebc-8929-4992-996b-73c5de2585ba/c_repro
syz repro: https://ci.syzbot.org/findings/f100bebc-8929-4992-996b-73c5de2585ba/syz_repro

loop0: rw=8912896, sector=1192, nr_sectors = 4 limit=256
syz.0.17: attempt to access beyond end of device
loop0: rw=8388608, sector=1192, nr_sectors = 4 limit=256
==================================================================
BUG: KASAN: stack-out-of-bounds in msdos_format_name+0x5fe/0xd90 fs/fat/namei_msdos.c:69
Write of size 1 at addr ffffc90003a27dcb by task syz.0.17/5956

CPU: 0 UID: 0 PID: 5956 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full) 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
Call Trace:
 <TASK>
 dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
 print_address_description mm/kasan/report.c:378 [inline]
 print_report+0xba/0x230 mm/kasan/report.c:482
 kasan_report+0x117/0x150 mm/kasan/report.c:595
 msdos_format_name+0x5fe/0xd90 fs/fat/namei_msdos.c:69
 fat_convert_volume_label_str fs/fat/file.c:193 [inline]
 fat_ioctl_set_volume_label fs/fat/file.c:215 [inline]
 fat_generic_ioctl+0xebd/0x12a0 fs/fat/file.c:246
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:583
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xe2/0xf80 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fa55ed9bf79
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ffe3b0c1748 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007fa55f015fa0 RCX: 00007fa55ed9bf79
RDX: 0000200000000240 RSI: 0000000041009432 RDI: 0000000000000004
RBP: 00007fa55ee327e0 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007fa55f015fac R14: 00007fa55f015fa0 R15: 00007fa55f015fa0
 </TASK>

The buggy address belongs to stack of task syz.0.17/5956
 and is located at offset 427 in frame:
 fat_generic_ioctl+0x0/0x12a0

This frame has 4 objects:
 [32, 56) 'range.i'
 [96, 352) 'from_user.i'
 [416, 427) 'new_vol_label.i'
 [448, 528) 'ia.i'

The buggy address belongs to a 8-page vmalloc region starting at 0xffffc90003a20000 allocated at copy_process+0x508/0x3980 kernel/fork.c:2052
The buggy address belongs to the physical page:
page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x1750f7
memcg:ffff888111b31502
flags: 0x57ff00000000000(node=1|zone=2|lastcpupid=0x7ff)
raw: 057ff00000000000 0000000000000000 dead000000000122 0000000000000000
raw: 0000000000000000 0000000000000000 00000001ffffffff ffff888111b31502
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0x29c2(GFP_NOWAIT|__GFP_HIGHMEM|__GFP_IO|__GFP_FS|__GFP_ZERO), pid 41, tgid 41 (kworker/u10:2), ts 69338575178, free_ts 66424269276
 set_page_owner include/linux/page_owner.h:32 [inline]
 post_alloc_hook+0x228/0x280 mm/page_alloc.c:1884
 prep_new_page mm/page_alloc.c:1892 [inline]
 get_page_from_freelist+0x24dc/0x2580 mm/page_alloc.c:3945
 __alloc_frozen_pages_noprof+0x18d/0x380 mm/page_alloc.c:5240
 alloc_pages_mpol+0x232/0x4a0 mm/mempolicy.c:2486
 alloc_frozen_pages_noprof mm/mempolicy.c:2557 [inline]
 alloc_pages_noprof+0xa8/0x190 mm/mempolicy.c:2577
 vm_area_alloc_pages mm/vmalloc.c:3649 [inline]
 __vmalloc_area_node mm/vmalloc.c:3863 [inline]
 __vmalloc_node_range_noprof+0x79b/0x1730 mm/vmalloc.c:4051
 __vmalloc_node_noprof+0xc2/0x100 mm/vmalloc.c:4111
 alloc_thread_stack_node kernel/fork.c:354 [inline]
 dup_task_struct+0x228/0x9a0 kernel/fork.c:923
 copy_process+0x508/0x3980 kernel/fork.c:2052
 kernel_clone+0x248/0x870 kernel/fork.c:2651
 user_mode_thread+0x110/0x180 kernel/fork.c:2727
 call_usermodehelper_exec_sync kernel/umh.c:132 [inline]
 call_usermodehelper_exec_work+0x9c/0x230 kernel/umh.c:163
 process_one_work kernel/workqueue.c:3257 [inline]
 process_scheduled_works+0xaec/0x17a0 kernel/workqueue.c:3340
 worker_thread+0xda6/0x1360 kernel/workqueue.c:3421
 kthread+0x726/0x8b0 kernel/kthread.c:463
 ret_from_fork+0x51b/0xa40 arch/x86/kernel/process.c:158
page last free pid 5918 tgid 5918 stack trace:
 reset_page_owner include/linux/page_owner.h:25 [inline]
 free_pages_prepare mm/page_alloc.c:1433 [inline]
 __free_frozen_pages+0xbf8/0xd70 mm/page_alloc.c:2973
 discard_slab mm/slub.c:3346 [inline]
 __put_partials+0x146/0x170 mm/slub.c:3886
 __slab_free+0x294/0x320 mm/slub.c:5956
 qlink_free mm/kasan/quarantine.c:163 [inline]
 qlist_free_all+0x97/0x100 mm/kasan/quarantine.c:179
 kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
 __kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:350
 kasan_slab_alloc include/linux/kasan.h:253 [inline]
 slab_post_alloc_hook mm/slub.c:4953 [inline]
 slab_alloc_node mm/slub.c:5263 [inline]
 __kmalloc_cache_noprof+0x36f/0x6e0 mm/slub.c:5775
 kmalloc_noprof include/linux/slab.h:957 [inline]
 kzalloc_noprof include/linux/slab.h:1094 [inline]
 ref_tracker_alloc+0x161/0x4d0 lib/ref_tracker.c:271
 __netdev_tracker_alloc include/linux/netdevice.h:4400 [inline]
 netdev_hold include/linux/netdevice.h:4429 [inline]
 netdev_queue_add_kobject net/core/net-sysfs.c:1994 [inline]
 netdev_queue_update_kobjects+0x1d1/0x6c0 net/core/net-sysfs.c:2056
 register_queue_kobjects net/core/net-sysfs.c:2119 [inline]
 netdev_register_kobject+0x258/0x310 net/core/net-sysfs.c:2362
 register_netdevice+0x12a0/0x1cd0 net/core/dev.c:11406
 register_netdev+0x40/0x60 net/core/dev.c:11522
 loopback_net_init+0x75/0x150 drivers/net/loopback.c:218
 ops_init+0x35c/0x5c0 net/core/net_namespace.c:137
 setup_net+0x118/0x340 net/core/net_namespace.c:446
 copy_net_ns+0x50e/0x730 net/core/net_namespace.c:581

Memory state around the buggy address:
 ffffc90003a27c80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 ffffc90003a27d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>ffffc90003a27d80: f2 f2 f2 f2 f2 f2 f2 f2 00 03 f2 f2 f8 f8 f8 f8
                                              ^
 ffffc90003a27e00: f8 f8 f8 f8 f8 f8 f3 f3 f3 f3 f3 f3 00 00 00 00
 ffffc90003a27e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
==================================================================


***

If these findings have caused you to resend the series or submit a
separate fix, please add the following tag to your commit message:
  Tested-by: syzbot@syzkaller.appspotmail.com

---
This report is generated by a bot. It may contain errors.
syzbot ci engineers can be reached at syzkaller@googlegroups.com.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl
  2026-02-17 23:06 ` [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl Ethan Ferguson
                     ` (2 preceding siblings ...)
  2026-02-18  7:22   ` OGAWA Hirofumi
@ 2026-02-18 10:22   ` kernel test robot
  2026-02-18 16:26   ` kernel test robot
  4 siblings, 0 replies; 11+ messages in thread
From: kernel test robot @ 2026-02-18 10:22 UTC (permalink / raw)
  To: Ethan Ferguson, hirofumi
  Cc: oe-kbuild-all, linux-fsdevel, linux-kernel, Ethan Ferguson

Hi Ethan,

kernel test robot noticed the following build errors:

[auto build test ERROR on 9f2693489ef8558240d9e80bfad103650daed0af]

url:    https://github.com/intel-lab-lkp/linux/commits/Ethan-Ferguson/fat-Add-FS_IOC_GETFSLABEL-ioctl/20260218-071019
base:   9f2693489ef8558240d9e80bfad103650daed0af
patch link:    https://lore.kernel.org/r/20260217230628.719475-3-ethan.ferguson%40zetier.com
patch subject: [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl
config: x86_64-rhel-9.4-ltp (https://download.01.org/0day-ci/archive/20260218/202602181149.k8dhUKY6-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260218/202602181149.k8dhUKY6-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602181149.k8dhUKY6-lkp@intel.com/

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "msdos_format_name" [fs/fat/fat.ko] undefined!

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl
@ 2026-02-18 16:01 Ethan Ferguson
  2026-02-18 18:42 ` OGAWA Hirofumi
  0 siblings, 1 reply; 11+ messages in thread
From: Ethan Ferguson @ 2026-02-18 16:01 UTC (permalink / raw)
  To: Hirofumi OGAWA; +Cc: linux-fsdevel, linux-kernel


> On Feb 18, 2026, at 02:22, OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> wrote:
> 
> Ethan Ferguson <ethan.ferguson@zetier.com> writes:
> 
>> Add support for writing to the volume label of a FAT filesystem via the
>> FS_IOC_SETFSLABEL ioctl.
>> Signed-off-by: Ethan Ferguson <ethan.ferguson@zetier.com>
>> ---
>> fs/fat/dir.c         | 51 +++++++++++++++++++++++++++++++++++
>> fs/fat/fat.h         |  6 +++++
>> fs/fat/file.c        | 63 ++++++++++++++++++++++++++++++++++++++++++++
>> fs/fat/inode.c       | 15 +++++++++++
>> fs/fat/namei_msdos.c |  4 +--
>> 5 files changed, 137 insertions(+), 2 deletions(-)
>> diff --git a/fs/fat/dir.c b/fs/fat/dir.c
>> index 07d95f1442c8..1b11713309ae 100644
>> --- a/fs/fat/dir.c
>> +++ b/fs/fat/dir.c
>> @@ -1425,3 +1425,54 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
>>  return err;
>> }
>> EXPORT_SYMBOL_GPL(fat_add_entries);
>> +
>> +static int fat_create_volume_label_dentry(struct super_block *sb, char *vol_label)
>> +{
>> +    struct msdos_sb_info *sbi = MSDOS_SB(sb);
>> +    struct inode *root_inode = sb->s_root->d_inode;
>> +    struct msdos_dir_entry de;
>> +    struct fat_slot_info sinfo;
>> +    struct timespec64 ts = current_time(root_inode);
>> +    __le16 date, time;
>> +    u8 time_cs;
>> +
>> +    memcpy(de.name, vol_label, MSDOS_NAME);
>> +    de.attr = ATTR_VOLUME;
>> +    de.starthi = de.start = de.size = de.lcase = 0;
>> +
>> +    fat_time_unix2fat(sbi, &ts, &time, &date, &time_cs);
>> +    de.time = time;
>> +    de.date = date;
>> +    if (sbi->options.isvfat) {
>> +        de.cdate = de.adate = date;
>> +        de.ctime = time;
>> +        de.ctime_cs = time_cs;
>> +    } else
>> +        de.cdate = de.adate = de.ctime = de.ctime_cs = 0;
>> +
>> +    return fat_add_entries(root_inode, &de, 1, &sinfo);
>> +}
>> +
>> +int fat_rename_volume_label_dentry(struct super_block *sb, char *vol_label)
>> +{
>> +    struct inode *root_inode = sb->s_root->d_inode;
>> +    struct buffer_head *bh = NULL;
>> +    struct msdos_dir_entry *de;
>> +    loff_t cpos = 0;
>> +    int err = 0;
>> +
>> +    while (1) {
>> +        if (fat_get_entry(root_inode, &cpos, &bh, &de) == -1)
>> +            return fat_create_volume_label_dentry(sb, vol_label);
>> +
>> +        if (de->attr == ATTR_VOLUME) {
>> +            memcpy(de->name, vol_label, MSDOS_NAME);
>> +            mark_buffer_dirty_inode(bh, root_inode);
>> +            if (IS_DIRSYNC(root_inode))
>> +                err = sync_dirty_buffer(bh);
>> +            brelse(bh);
>> +            return err;
>> +        }
>> +    }
> 
> I didn't check how to know the label though, the label is only if
> ATTR_VOLUME? IOW, any other attributes are disallowed?
I'm pretty sure ATTR_VOLUME is disallowed except for:
* Volume labels, where it is the only flag present
* Long file name entries, where it is /not/ the only flag present
This is why I check if attr == ATTR_VOLUME, not attr & ATTR_VOLUME
> What if label is marked as deleted?
As far as I know, a Volume label can never be marked as deleted, but if you want me to change the behavior of my patch, just let me know how you would like me to handle it and I'd be happy to change it.
> I'm not sure though, no need to update timestamps? (need to investigate
> spec or windows behavior)
It's not in the spec that I know either, I'm happy to remove if you deem this unnecessary.
>> +static int fat_convert_volume_label_str(struct msdos_sb_info *sbi, char *in,
>> +                    char *out)
>> +{
>> +    int ret, in_len = max(strnlen(in, FSLABEL_MAX), 11);
>> +    char *needle;
> 
> Silently truncate is the common way for this ioctl?
When I implemented this in exfat, I returned -EINVAL for names that were longer than allowed, but only after converting from nls to UTF16. I can copy this behavior here as well.
> 
>> +    /*
>> +     * '.' is not included in any bad_chars list in this driver,
>> +     * but it is specifically not allowed for volume labels
>> +     */
>> +    for (needle = in; needle - in < in_len; needle++)
>> +        if (*needle == '.')
>> +            return -EINVAL;
> 
> memchr() or such?
Noted, will use, thanks.
>> +    ret = msdos_format_name(in, in_len, out, &sbi->options);
>> +    if (ret)
>> +        return ret;
> 
>> +    /*
>> +     * msdos_format_name assumes we're translating an 8.3 name, but
>> +     * we can handle 11 chars
>> +     */
>> +    if (in_len > 8)
>> +        ret = msdos_format_name(in + 8, in_len - 8, out + 8,
>> +                    &sbi->options);
>> +    return ret;
> 
> fat module should not import msdos module.
Fair. How would you implement checking the validity of the new volume label?
> 
>> +static int fat_ioctl_set_volume_label(struct super_block *sb, char __user *arg)
>> +{
>> +    struct msdos_sb_info *sbi = MSDOS_SB(sb);
>> +    struct inode *root_inode = sb->s_root->d_inode;
>> +    char from_user[FSLABEL_MAX];
>> +    char new_vol_label[MSDOS_NAME];
>> +    int ret;
>> +
>> +    if (!capable(CAP_SYS_ADMIN))
>> +        return -EPERM;
>> +
>> +    if (sb_rdonly(sb))
>> +        return -EROFS;
>> +
>> +    if (copy_from_user(from_user, arg, FSLABEL_MAX))
>> +        return -EFAULT;
>> +
>> +    ret = fat_convert_volume_label_str(sbi, from_user, new_vol_label);
>> +    if (ret)
>> +        return ret;
>> +
>> +    inode_lock(root_inode);
>> +    ret = fat_rename_volume_label_dentry(sb, new_vol_label);
>> +    inode_unlock(root_inode);
>> +    if (ret)
>> +        return ret;
> 
> This rename will have to take same or similar locks with rename(2)?
Sure, so should I only lock on sbi->s_lock through the whole function?
>> diff --git a/fs/fat/inode.c b/fs/fat/inode.c
>> index 6f9a8cc1ad2a..a7528937383b 100644
>> --- a/fs/fat/inode.c
>> +++ b/fs/fat/inode.c
>> @@ -736,6 +736,21 @@ static void delayed_free(struct rcu_head *p)
>> static void fat_put_super(struct super_block *sb)
>> {
>>  struct msdos_sb_info *sbi = MSDOS_SB(sb);
>> +    struct buffer_head *bh = NULL;
>> +    struct fat_boot_sector *bs;
>> +
>> +    bh = sb_bread(sb, 0);
>> +    if (bh == NULL)
>> +        fat_msg(sb, KERN_ERR, "unable to read boot sector");
>> +    else if (!sb_rdonly(sb)) {
>> +        bs = (struct fat_boot_sector *)bh->b_data;
>> +        if (is_fat32(sbi))
>> +            memcpy(bs->fat32.vol_label, sbi->vol_label, MSDOS_NAME);
>> +        else
>> +            memcpy(bs->fat16.vol_label, sbi->vol_label, MSDOS_NAME);
>> +        mark_buffer_dirty(bh);
>> +    }
>> +    brelse(bh);
> 
> Why this unconditionally update the vol_label at unmount?
I can add a dirty bit to msdos_sb_info, and only write if it's present.
> Thanks.
> --
> OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl
  2026-02-17 23:06 ` [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl Ethan Ferguson
                     ` (3 preceding siblings ...)
  2026-02-18 10:22   ` kernel test robot
@ 2026-02-18 16:26   ` kernel test robot
  4 siblings, 0 replies; 11+ messages in thread
From: kernel test robot @ 2026-02-18 16:26 UTC (permalink / raw)
  To: Ethan Ferguson, hirofumi
  Cc: oe-kbuild-all, linux-fsdevel, linux-kernel, Ethan Ferguson

Hi Ethan,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 9f2693489ef8558240d9e80bfad103650daed0af]

url:    https://github.com/intel-lab-lkp/linux/commits/Ethan-Ferguson/fat-Add-FS_IOC_GETFSLABEL-ioctl/20260218-071019
base:   9f2693489ef8558240d9e80bfad103650daed0af
patch link:    https://lore.kernel.org/r/20260217230628.719475-3-ethan.ferguson%40zetier.com
patch subject: [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl
config: hexagon-randconfig-r121-20260218 (https://download.01.org/0day-ci/archive/20260219/202602190010.tPRKu8kq-lkp@intel.com/config)
compiler: clang version 23.0.0git (https://github.com/llvm/llvm-project e86750b29fa0ff207cd43213d66dabe565417638)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260219/202602190010.tPRKu8kq-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602190010.tPRKu8kq-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> fs/fat/dir.c:1439:41: sparse: sparse: incorrect type in assignment (different base types) @@     expected restricted __le32 [addressable] [assigned] [usertype] size @@     got unsigned char [addressable] [assigned] [usertype] lcase @@
   fs/fat/dir.c:1439:41: sparse:     expected restricted __le32 [addressable] [assigned] [usertype] size
   fs/fat/dir.c:1439:41: sparse:     got unsigned char [addressable] [assigned] [usertype] lcase
>> fs/fat/dir.c:1449:48: sparse: sparse: incorrect type in assignment (different base types) @@     expected restricted __le16 [addressable] [assigned] [usertype] ctime @@     got unsigned char [addressable] [assigned] [usertype] ctime_cs @@
   fs/fat/dir.c:1449:48: sparse:     expected restricted __le16 [addressable] [assigned] [usertype] ctime
   fs/fat/dir.c:1449:48: sparse:     got unsigned char [addressable] [assigned] [usertype] ctime_cs

vim +1439 fs/fat/dir.c

  1426	
  1427	static int fat_create_volume_label_dentry(struct super_block *sb, char *vol_label)
  1428	{
  1429		struct msdos_sb_info *sbi = MSDOS_SB(sb);
  1430		struct inode *root_inode = sb->s_root->d_inode;
  1431		struct msdos_dir_entry de;
  1432		struct fat_slot_info sinfo;
  1433		struct timespec64 ts = current_time(root_inode);
  1434		__le16 date, time;
  1435		u8 time_cs;
  1436	
  1437		memcpy(de.name, vol_label, MSDOS_NAME);
  1438		de.attr = ATTR_VOLUME;
> 1439		de.starthi = de.start = de.size = de.lcase = 0;
  1440	
  1441		fat_time_unix2fat(sbi, &ts, &time, &date, &time_cs);
  1442		de.time = time;
  1443		de.date = date;
  1444		if (sbi->options.isvfat) {
  1445			de.cdate = de.adate = date;
  1446			de.ctime = time;
  1447			de.ctime_cs = time_cs;
  1448		} else
> 1449			de.cdate = de.adate = de.ctime = de.ctime_cs = 0;
  1450	
  1451		return fat_add_entries(root_inode, &de, 1, &sinfo);
  1452	}
  1453	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl
  2026-02-18 16:01 [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl Ethan Ferguson
@ 2026-02-18 18:42 ` OGAWA Hirofumi
  0 siblings, 0 replies; 11+ messages in thread
From: OGAWA Hirofumi @ 2026-02-18 18:42 UTC (permalink / raw)
  To: Ethan Ferguson; +Cc: linux-fsdevel, linux-kernel

Ethan Ferguson <ethan.ferguson@zetier.com> writes:

>> I didn't check how to know the label though, the label is only if
>> ATTR_VOLUME? IOW, any other attributes are disallowed?
> I'm pretty sure ATTR_VOLUME is disallowed except for:
> * Volume labels, where it is the only flag present
> * Long file name entries, where it is /not/ the only flag present
> This is why I check if attr == ATTR_VOLUME, not attr & ATTR_VOLUME

What happen on Windows if ATTR_VOLUME | ATTR_ARCH, for example? There
are many strange behavior tools for FAT.

>> What if label is marked as deleted?
> As far as I know, a Volume label can never be marked as deleted, but if you want me to change the behavior of my patch, just let me know how you would like me to handle it and I'd be happy to change it.

That state is easily happen too, I'd like to emulate Windows behavior if
possible.

>> I'm not sure though, no need to update timestamps? (need to investigate
>> spec or windows behavior)
> It's not in the spec that I know either, I'm happy to remove if you deem this unnecessary.

Rather I'd like to know if Windows updates it or not.

>>> +static int fat_convert_volume_label_str(struct msdos_sb_info *sbi, char *in,
>>> +                    char *out)
>>> +{
>>> +    int ret, in_len = max(strnlen(in, FSLABEL_MAX), 11);
>>> +    char *needle;
>> 
>> Silently truncate is the common way for this ioctl?
> When I implemented this in exfat, I returned -EINVAL for names that were longer than allowed, but only after converting from nls to UTF16. I can copy this behavior here as well.

I think we should avoid userspace adds workaround for per fs
behavior. So if possible, ioctl should behave same behavior or meaning
of error code.

>>> +    ret = msdos_format_name(in, in_len, out, &sbi->options);
>>> +    if (ret)
>>> +        return ret;
>> 
>>> +    /*
>>> +     * msdos_format_name assumes we're translating an 8.3 name, but
>>> +     * we can handle 11 chars
>>> +     */
>>> +    if (in_len > 8)
>>> +        ret = msdos_format_name(in + 8, in_len - 8, out + 8,
>>> +                    &sbi->options);
>>> +    return ret;
>> 
>> fat module should not import msdos module.
> Fair. How would you implement checking the validity of the new volume label?

For example, move label verifier to fat module instead, and export to
msdos module if required.

>> This rename will have to take same or similar locks with rename(2)?
> Sure, so should I only lock on sbi->s_lock through the whole function?

Hm, I expected to take same locking with vfs what does for rename(2)
syscall path. Otherwise, this would be able to race with normal dir rename.

>>> diff --git a/fs/fat/inode.c b/fs/fat/inode.c
>>> index 6f9a8cc1ad2a..a7528937383b 100644
>>> --- a/fs/fat/inode.c
>>> +++ b/fs/fat/inode.c
>>> @@ -736,6 +736,21 @@ static void delayed_free(struct rcu_head *p)
>>> static void fat_put_super(struct super_block *sb)
>>> {
>>>  struct msdos_sb_info *sbi = MSDOS_SB(sb);
>>> +    struct buffer_head *bh = NULL;
>>> +    struct fat_boot_sector *bs;
>>> +
>>> +    bh = sb_bread(sb, 0);
>>> +    if (bh == NULL)
>>> +        fat_msg(sb, KERN_ERR, "unable to read boot sector");
>>> +    else if (!sb_rdonly(sb)) {
>>> +        bs = (struct fat_boot_sector *)bh->b_data;
>>> +        if (is_fat32(sbi))
>>> +            memcpy(bs->fat32.vol_label, sbi->vol_label, MSDOS_NAME);
>>> +        else
>>> +            memcpy(bs->fat16.vol_label, sbi->vol_label, MSDOS_NAME);
>>> +        mark_buffer_dirty(bh);
>>> +    }
>>> +    brelse(bh);
>> 
>> Why this unconditionally update the vol_label at unmount?
> I can add a dirty bit to msdos_sb_info, and only write if it's present.

And why this update at unmount? Looks like it is natural to update like
normal rename.

Thanks.
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-02-18 18:42 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-17 23:06 [PATCH v2 0/2] fat: Add FS_IOC_GETFSLABEL / FS_IOC_SETFSLABEL ioctls Ethan Ferguson
2026-02-17 23:06 ` [PATCH v2 1/2] fat: Add FS_IOC_GETFSLABEL ioctl Ethan Ferguson
2026-02-17 23:06 ` [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl Ethan Ferguson
2026-02-18  6:50   ` kernel test robot
2026-02-18  7:21   ` kernel test robot
2026-02-18  7:22   ` OGAWA Hirofumi
2026-02-18 10:22   ` kernel test robot
2026-02-18 16:26   ` kernel test robot
2026-02-18  8:46 ` [syzbot ci] Re: fat: Add FS_IOC_GETFSLABEL / FS_IOC_SETFSLABEL ioctls syzbot ci
  -- strict thread matches above, loose matches on Subject: below --
2026-02-18 16:01 [PATCH v2 2/2] fat: Add FS_IOC_SETFSLABEL ioctl Ethan Ferguson
2026-02-18 18:42 ` OGAWA Hirofumi

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