summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZdenek Kabelac <zkabelac@redhat.com>2021-12-15 11:34:50 +0100
committerZdenek Kabelac <zkabelac@redhat.com>2021-12-20 16:13:28 +0100
commit988ea0e94c79a496f2619eab878fd9db6168711d (patch)
treee7b9d05b0c0b38f281911481ea70a2443a7278ec
parent90da953fd22437a8abfff02eb590a621efcc007c (diff)
downloadlvm2-988ea0e94c79a496f2619eab878fd9db6168711d.tar.gz
devicemapper: add dm_task_get_device_list
New API extension (internal ATM) for getting a list of active DM device with extra features like i.e. uuid. To easily lookout for existing UUID in device list, there is: dm_device_list_find_by_uuid() Once the returned structure is no longer usable call: dm_device_list_destroy() Struct dm_active_device {} holds all the info, but is always allocated and destroyed within library. TODO: once it's stable, copy to libdm
-rw-r--r--WHATS_NEW1
-rw-r--r--device_mapper/all.h29
-rw-r--r--device_mapper/ioctl/libdm-iface.c128
3 files changed, 158 insertions, 0 deletions
diff --git a/WHATS_NEW b/WHATS_NEW
index fc327dffd..0b206f067 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.03.15 -
===================================
+ Introduce function to utilize UUIDs from DM_DEVICE_LIST.
Increase some hash table size to better support large device sets.
Version 2.03.14 - 20th October 2021
diff --git a/device_mapper/all.h b/device_mapper/all.h
index 17f78d989..c8f040b80 100644
--- a/device_mapper/all.h
+++ b/device_mapper/all.h
@@ -173,6 +173,16 @@ struct dm_names {
char name[];
};
+struct dm_active_device {
+ struct dm_list list;
+ int major;
+ int minor;
+ char *name; /* device name */
+
+ uint32_t event_nr; /* valid when DM_DEVICE_LIST_HAS_EVENT_NR is set */
+ char *uuid; /* valid uuid when DM_DEVICE_LIST_HAS_UUID is set */
+};
+
struct dm_versions {
uint32_t next; /* Offset to next struct from start of this struct */
uint32_t version[3];
@@ -210,6 +220,25 @@ const char *dm_task_get_message_response(struct dm_task *dmt);
*/
const char *dm_task_get_name(const struct dm_task *dmt);
struct dm_names *dm_task_get_names(struct dm_task *dmt);
+/*
+ * Retrieve the list of devices and put them into easily accessible
+ * struct dm_active_device list elements.
+ * devs_features provides flag-set with used features so it's easy to check
+ * whether the kernel provides i.e. UUID info together with DM names
+ */
+#define DM_DEVICE_LIST_HAS_EVENT_NR 1
+#define DM_DEVICE_LIST_HAS_UUID 2
+int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
+ unsigned *devs_features);
+/*
+ * -1: no idea about uuid (not provided by DM_DEVICE_LIST ioctl)
+ * 0: uuid not present
+ * 1: listed and dm_active_device will be set for not NULL pointer
+ */
+int dm_device_list_find_by_uuid(struct dm_list *devs_list, const char *uuid,
+ const struct dm_active_device **dev);
+/* Release all associated memory with list of active DM devices */
+void dm_device_list_destroy(struct dm_list **devs_list);
int dm_task_set_ro(struct dm_task *dmt);
int dm_task_set_newname(struct dm_task *dmt, const char *newname);
diff --git a/device_mapper/ioctl/libdm-iface.c b/device_mapper/ioctl/libdm-iface.c
index acc0f557c..738807f8f 100644
--- a/device_mapper/ioctl/libdm-iface.c
+++ b/device_mapper/ioctl/libdm-iface.c
@@ -779,6 +779,134 @@ static int _check_has_event_nr(void) {
return _has_event_nr;
}
+struct dm_device_list {
+ struct dm_list list;
+ unsigned count;
+ unsigned features;
+ struct dm_hash_table *uuids;
+};
+
+int dm_task_get_device_list(struct dm_task *dmt, struct dm_list **devs_list,
+ unsigned *devs_features)
+{
+ struct dm_names *names, *names1;
+ struct dm_active_device *dm_dev, *dm_new_dev;
+ struct dm_device_list *devs;
+ unsigned next = 0;
+ uint32_t *event_nr;
+ char *uuid_ptr;
+ size_t len;
+ int cnt = 0;
+
+ *devs_list = 0;
+ *devs_features = 0;
+
+ if ((names = dm_task_get_names(dmt)) && names->dev) {
+ names1 = names;
+ if (!names->name[0])
+ cnt = -1; /* -> cnt == 0 when no device is really present */
+ do {
+ names1 = (struct dm_names *)((char *) names1 + next);
+ next = names1->next;
+ ++cnt;
+ } while (next);
+ }
+
+ if (!(devs = malloc(sizeof(*devs) + (cnt ? cnt * sizeof(*dm_dev) + (char*)names1 - (char*)names + 256 : 0))))
+ return_0;
+
+ dm_list_init(&devs->list);
+ devs->count = cnt;
+ devs->uuids = NULL;
+
+ if (!cnt) {
+ /* nothing in the list -> mark all features present */
+ *devs_features |= (DM_DEVICE_LIST_HAS_EVENT_NR | DM_DEVICE_LIST_HAS_UUID);
+ goto out; /* nothing else to do */
+ }
+
+ dm_dev = (struct dm_active_device *) (devs + 1);
+
+ do {
+ names = (struct dm_names *)((char *) names + next);
+
+ dm_dev->major = MAJOR(names->dev);
+ dm_dev->minor = MINOR(names->dev);
+ dm_dev->name = (char*)(dm_dev + 1);
+ dm_dev->event_nr = 0;
+ dm_dev->uuid = NULL;
+
+ strcpy(dm_dev->name, names->name);
+ len = strlen(names->name) + 1;
+
+ dm_new_dev = _align_ptr((char*)(dm_dev + 1) + len);
+ if (_check_has_event_nr()) {
+ /* Hash for UUIDs with some more bits to reduce colision count */
+ if (!devs->uuids && !(devs->uuids = dm_hash_create(cnt * 8))) {
+ free(devs);
+ return_0;
+ }
+
+ *devs_features |= DM_DEVICE_LIST_HAS_EVENT_NR;
+ event_nr = _align_ptr(names->name + len);
+ dm_dev->event_nr = event_nr[0];
+
+ if ((event_nr[1] & DM_NAME_LIST_FLAG_HAS_UUID)) {
+ *devs_features |= DM_DEVICE_LIST_HAS_UUID;
+ uuid_ptr = _align_ptr(event_nr + 2);
+ dm_dev->uuid = (char*) dm_new_dev;
+ dm_new_dev = _align_ptr((char*)dm_new_dev + strlen(uuid_ptr) + 1);
+ strcpy(dm_dev->uuid, uuid_ptr);
+ if (!dm_hash_insert(devs->uuids, dm_dev->uuid, dm_dev))
+ return_0; // FIXME
+#if 0
+ log_debug("Active %s (%s) %d:%d event:%u",
+ dm_dev->name, dm_dev->uuid,
+ dm_dev->major, dm_dev->minor, dm_dev->event_nr);
+#endif
+ }
+ }
+
+ dm_list_add(&devs->list, &dm_dev->list);
+ dm_dev = dm_new_dev;
+ next = names->next;
+ } while (next);
+
+ out:
+ *devs_list = (struct dm_list *)devs;
+
+ return 1;
+}
+
+int dm_device_list_find_by_uuid(struct dm_list *devs_list, const char *uuid,
+ const struct dm_active_device **dev)
+{
+ struct dm_device_list *devs = (struct dm_device_list *) devs_list;
+ struct dm_active_device *dm_dev;
+
+ if (devs->uuids &&
+ (dm_dev = dm_hash_lookup(devs->uuids, uuid))) {
+ if (dev)
+ *dev = dm_dev;
+ return 1;
+ }
+
+ return 0;
+}
+
+void dm_device_list_destroy(struct dm_list **devs_list)
+{
+ struct dm_device_list *devs = (struct dm_device_list *) *devs_list;
+
+ if (devs) {
+ if (devs->uuids)
+ dm_hash_destroy(devs->uuids);
+
+ free(devs);
+ *devs_list = NULL;
+ }
+}
+
struct dm_names *dm_task_get_names(struct dm_task *dmt)
{
return (struct dm_names *) (((char *) dmt->dmi.v4) +