From: "Darrick J. Wong" <djwong@kernel.org>
To: Jeremy Bongio <bongiojp@gmail.com>
Cc: Ted Tso <tytso@mit.edu>, linux-ext4@vger.kernel.org
Subject: Re: [PATCH v2] Add support for get/set UUID ioctls.
Date: Tue, 19 Jul 2022 08:17:04 -0700 [thread overview]
Message-ID: <YtbK8LJSYfCRx5B1@magnolia> (raw)
In-Reply-To: <20220719065637.154309-1-bongiojp@gmail.com>
> Subject: [PATCH v2] Add support for get/set UUID ioctls.
Quick tip: Many people explicitly tag these userspace patches with the
name of the tool in the subject line, e.g.
[PATCH v2] tune2fs: add support for get/set UUID ioctls.
On Mon, Jul 18, 2022 at 11:56:37PM -0700, Jeremy Bongio wrote:
> When mounted, there is a race condition between changing the filesystem
> UUID and changing other aspects of the filesystem, like mounting, resizing,
> changing features, etc. Using these ioctls to get/set the UUID ensures the
> filesystem is not being resized.
>
> Signed-off-by: Jeremy Bongio <bongiojp@gmail.com>
> ---
>
> fu_* fields are now named fsu_*.
>
> Removed EXT4_IOC_SETFSUUID_FLAG_BLOCKING flag.
>
> fsu_flags is initialized to 0.
>
> misc/tune2fs.c | 104 ++++++++++++++++++++++++++++++++++++++++---------
> 1 file changed, 86 insertions(+), 18 deletions(-)
>
> diff --git a/misc/tune2fs.c b/misc/tune2fs.c
> index 6c162ba5..39399d83 100644
> --- a/misc/tune2fs.c
> +++ b/misc/tune2fs.c
> @@ -82,11 +82,25 @@ extern int optind;
> #define FS_IOC_GETFSLABEL _IOR(0x94, 49, char[FSLABEL_MAX])
> #endif
>
> +struct fsuuid {
> + __u32 fsu_len;
> + __u32 fsu_flags;
> + __u8 fsu_uuid[];
> +};
> +
> +#ifndef EXT4_IOC_GETFSUUID
> +#define EXT4_IOC_GETFSUUID _IOR('f', 44, struct fsuuid)
> +#endif
> +
> +#ifndef EXT4_IOC_SETFSUUID
> +#define EXT4_IOC_SETFSUUID _IOW('f', 44, struct fsuuid)
> +#endif
> +
> extern int ask_yn(const char *string, int def);
>
> const char *program_name = "tune2fs";
> char *device_name;
> -char *new_label, *new_last_mounted, *new_UUID;
> +char *new_label, *new_last_mounted, *requested_uuid;
> char *io_options;
> static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag;
> static int m_flag, M_flag, Q_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag;
> @@ -2102,7 +2116,7 @@ static void parse_tune2fs_options(int argc, char **argv)
> open_flag = EXT2_FLAG_RW;
> break;
> case 'U':
> - new_UUID = optarg;
> + requested_uuid = optarg;
> U_flag = 1;
> open_flag = EXT2_FLAG_RW |
> EXT2_FLAG_JOURNAL_DEV_OK;
> @@ -3078,6 +3092,52 @@ int handle_fslabel(int setlabel) {
> return 0;
> }
>
> +/*
> + * Use EXT4_IOC_GETFSUUID/EXT4_IOC_SETFSUUID to get/set file system UUID.
> + * Return: 0 on success
> + * 1 on error
> + * -1 when the old method should be used
> + */
> +int handle_fsuuid(__u8 *uuid, bool get)
> +{
> + errcode_t ret;
> + int mnt_flags, fd;
> + char label[FSLABEL_MAX];
> + int maxlen = FSLABEL_MAX - 1;
> + char mntpt[PATH_MAX + 1];
> + struct fsuuid *fsuuid = NULL;
> +
> + fsuuid = malloc(sizeof(*fsuuid) + UUID_SIZE);
> + if (!fsuuid)
> + return -1;
> +
> + memcpy(fsuuid->fsu_uuid, uuid, UUID_SIZE);
> + fsuuid->fsu_len = UUID_SIZE;
> + fsuuid->fsu_flags = 0;
> +
> + ret = ext2fs_check_mount_point(device_name, &mnt_flags,
> + mntpt, sizeof(mntpt));
> + if (ret || !(mnt_flags & EXT2_MF_MOUNTED) ||
> + (!get && (mnt_flags & EXT2_MF_READONLY)) ||
> + !mntpt[0])
> + return -1;
> +
> + fd = open(mntpt, O_RDONLY);
> + if (fd < 0)
> + return -1;
> +
> + if (get) {
> + if (ioctl(fd, EXT4_IOC_GETFSUUID, fsuuid))
> + ret = -1;
> + } else {
> + if (ioctl(fd, EXT4_IOC_SETFSUUID, fsuuid))
> + ret = -1;
> + }
> + close(fd);
> + return ret;
ret is probably zero here, right?
That said, I don't think it's a great idea to go mixing errcode_t and
"the normal libc int return value" like that, since (a) that's type
confusion and (b)
return 0;
gets the point across with less effort.
> +}
> +
> +
> #ifndef BUILD_AS_LIB
> int main(int argc, char **argv)
> #else
> @@ -3454,6 +3514,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
> dgrp_t i;
> char buf[SUPERBLOCK_SIZE] __attribute__ ((aligned(8)));
> __u8 old_uuid[UUID_SIZE];
> + uuid_t new_uuid;
>
> if (ext2fs_has_feature_stable_inodes(fs->super)) {
> fputs(_("Cannot change the UUID of this filesystem "
> @@ -3507,25 +3568,34 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
> set_csum = 1;
> }
>
> - memcpy(old_uuid, sb->s_uuid, UUID_SIZE);
> - if ((strcasecmp(new_UUID, "null") == 0) ||
> - (strcasecmp(new_UUID, "clear") == 0)) {
> - uuid_clear(sb->s_uuid);
> - } else if (strcasecmp(new_UUID, "time") == 0) {
> - uuid_generate_time(sb->s_uuid);
> - } else if (strcasecmp(new_UUID, "random") == 0) {
> - uuid_generate(sb->s_uuid);
> - } else if (uuid_parse(new_UUID, sb->s_uuid)) {
> + rc = handle_fsuuid(old_uuid, true);
Might also be helpful to readers to wrap handle_fsuuid with something
containing "get" and "set" in the name explicitly, e.g.
static inline int get_mounted_fsuuid(__u8 *old_uuid)
{
return handle_fssuid(old_uuid, true);
}
I /think/ the rest looks plausible, but oof tune2fs is a bear to read.
My apologies for all the random cruft I've contributed over the years
(rewriting every inode on the filesystem to add checksums? seriously??)
--D
> + if (rc == -1)
> + memcpy(old_uuid, sb->s_uuid, UUID_SIZE);
> +
> + if ((strcasecmp(requested_uuid, "null") == 0) ||
> + (strcasecmp(requested_uuid, "clear") == 0)) {
> + uuid_clear(new_uuid);
> + } else if (strcasecmp(requested_uuid, "time") == 0) {
> + uuid_generate_time(new_uuid);
> + } else if (strcasecmp(requested_uuid, "random") == 0) {
> + uuid_generate(new_uuid);
> + } else if (uuid_parse(requested_uuid, new_uuid)) {
> com_err(program_name, 0, "%s",
> _("Invalid UUID format\n"));
> rc = 1;
> goto closefs;
> }
> - ext2fs_init_csum_seed(fs);
> - if (set_csum) {
> - for (i = 0; i < fs->group_desc_count; i++)
> - ext2fs_group_desc_csum_set(fs, i);
> - fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
> +
> + rc = handle_fsuuid(new_uuid, false);
> + if (rc == -1) {
> + memcpy(sb->s_uuid, new_uuid, UUID_SIZE);
> + ext2fs_init_csum_seed(fs);
> + if (set_csum) {
> + for (i = 0; i < fs->group_desc_count; i++)
> + ext2fs_group_desc_csum_set(fs, i);
> + fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
> + }
> + ext2fs_mark_super_dirty(fs);
> }
>
> /* If this is a journal dev, we need to copy UUID into jsb */
> @@ -3549,8 +3619,6 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
> if ((rc = fs_update_journal_user(sb, old_uuid)))
> goto closefs;
> }
> -
> - ext2fs_mark_super_dirty(fs);
> }
>
> if (I_flag) {
> --
> 2.37.0.170.g444d1eabd0-goog
>
next prev parent reply other threads:[~2022-07-19 15:17 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-07-19 6:56 [PATCH v2] Add support for get/set UUID ioctls Jeremy Bongio
2022-07-19 15:17 ` Darrick J. Wong [this message]
2022-07-19 21:16 ` Jeremy Bongio
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=YtbK8LJSYfCRx5B1@magnolia \
--to=djwong@kernel.org \
--cc=bongiojp@gmail.com \
--cc=linux-ext4@vger.kernel.org \
--cc=tytso@mit.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.