Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Documentation/userspace-api/ioctl/ioctl-number.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,9 @@ Code Seq# Include File Comments
0x10 00-0F drivers/char/s390/vmcp.h
0x10 10-1F arch/s390/include/uapi/sclp_ctl.h
0x10 20-2F arch/s390/include/uapi/asm/hypfs.h
0x12 all linux/fs.h
0x12 all linux/fs.h BLK* ioctls
linux/blkpg.h
0x15 all linux/fs.h FS_IOC_* ioctls
0x1b all InfiniBand Subsystem
<http://infiniband.sourceforge.net/>
0x20 all drivers/cdrom/cm206.h
Expand Down
2 changes: 1 addition & 1 deletion fs/ext4/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -5368,7 +5368,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
sb->s_qcop = &ext4_qctl_operations;
sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ;
#endif
memcpy(&sb->s_uuid, es->s_uuid, sizeof(es->s_uuid));
super_set_uuid(sb, es->s_uuid, sizeof(es->s_uuid));

INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
mutex_init(&sbi->s_orphan_lock);
Expand Down
2 changes: 1 addition & 1 deletion fs/f2fs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -4468,7 +4468,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_time_gran = 1;
sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
(test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0);
memcpy(&sb->s_uuid, raw_super->uuid, sizeof(raw_super->uuid));
super_set_uuid(sb, (void *) raw_super->uuid, sizeof(raw_super->uuid));
sb->s_iflags |= SB_I_CGROUPWB;

/* init f2fs-specific super block info */
Expand Down
2 changes: 1 addition & 1 deletion fs/gfs2/ops_fstype.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ static void gfs2_sb_in(struct gfs2_sbd *sdp, const void *buf)

memcpy(sb->sb_lockproto, str->sb_lockproto, GFS2_LOCKNAME_LEN);
memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN);
memcpy(&s->s_uuid, str->sb_uuid, 16);
super_set_uuid(s, str->sb_uuid, 16);
}

/**
Expand Down
33 changes: 33 additions & 0 deletions fs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,33 @@ static int ioctl_fssetxattr(struct file *file, void __user *argp)
return err;
}

static int ioctl_getfsuuid(struct file *file, void __user *argp)
{
struct super_block *sb = file_inode(file)->i_sb;
struct fsuuid2 u = { .len = sb->s_uuid_len, };

if (!sb->s_uuid_len)
return -ENOIOCTLCMD;

memcpy(&u.uuid[0], &sb->s_uuid, sb->s_uuid_len);

return copy_to_user(argp, &u, sizeof(u)) ? -EFAULT : 0;
}

static int ioctl_get_fs_sysfs_path(struct file *file, void __user *argp)
{
struct super_block *sb = file_inode(file)->i_sb;

if (!strlen(sb->s_sysfs_name))
return -ENOIOCTLCMD;

struct fs_sysfs_path u = {};

Comment on lines +782 to +787
Copy link

Copilot AI Jul 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable declaration should be at the beginning of the function scope for C89 compatibility, not in the middle of the function after other statements.

Suggested change
if (!strlen(sb->s_sysfs_name))
return -ENOIOCTLCMD;
struct fs_sysfs_path u = {};
struct fs_sysfs_path u = {};
if (!strlen(sb->s_sysfs_name))
return -ENOIOCTLCMD;

Copilot uses AI. Check for mistakes.
u.len = scnprintf(u.name, sizeof(u.name), "%s/%s", sb->s_type->name, sb->s_sysfs_name);

return copy_to_user(argp, &u, sizeof(u)) ? -EFAULT : 0;
}

/*
* do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d.
* It's just a simple helper for sys_ioctl and compat_sys_ioctl.
Expand Down Expand Up @@ -845,6 +872,12 @@ static int do_vfs_ioctl(struct file *filp, unsigned int fd,
case FS_IOC_FSSETXATTR:
return ioctl_fssetxattr(filp, argp);

case FS_IOC_GETFSUUID:
return ioctl_getfsuuid(filp, argp);

case FS_IOC_GETFSSYSFSPATH:
return ioctl_get_fs_sysfs_path(filp, argp);

default:
if (S_ISREG(inode->i_mode))
return file_ioctl(filp, cmd, argp);
Expand Down
4 changes: 3 additions & 1 deletion fs/kernfs/mount.c
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,9 @@ int kernfs_get_tree(struct fs_context *fc)
}
sb->s_flags |= SB_ACTIVE;

uuid_gen(&sb->s_uuid);
uuid_t uuid;
uuid_gen(&uuid);
super_set_uuid(sb, uuid.b, sizeof(uuid));

down_write(&root->kernfs_supers_rwsem);
list_add(&info->node, &info->root->supers);
Expand Down
4 changes: 2 additions & 2 deletions fs/ocfs2/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -2032,8 +2032,8 @@ static int ocfs2_initialize_super(struct super_block *sb,
cbits = le32_to_cpu(di->id2.i_super.s_clustersize_bits);
bbits = le32_to_cpu(di->id2.i_super.s_blocksize_bits);
sb->s_maxbytes = ocfs2_max_file_offset(bbits, cbits);
memcpy(&sb->s_uuid, di->id2.i_super.s_uuid,
sizeof(di->id2.i_super.s_uuid));
super_set_uuid(sb, di->id2.i_super.s_uuid,
sizeof(di->id2.i_super.s_uuid));

osb->osb_dx_mask = (1 << (cbits - bbits)) - 1;

Expand Down
2 changes: 1 addition & 1 deletion fs/ubifs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -2246,7 +2246,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
goto out_umount;
}

import_uuid(&sb->s_uuid, c->uuid);
super_set_uuid(sb, c->uuid, sizeof(c->uuid));

mutex_unlock(&c->umount_mutex);
return 0;
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_mount.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ xfs_uuid_mount(
int hole, i;

/* Publish UUID in struct super_block */
uuid_copy(&mp->m_super->s_uuid, uuid);
super_set_uuid(mp->m_super, uuid->b, sizeof(*uuid));

if (xfs_has_nouuid(mp))
return 0;
Expand Down
52 changes: 52 additions & 0 deletions include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1267,8 +1267,22 @@ struct super_block {
struct fsnotify_mark_connector __rcu *s_fsnotify_marks;
#endif

/*
* q: why are s_id and s_sysfs_name not the same? both are human
* readable strings that identify the filesystem
* a: s_id is allowed to change at runtime; it's used in log messages,
* and we want to when a device starts out as single device (s_id is dev
* name) but then a device is hot added and we have to switch to
* identifying it by UUID
* but s_sysfs_name is a handle for programmatic access, and can't
* change at runtime
*/
char s_id[32]; /* Informational name */
uuid_t s_uuid; /* UUID */
u8 s_uuid_len; /* Default 16, possibly smaller for weird filesystems */

/* if set, fs shows up under sysfs at /sys/fs/$FSTYP/s_sysfs_name */
char s_sysfs_name[UUID_STRING_LEN + 1];

unsigned int s_max_links;

Expand Down Expand Up @@ -2474,6 +2488,44 @@ extern __printf(2, 3)
int super_setup_bdi_name(struct super_block *sb, char *fmt, ...);
extern int super_setup_bdi(struct super_block *sb);

static inline void super_set_uuid(struct super_block *sb, const u8 *uuid, unsigned len)
{
if (WARN_ON(len > sizeof(sb->s_uuid)))
len = sizeof(sb->s_uuid);
sb->s_uuid_len = len;
memcpy(&sb->s_uuid, uuid, len);
}

/* set sb sysfs name based on sb->s_bdev */
static inline void super_set_sysfs_name_bdev(struct super_block *sb)
{
snprintf(sb->s_sysfs_name, sizeof(sb->s_sysfs_name), "%pg", sb->s_bdev);
}

/* set sb sysfs name based on sb->s_uuid */
static inline void super_set_sysfs_name_uuid(struct super_block *sb)
{
WARN_ON(sb->s_uuid_len != sizeof(sb->s_uuid));
snprintf(sb->s_sysfs_name, sizeof(sb->s_sysfs_name), "%pU", sb->s_uuid.b);
}

/* set sb sysfs name based on sb->s_id */
static inline void super_set_sysfs_name_id(struct super_block *sb)
{
strscpy(sb->s_sysfs_name, sb->s_id, sizeof(sb->s_sysfs_name));
}

/* try to use something standard before you use this */
__printf(2, 3)
static inline void super_set_sysfs_name_generic(struct super_block *sb, const char *fmt, ...)
{
va_list args;

va_start(args, fmt);
vsnprintf(sb->s_sysfs_name, sizeof(sb->s_sysfs_name), fmt, args);
va_end(args);
}

extern int current_umask(void);

extern void ihold(struct inode * inode);
Expand Down
25 changes: 25 additions & 0 deletions include/uapi/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,24 @@ struct fstrim_range {
__u64 minlen;
};

/*
* We include a length field because some filesystems (vfat) have an identifier
* that we do want to expose as a UUID, but doesn't have the standard length.
*
* We use a fixed size buffer beacuse this interface will, by fiat, never
Copy link

Copilot AI Jul 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error: 'beacuse' should be 'because'.

Suggested change
* We use a fixed size buffer beacuse this interface will, by fiat, never
* We use a fixed size buffer because this interface will, by fiat, never

Copilot uses AI. Check for mistakes.
* support "UUIDs" longer than 16 bytes; we don't want to force all downstream
* users to have to deal with that.
*/
struct fsuuid2 {
__u8 len;
__u8 uuid[16];
};

struct fs_sysfs_path {
__u8 len;
__u8 name[128];
};

/* extent-same (dedupe) ioctls; these MUST match the btrfs ioctl definitions */
#define FILE_DEDUPE_RANGE_SAME 0
#define FILE_DEDUPE_RANGE_DIFFERS 1
Expand Down Expand Up @@ -215,6 +233,13 @@ struct fsxattr {
#define FS_IOC_FSSETXATTR _IOW('X', 32, struct fsxattr)
#define FS_IOC_GETFSLABEL _IOR(0x94, 49, char[FSLABEL_MAX])
#define FS_IOC_SETFSLABEL _IOW(0x94, 50, char[FSLABEL_MAX])
/* Returns the external filesystem UUID, the same one blkid returns */
#define FS_IOC_GETFSUUID _IOR(0x15, 0, struct fsuuid2)
/*
* Returns the path component under /sys/fs/ that refers to this filesystem;
* also /sys/kernel/debug/ for filesystems with debugfs exports
*/
#define FS_IOC_GETFSSYSFSPATH _IOR(0x15, 1, struct fs_sysfs_path)

/*
* Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS)
Expand Down
4 changes: 3 additions & 1 deletion mm/shmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -4352,7 +4352,9 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
#ifdef CONFIG_TMPFS_POSIX_ACL
sb->s_flags |= SB_POSIXACL;
#endif
uuid_gen(&sb->s_uuid);
uuid_t uuid;
uuid_gen(&uuid);
super_set_uuid(sb, uuid.b, sizeof(uuid));

#ifdef CONFIG_TMPFS_QUOTA
if (ctx->seen & SHMEM_SEEN_QUOTA) {
Expand Down
Loading