summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlasdair G Kergon <agk@redhat.com>2014-08-16 00:34:48 +0100
committerAlasdair G Kergon <agk@redhat.com>2014-08-16 00:34:48 +0100
commit42e07d2bceaad21f197de5dde9ead69742425159 (patch)
treeb73d0969c48c9ef830047655a0c53f13ae2de43d
parentec41bd1920be119538cd9c98a8fc3d38e184803f (diff)
downloadlvm2-42e07d2bceaad21f197de5dde9ead69742425159.tar.gz
dmsetup: Support remove --deferred.
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. struct dm_info is extended. The existing dm_task_get_info() is converted into a wrapper around the new version dm_task_get_info_with_deferred_remove() so existing binaries can still use the old smaller structure. Recompiled code will pick up the new larger structure. From: Mikulas Patocka <mpatocka@redhat.com>
-rw-r--r--WHATS_NEW_DM1
-rw-r--r--libdm/.exported_symbols1
-rw-r--r--libdm/ioctl/libdm-iface.c44
-rw-r--r--libdm/ioctl/libdm-targets.h1
-rw-r--r--libdm/libdevmapper.h5
-rw-r--r--man/dmsetup.8.in47
-rw-r--r--tools/dmsetup.c14
7 files changed, 87 insertions, 26 deletions
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 41aa89de5..4a2c8b405 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,6 @@
Version 1.02.89 -
=================================
+ Support --deferred with dmsetup remove to defer removal of open devices.
Update dm-ioctl.h to include DM_DEFERRED_REMOVE flag.
Add support for selection to match string list subset, recognize { } operator.
Fix string list selection with '[value]' to not match list that's superset.
diff --git a/libdm/.exported_symbols b/libdm/.exported_symbols
index 3a6986085..5bacc26e2 100644
--- a/libdm/.exported_symbols
+++ b/libdm/.exported_symbols
@@ -1,2 +1,3 @@
dm_log
dm_log_with_errno
+dm_task_get_info
diff --git a/libdm/ioctl/libdm-iface.c b/libdm/ioctl/libdm-iface.c
index 345651b30..4f55ddf3a 100644
--- a/libdm/ioctl/libdm-iface.c
+++ b/libdm/ioctl/libdm-iface.c
@@ -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, struct dm_info *info)
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 *dmt)
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 dm_task *dmt, unsigned repeat_count)
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(struct dm_task *dmt, unsigned command,
}
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(struct dm_task *dmt, unsigned command,
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,32 @@ void dm_lib_exit(void)
_version_ok = 1;
_version_checked = 0;
}
+
+/*
+ * This following code is here to retain ABI compatibility after adding
+ * the field deferred_remove to struct dm_info in version 1.02.89.
+ *
+ * Binaries linked against version 1.02.88 of libdevmapper or earlier
+ * will use this function that returns dm_info without the
+ * deferred_remove field.
+ *
+ * Binaries compiled against version 1.02.89 onwards will use
+ * the new function dm_task_get_info_with_deferred_remove due to the
+ * #define.
+ *
+ * N.B. Keep this function 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;
+}
diff --git a/libdm/ioctl/libdm-targets.h b/libdm/ioctl/libdm-targets.h
index 54223c752..100681fec 100644
--- a/libdm/ioctl/libdm-targets.h
+++ b/libdm/ioctl/libdm-targets.h
@@ -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;
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index e37ee39b9..bf8a65831 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -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 dm_task *dmt);
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.
diff --git a/man/dmsetup.8.in b/man/dmsetup.8.in
index b18b0b008..477e4252b 100644
--- a/man/dmsetup.8.in
+++ b/man/dmsetup.8.in
@@ -81,10 +81,12 @@ dmsetup \(em low level logical volume management
.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,35 @@ reactivating it with proper mangling mode used (see also \fB\-\-manglename\fP).
.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, but 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 supported since version 4.27.0 of the device-mapper
+driver available in upstream kernel version 3.13. (Use \fBdmsetup version\fP
+to check this.) 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 ]
-.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.
+.RB [ \-\-deferred ]
+.br
+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, but
+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
+supported since version 4.27.0 of the device-mapper driver available in
+upstream kernel version 3.13.
.br
.HP
.B rename
diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index c679c52e5..8f64bfce6 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -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_task *dmt, struct dm_info *info)
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 *name, uint32_t event_nr, int display)
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, char ***argv, const char *dev_dir)
{"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, char ***argv, const char *dev_dir)
/* 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;