[lvm-devel] LVM2 ./WHATS_NEW_DM libdm/ioctl/libdm-iface.c
agk at sourceware.org
agk at sourceware.org
Sat Jul 2 01:17:10 UTC 2011
CVSROOT: /cvs/lvm2
Module name: LVM2
Changes by: agk at sourceware.org 2011-07-02 01:17:10
Modified files:
. : WHATS_NEW_DM
libdm/ioctl : libdm-iface.c
Log message:
Report internal error if suspending a device using an already-suspended dev.
This catches the recent pvmove problem trapping I/O between layers.
Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW_DM.diff?cvsroot=lvm2&r1=1.477&r2=1.478
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/libdm/ioctl/libdm-iface.c.diff?cvsroot=lvm2&r1=1.112&r2=1.113
--- LVM2/WHATS_NEW_DM 2011/07/01 14:09:19 1.477
+++ LVM2/WHATS_NEW_DM 2011/07/02 01:17:09 1.478
@@ -1,5 +1,6 @@
Version 1.02.65 -
==================================
+ Report internal error if suspending a device using an already-suspended dev.
Add dmsetup --checks and dm_task_enable_checks framework to validate ioctls.
Add age_in_minutes parameter to dmsetup udevcomplete_all.
Return immediately from dm_lib_exit() if called more than once.
--- LVM2/libdm/ioctl/libdm-iface.c 2011/07/01 14:09:20 1.112
+++ LVM2/libdm/ioctl/libdm-iface.c 2011/07/02 01:17:10 1.113
@@ -1884,13 +1884,104 @@
return r;
}
-static int _suspend_with_validation_v4(struct dm_task *dmt)
+static int _check_children_not_suspended_v4(struct dm_task *dmt, uint64_t device)
{
+ struct dm_task *task;
+ struct dm_info info;
+ struct dm_deps *deps;
+ int r = 0;
+ uint32_t i;
+
+ /* Find dependencies */
+ if (!(task = dm_task_create(DM_DEVICE_DEPS)))
+ return 0;
+
+ /* Copy across or set relevant fields */
+ if (device) {
+ task->major = MAJOR(device);
+ task->minor = MINOR(device);
+ } else {
+ if (dmt->dev_name && !dm_task_set_name(task, dmt->dev_name))
+ goto out;
+
+ if (dmt->uuid && !dm_task_set_uuid(task, dmt->uuid))
+ goto out;
+
+ task->major = dmt->major;
+ task->minor = dmt->minor;
+ }
+
+ task->uid = dmt->uid;
+ task->gid = dmt->gid;
+ task->mode = dmt->mode;
+ /* FIXME: Just for udev_check in dm_task_run. Can we avoid this? */
+ task->event_nr = dmt->event_nr & DM_UDEV_FLAGS_MASK;
+ task->cookie_set = dmt->cookie_set;
+ task->add_node = dmt->add_node;
+
+ if (!(r = dm_task_run(task)))
+ goto out;
+
+ if (!dm_task_get_info(task, &info) || !info.exists)
+ goto out;
+
/*
- * FIXME Ensure we can't leave any I/O trapped between suspended devices.
+ * Warn if any of the devices this device depends upon are already
+ * suspended: I/O could become trapped between the two devices.
*/
+ if (info.suspended) {
+ if (!device)
+ log_debug("Attempting to suspend a device that is already suspended "
+ "(%u:%u)", info.major, info.minor);
+ else
+ log_error(INTERNAL_ERROR "Attempt to suspend device %s%s%s%.0d%s%.0d%s%s"
+ "that uses already-suspended device (%u:%u)",
+ dmt->dev_name ? : "", dmt->uuid ? : "",
+ dmt->major > 0 ? "(" : "",
+ dmt->major > 0 ? dmt->major : 0,
+ dmt->major > 0 ? ":" : "",
+ dmt->minor > 0 ? dmt->minor : 0,
+ dmt->major > 0 && dmt->minor == 0 ? "0" : "",
+ dmt->major > 0 ? ") " : "",
+ info.major, info.minor);
+
+ /* No need for further recursion */
+ r = 1;
+ goto out;
+ }
+
+ if (!(deps = dm_task_get_deps(task)))
+ goto out;
+
+ for (i = 0; i < deps->count; i++) {
+ /* Only recurse with dm devices */
+ if (MAJOR(deps->device[i]) != _dm_device_major)
+ continue;
+
+ if (!_check_children_not_suspended_v4(task, deps->device[i]))
+ goto out;
+ }
+
+ r = 1;
+
+out:
+ dm_task_destroy(task);
+
+ return r;
+}
+
+static int _suspend_with_validation_v4(struct dm_task *dmt)
+{
+ /* Avoid recursion */
dmt->enable_checks = 0;
-
+
+ /*
+ * Ensure we can't leave any I/O trapped between suspended devices.
+ */
+ if (!_check_children_not_suspended_v4(dmt, 0))
+ return 0;
+
+ /* Finally, perform the original suspend. */
return dm_task_run(dmt);
}
More information about the lvm-devel
mailing list