[lvm-devel] [PATCH] dmsetup: provide deferred remove feature
Mikulas Patocka
mpatocka at redhat.com
Fri Aug 15 17:41:24 UTC 2014
Hi
Here I'm sending the update deferred remove patch. I tested that lvm
compiled without this patch works with libdevmapper compiled with this
patch.
From: Mikulas Patocka <mpatocka at redhat.com>
This patch adds a new flag --deferred to dmsetup remove. If this flag is
specified and the device is open, it is scheduled to be deleted on close.
Signed-off-by: Mikulas Patocka <mpatocka at redhat.com>
---
libdm/.exported_symbols | 1 +
libdm/ioctl/libdm-iface.c | 39 ++++++++++++++++++++++++++++++++++++++-
libdm/ioctl/libdm-targets.h | 1 +
libdm/libdevmapper.h | 5 +++++
libdm/misc/dm-ioctl.h | 14 ++++++++++++++
man/dmsetup.8.in | 41 ++++++++++++++++++++---------------------
tools/dmsetup.c | 14 +++++++++++---
7 files changed, 90 insertions(+), 25 deletions(-)
Index: lvm2-copy/tools/dmsetup.c
===================================================================
--- lvm2-copy.orig/tools/dmsetup.c 2014-08-15 16:45:02.000000000 +0200
+++ lvm2-copy/tools/dmsetup.c 2014-08-15 16:50:13.000000000 +0200
@@ -120,6 +120,7 @@ enum {
ADD_NODE_ON_RESUME_ARG,
CHECKS_ARG,
COLS_ARG,
+ DEFERRED_ARG,
SELECT_ARG,
EXEC_ARG,
FORCE_ARG,
@@ -468,9 +469,10 @@ static void _display_info_long(struct dm
printf("Name: %s\n", dm_task_get_name(dmt));
- printf("State: %s%s\n",
+ printf("State: %s%s%s\n",
info->suspended ? "SUSPENDED" : "ACTIVE",
- info->read_only ? " (READ-ONLY)" : "");
+ info->read_only ? " (READ-ONLY)" : "",
+ info->deferred_remove ? " (DEFERRED REMOVE)" : "");
/* FIXME Old value is being printed when it's being changed. */
if (dm_task_get_read_ahead(dmt, &read_ahead))
@@ -1321,6 +1323,9 @@ static int _simple(int task, const char
if (_switches[RETRY_ARG] && task == DM_DEVICE_REMOVE)
dm_task_retry_remove(dmt);
+ if (_switches[DEFERRED_ARG] && (task == DM_DEVICE_REMOVE || task == DM_DEVICE_REMOVE_ALL))
+ dm_task_deferred_remove(dmt);
+
r = dm_task_run(dmt);
out:
@@ -3071,7 +3076,7 @@ static struct command _commands[] = {
"\t [-u|uuid <uuid>] [{--addnodeonresume|--addnodeoncreate}]\n"
"\t [--notable | --table <table> | <table_file>]",
1, 2,0, _create},
- {"remove", "[-f|--force] <device>", 0, -1, 1, _remove},
+ {"remove", "[-f|--force] [--deferred] <device>", 0, -1, 1, _remove},
{"remove_all", "[-f|--force]", 0, 0, 0, _remove_all},
{"suspend", "[--noflush] <device>", 0, -1, 1, _suspend},
{"resume", "<device> [{--addnodeonresume|--addnodeoncreate}]", 0, -1, 1, _resume},
@@ -3521,6 +3526,7 @@ static int _process_switches(int *argc,
{"readonly", 0, &ind, READ_ONLY},
{"checks", 0, &ind, CHECKS_ARG},
{"columns", 0, &ind, COLS_ARG},
+ {"deferred", 0, &ind, DEFERRED_ARG},
{"select", 1, &ind, SELECT_ARG},
{"exec", 1, &ind, EXEC_ARG},
{"force", 0, &ind, FORCE_ARG},
@@ -3694,6 +3700,8 @@ static int _process_switches(int *argc,
/* FIXME Accept modes as per chmod */
_int_args[MODE_ARG] = (int) strtol(optarg, NULL, 8);
}
+ if (ind == DEFERRED_ARG)
+ _switches[DEFERRED_ARG]++;
if (ind == EXEC_ARG) {
_switches[EXEC_ARG]++;
_command = optarg;
Index: lvm2-copy/libdm/ioctl/libdm-iface.c
===================================================================
--- lvm2-copy.orig/libdm/ioctl/libdm-iface.c 2014-08-15 16:45:02.000000000 +0200
+++ lvm2-copy/libdm/ioctl/libdm-iface.c 2014-08-15 17:22:11.000000000 +0200
@@ -17,6 +17,7 @@
#include "libdm-targets.h"
#include "libdm-common.h"
+#include <stddef.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/ioctl.h>
@@ -654,6 +655,7 @@ int dm_task_get_info(struct dm_task *dmt
info->live_table = dmt->dmi.v4->flags & DM_ACTIVE_PRESENT_FLAG ? 1 : 0;
info->inactive_table = dmt->dmi.v4->flags & DM_INACTIVE_PRESENT_FLAG ?
1 : 0;
+ info->deferred_remove = dmt->dmi.v4->flags & DM_DEFERRED_REMOVE;
info->target_count = dmt->dmi.v4->target_count;
info->open_count = dmt->dmi.v4->open_count;
info->event_nr = dmt->dmi.v4->event_nr;
@@ -862,6 +864,13 @@ int dm_task_retry_remove(struct dm_task
return 1;
}
+int dm_task_deferred_remove(struct dm_task *dmt)
+{
+ dmt->deferred_remove = 1;
+
+ return 1;
+}
+
int dm_task_query_inactive_table(struct dm_task *dmt)
{
dmt->query_inactive_table = 1;
@@ -1137,6 +1146,9 @@ static struct dm_ioctl *_flatten(struct
dmi->flags |= DM_READONLY_FLAG;
if (dmt->skip_lockfs)
dmi->flags |= DM_SKIP_LOCKFS_FLAG;
+ if (dmt->deferred_remove && (dmt->type == DM_DEVICE_REMOVE || dmt->type == DM_DEVICE_REMOVE_ALL))
+ dmi->flags |= DM_DEFERRED_REMOVE;
+
if (dmt->secure_data) {
if (_dm_version_minor < 20)
log_verbose("Secure data flag unsupported by kernel. "
@@ -1732,7 +1744,7 @@ static struct dm_ioctl *_do_dm_ioctl(str
}
log_debug_activation("dm %s %s%s %s%s%s %s%.0d%s%.0d%s"
- "%s%c%c%s%s%s%s%s%s %.0" PRIu64 " %s [%u] (*%u)",
+ "%s%c%c%s%s%s%s%s%s%s %.0" PRIu64 " %s [%u] (*%u)",
_cmd_data_v4[dmt->type].name,
dmt->new_uuid ? "UUID " : "",
dmi->name, dmi->uuid, dmt->newname ? " " : "",
@@ -1748,6 +1760,7 @@ static struct dm_ioctl *_do_dm_ioctl(str
dmt->read_only ? "R" : "",
dmt->skip_lockfs ? "S " : "",
dmt->retry_remove ? "T " : "",
+ dmt->deferred_remove ? "D " : "",
dmt->secure_data ? "W " : "",
dmt->query_inactive_table ? "I " : "",
dmt->enable_checks ? "C" : "",
@@ -2006,3 +2019,27 @@ void dm_lib_exit(void)
_version_ok = 1;
_version_checked = 0;
}
+
+/*
+ * This is a trick to add the field deferred_remove to struct dm_info and keep
+ * ABI compatibility.
+ *
+ * The old binaries linked against old version of libdevmapper will use this
+ * function that returns dm_info without the deferred_remove field.
+ *
+ * The new binaries will use dm_task_get_info_with_deferred_remove because of
+ * #define dm_task_get_info dm_task_get_info_with_deferred_remove
+ *
+ * Note that this function must be kept at the end of the file to make sure that
+ * no code in this file accidentally calls it.
+ */
+#undef dm_task_get_info
+int dm_task_get_info(struct dm_task *dmt, struct dm_info *info);
+int dm_task_get_info(struct dm_task *dmt, struct dm_info *info)
+{
+ struct dm_info new_info;
+ if (!dm_task_get_info_with_deferred_remove(dmt, &new_info))
+ return 0;
+ memcpy(info, &new_info, offsetof(struct dm_info, deferred_remove));
+ return 1;
+}
Index: lvm2-copy/libdm/ioctl/libdm-targets.h
===================================================================
--- lvm2-copy.orig/libdm/ioctl/libdm-targets.h 2014-08-15 16:45:02.000000000 +0200
+++ lvm2-copy/libdm/ioctl/libdm-targets.h 2014-08-15 16:50:13.000000000 +0200
@@ -65,6 +65,7 @@ struct dm_task {
int new_uuid;
int secure_data;
int retry_remove;
+ int deferred_remove;
int enable_checks;
int expected_errno;
Index: lvm2-copy/libdm/libdevmapper.h
===================================================================
--- lvm2-copy.orig/libdm/libdevmapper.h 2014-08-15 16:45:02.000000000 +0200
+++ lvm2-copy/libdm/libdevmapper.h 2014-08-15 16:58:32.000000000 +0200
@@ -149,6 +149,8 @@ struct dm_info {
int read_only; /* 0:read-write; 1:read-only */
int32_t target_count;
+
+ int deferred_remove;
};
struct dm_deps {
@@ -172,6 +174,8 @@ struct dm_versions {
int dm_get_library_version(char *version, size_t size);
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size);
+
+#define dm_task_get_info dm_task_get_info_with_deferred_remove
int dm_task_get_info(struct dm_task *dmt, struct dm_info *dmi);
/*
@@ -222,6 +226,7 @@ int dm_task_query_inactive_table(struct
int dm_task_suppress_identical_reload(struct dm_task *dmt);
int dm_task_secure_data(struct dm_task *dmt);
int dm_task_retry_remove(struct dm_task *dmt);
+int dm_task_deferred_remove(struct dm_task *dmt);
/*
* Enable checks for common mistakes such as issuing ioctls in an unsafe order.
Index: lvm2-copy/libdm/misc/dm-ioctl.h
===================================================================
--- lvm2-copy.orig/libdm/misc/dm-ioctl.h 2014-08-15 16:45:02.000000000 +0200
+++ lvm2-copy/libdm/misc/dm-ioctl.h 2014-08-15 16:50:13.000000000 +0200
@@ -343,4 +343,18 @@ enum {
*/
#define DM_DATA_OUT_FLAG (1 << 16) /* Out */
+/*
+ * Remove the device when it is closed.
+ *
+ * This flag may be set on DM_DEV_REMOVE or DM_REMOVE_ALL to indicate that
+ * the device should be remove on close if it is open.
+ *
+ * On return from DM_DEV_REMOVE, this flag indicates that the device was not
+ * removed because it was open, but it is scheduled to be removed on close.
+ *
+ * When this flag is returned in DM_DEV_STATUS or other ioctls, it indicates
+ * that the device is scheduled to be removed on close.
+ */
+#define DM_DEFERRED_REMOVE (1 << 17) /* In/Out */
+
#endif /* _LINUX_DM_IOCTL_H */
Index: lvm2-copy/libdm/.exported_symbols
===================================================================
--- lvm2-copy.orig/libdm/.exported_symbols 2014-08-15 17:10:02.000000000 +0200
+++ lvm2-copy/libdm/.exported_symbols 2014-08-15 17:10:06.000000000 +0200
@@ -1,2 +1,3 @@
dm_log
dm_log_with_errno
+dm_task_get_info
Index: lvm2-copy/man/dmsetup.8.in
===================================================================
--- lvm2-copy.orig/man/dmsetup.8.in 2014-08-15 17:22:56.000000000 +0200
+++ lvm2-copy/man/dmsetup.8.in 2014-08-15 18:52:24.000000000 +0200
@@ -81,10 +81,12 @@ dmsetup \(em low level logical volume ma
.B dmsetup remove
.RB [ \-f | \-\-force ]
.RB [ \-\-retry ]
+.RB [ \-\-deferred ]
.I device_name
.br
.B dmsetup remove_all
.RB [ \-f | \-\-force ]
+.RB [ \-\-deferred ]
.br
.B dmsetup rename
.I device_name new_name
@@ -436,34 +438,31 @@ reactivating it with proper mangling mod
.B remove
.RB [ \-f | \-\-force ]
.RB [ \-\-retry ]
+.RB [ \-\-deferred ]
.I device_name
.br
-Removes a device. It will no longer be visible to dmsetup.
-Open devices cannot be removed except with older kernels
-that contain a version of device-mapper prior to 4.8.0.
-In this case the device will be deleted when its open_count
-drops to zero. From version 4.8.0 onwards, if a device can't
-be removed because an uninterruptible process is waiting for
-I/O to return from it, adding \fB\-\-force\fP will replace the table
-with one that fails all I/O, which might allow the
-process to be killed. If an attempt to remove a device fails,
-perhaps because a process run from a quick udev rule
-temporarily opened the device, the \fB\-\-retry\fP option will cause
-the operation to be retried for a few seconds before failing.
-Do NOT combine \fB\-\-force\fP and \fB\-\-udevcookie\fP,
-as udev may start to process udev rules in the middle of error target
-replacement and result in nondeterministic result.
+Removes a device. It will no longer be visible to dmsetup. Open devices cannot
+be removed, adding \fB\-\-force\fP will replace the table with one that fails
+all I/O. \fB\-\-deferred\fP will enable deferred removal of open devices - the
+device will be removed when the last user closes it. The deferred removal
+feature is present in kernels starting with 3.13. If an attempt to remove a
+device fails, perhaps because a process run from a quick udev rule temporarily
+opened the device, the \fB\-\-retry\fP option will cause the operation to be
+retried for a few seconds before failing. Do NOT combine \fB\-\-force\fP and
+\fB\-\-udevcookie\fP, as udev may start to process udev rules in the middle of
+error target replacement and result in nondeterministic result.
.br
.HP
.B remove_all
.RB [ \-f | \-\-force ]
+.RB [ \-\-deferred ]
.br
-Attempts to remove all device definitions i.e. reset the driver.
-Use with care! From version 4.8.0 onwards, if devices can't
-be removed because uninterruptible processes are waiting for
-I/O to return from them, adding \fB\-\-force\fP will replace the table
-with one that fails all I/O, which might allow the
-process to be killed. This also runs \fBmknodes\fP afterwards.
+Attempts to remove all device definitions i.e. reset the driver. This also runs
+\fBmknodes\fP afterwards. Use with care! Open devices cannot be removed,
+adding \fB\-\-force\fP will replace the table with one that fails all I/O.
+\fB\-\-deferred\fP will enable deferred removal of open devices - the device
+will be removed when the last user closes it. The deferred removal feature is
+present in kernels starting with 3.13.
.br
.HP
.B rename
More information about the lvm-devel
mailing list