dm ioctl: return UUID in DM_LIST_DEVICES_CMD result
authorMikulas Patocka <mpatocka@redhat.com>
Fri, 12 Mar 2021 14:07:30 +0000 (09:07 -0500)
committerMike Snitzer <snitzer@redhat.com>
Fri, 26 Mar 2021 18:53:41 +0000 (14:53 -0400)
When LVM needs to find a device with a particular UUID it needs to ask for
UUID for each device. This patch returns UUID directly in the list of
devices, so that LVM doesn't have to query all the devices with an ioctl.
The UUID is returned if the flag DM_UUID_FLAG is set in the parameters.

Returning UUID is done in backward-compatible way. There's one unused
32-bit word value after the event number. This patch sets the bit
DM_NAME_LIST_FLAG_HAS_UUID if UUID is present and
DM_NAME_LIST_FLAG_DOESNT_HAVE_UUID if it isn't (if none of these bits is
set, then we have an old kernel that doesn't support returning UUIDs). The
UUID is stored after this word. The 'next' value is updated to point after
the UUID, so that old version of libdevmapper will skip the UUID without
attempting to interpret it.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
drivers/md/dm-ioctl.c
include/uapi/linux/dm-ioctl.h

index 272de8772d52aecda3c1e59122d80c294b0c9872..0812ac6e9d70a713f643f06448407e6d41710af8 100644 (file)
@@ -558,7 +558,9 @@ static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_
        for (n = rb_first(&name_rb_tree); n; n = rb_next(n)) {
                hc = container_of(n, struct hash_cell, name_node);
                needed += align_val(offsetof(struct dm_name_list, name) + strlen(hc->name) + 1);
-               needed += align_val(sizeof(uint32_t));
+               needed += align_val(sizeof(uint32_t) * 2);
+               if (param->flags & DM_UUID_FLAG && hc->uuid)
+                       needed += align_val(strlen(hc->uuid) + 1);
        }
 
        /*
@@ -577,6 +579,7 @@ static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_
         * Now loop through filling out the names.
         */
        for (n = rb_first(&name_rb_tree); n; n = rb_next(n)) {
+               void *uuid_ptr;
                hc = container_of(n, struct hash_cell, name_node);
                if (old_nl)
                        old_nl->next = (uint32_t) ((void *) nl -
@@ -588,8 +591,19 @@ static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_
 
                old_nl = nl;
                event_nr = align_ptr(nl->name + strlen(hc->name) + 1);
-               *event_nr = dm_get_event_nr(hc->md);
-               nl = align_ptr(event_nr + 1);
+               event_nr[0] = dm_get_event_nr(hc->md);
+               event_nr[1] = 0;
+               uuid_ptr = align_ptr(event_nr + 2);
+               if (param->flags & DM_UUID_FLAG) {
+                       if (hc->uuid) {
+                               event_nr[1] |= DM_NAME_LIST_FLAG_HAS_UUID;
+                               strcpy(uuid_ptr, hc->uuid);
+                               uuid_ptr = align_ptr(uuid_ptr + strlen(hc->uuid) + 1);
+                       } else {
+                               event_nr[1] |= DM_NAME_LIST_FLAG_DOESNT_HAVE_UUID;
+                       }
+               }
+               nl = uuid_ptr;
        }
        /*
         * If mismatch happens, security may be compromised due to buffer
index fcff6669137b500bf5d64f1ab27dfce53d957e2e..e5c6e458bdf73e3783e91609626c16dce7ddf24d 100644 (file)
@@ -193,8 +193,22 @@ struct dm_name_list {
        __u32 next;             /* offset to the next record from
                                   the _start_ of this */
        char name[0];
+
+       /*
+        * The following members can be accessed by taking a pointer that
+        * points immediately after the terminating zero character in "name"
+        * and aligning this pointer to next 8-byte boundary.
+        * Uuid is present if the flag DM_NAME_LIST_FLAG_HAS_UUID is set.
+        *
+        * __u32 event_nr;
+        * __u32 flags;
+        * char uuid[0];
+        */
 };
 
+#define DM_NAME_LIST_FLAG_HAS_UUID             1
+#define DM_NAME_LIST_FLAG_DOESNT_HAVE_UUID     2
+
 /*
  * Used to retrieve the target versions
  */
@@ -272,9 +286,9 @@ enum {
 #define DM_DEV_SET_GEOMETRY    _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
 
 #define DM_VERSION_MAJOR       4
-#define DM_VERSION_MINOR       44
+#define DM_VERSION_MINOR       45
 #define DM_VERSION_PATCHLEVEL  0
-#define DM_VERSION_EXTRA       "-ioctl (2021-02-01)"
+#define DM_VERSION_EXTRA       "-ioctl (2021-03-22)"
 
 /* Status bits */
 #define DM_READONLY_FLAG       (1 << 0) /* In/Out */