1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

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>
This commit is contained in:
Alasdair G Kergon 2014-08-16 00:34:48 +01:00
parent ec41bd1920
commit 42e07d2bce
7 changed files with 86 additions and 25 deletions

View File

@ -1,5 +1,6 @@
Version 1.02.89 - 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. Update dm-ioctl.h to include DM_DEFERRED_REMOVE flag.
Add support for selection to match string list subset, recognize { } operator. Add support for selection to match string list subset, recognize { } operator.
Fix string list selection with '[value]' to not match list that's superset. Fix string list selection with '[value]' to not match list that's superset.

View File

@ -1,2 +1,3 @@
dm_log dm_log
dm_log_with_errno dm_log_with_errno
dm_task_get_info

View File

@ -17,6 +17,7 @@
#include "libdm-targets.h" #include "libdm-targets.h"
#include "libdm-common.h" #include "libdm-common.h"
#include <stddef.h>
#include <fcntl.h> #include <fcntl.h>
#include <dirent.h> #include <dirent.h>
#include <sys/ioctl.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->live_table = dmt->dmi.v4->flags & DM_ACTIVE_PRESENT_FLAG ? 1 : 0;
info->inactive_table = dmt->dmi.v4->flags & DM_INACTIVE_PRESENT_FLAG ? info->inactive_table = dmt->dmi.v4->flags & DM_INACTIVE_PRESENT_FLAG ?
1 : 0; 1 : 0;
info->deferred_remove = dmt->dmi.v4->flags & DM_DEFERRED_REMOVE;
info->target_count = dmt->dmi.v4->target_count; info->target_count = dmt->dmi.v4->target_count;
info->open_count = dmt->dmi.v4->open_count; info->open_count = dmt->dmi.v4->open_count;
info->event_nr = dmt->dmi.v4->event_nr; info->event_nr = dmt->dmi.v4->event_nr;
@ -862,6 +864,13 @@ int dm_task_retry_remove(struct dm_task *dmt)
return 1; 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) int dm_task_query_inactive_table(struct dm_task *dmt)
{ {
dmt->query_inactive_table = 1; 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; dmi->flags |= DM_READONLY_FLAG;
if (dmt->skip_lockfs) if (dmt->skip_lockfs)
dmi->flags |= DM_SKIP_LOCKFS_FLAG; 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 (dmt->secure_data) {
if (_dm_version_minor < 20) if (_dm_version_minor < 20)
log_verbose("Secure data flag unsupported by kernel. " 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" 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, _cmd_data_v4[dmt->type].name,
dmt->new_uuid ? "UUID " : "", dmt->new_uuid ? "UUID " : "",
dmi->name, dmi->uuid, dmt->newname ? " " : "", 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->read_only ? "R" : "",
dmt->skip_lockfs ? "S " : "", dmt->skip_lockfs ? "S " : "",
dmt->retry_remove ? "T " : "", dmt->retry_remove ? "T " : "",
dmt->deferred_remove ? "D " : "",
dmt->secure_data ? "W " : "", dmt->secure_data ? "W " : "",
dmt->query_inactive_table ? "I " : "", dmt->query_inactive_table ? "I " : "",
dmt->enable_checks ? "C" : "", dmt->enable_checks ? "C" : "",
@ -2006,3 +2019,32 @@ void dm_lib_exit(void)
_version_ok = 1; _version_ok = 1;
_version_checked = 0; _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;
}

View File

@ -65,6 +65,7 @@ struct dm_task {
int new_uuid; int new_uuid;
int secure_data; int secure_data;
int retry_remove; int retry_remove;
int deferred_remove;
int enable_checks; int enable_checks;
int expected_errno; int expected_errno;

View File

@ -149,6 +149,8 @@ struct dm_info {
int read_only; /* 0:read-write; 1:read-only */ int read_only; /* 0:read-write; 1:read-only */
int32_t target_count; int32_t target_count;
int deferred_remove;
}; };
struct dm_deps { struct dm_deps {
@ -172,6 +174,8 @@ struct dm_versions {
int dm_get_library_version(char *version, size_t size); 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); 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); 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_suppress_identical_reload(struct dm_task *dmt);
int dm_task_secure_data(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_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. * Enable checks for common mistakes such as issuing ioctls in an unsafe order.

View File

@ -81,10 +81,12 @@ dmsetup \(em low level logical volume management
.B dmsetup remove .B dmsetup remove
.RB [ \-f | \-\-force ] .RB [ \-f | \-\-force ]
.RB [ \-\-retry ] .RB [ \-\-retry ]
.RB [ \-\-deferred ]
.I device_name .I device_name
.br .br
.B dmsetup remove_all .B dmsetup remove_all
.RB [ \-f | \-\-force ] .RB [ \-f | \-\-force ]
.RB [ \-\-deferred ]
.br .br
.B dmsetup rename .B dmsetup rename
.I device_name new_name .I device_name new_name
@ -436,34 +438,35 @@ reactivating it with proper mangling mode used (see also \fB\-\-manglename\fP).
.B remove .B remove
.RB [ \-f | \-\-force ] .RB [ \-f | \-\-force ]
.RB [ \-\-retry ] .RB [ \-\-retry ]
.RB [ \-\-deferred ]
.I device_name .I device_name
.br .br
Removes a device. It will no longer be visible to dmsetup. Removes a device. It will no longer be visible to dmsetup. Open devices
Open devices cannot be removed except with older kernels cannot be removed, but adding \fB\-\-force\fP will replace the table with one
that contain a version of device-mapper prior to 4.8.0. that fails all I/O. \fB\-\-deferred\fP will enable deferred removal of open
In this case the device will be deleted when its open_count devices - the device will be removed when the last user closes it. The deferred
drops to zero. From version 4.8.0 onwards, if a device can't removal feature is supported since version 4.27.0 of the device-mapper
be removed because an uninterruptible process is waiting for driver available in upstream kernel version 3.13. (Use \fBdmsetup version\fP
I/O to return from it, adding \fB\-\-force\fP will replace the table to check this.) If an attempt to remove a device fails, perhaps because a process run
with one that fails all I/O, which might allow the from a quick udev rule temporarily opened the device, the \fB\-\-retry\fP
process to be killed. If an attempt to remove a device fails, option will cause the operation to be retried for a few seconds before failing.
perhaps because a process run from a quick udev rule Do NOT combine
temporarily opened the device, the \fB\-\-retry\fP option will cause \fB\-\-force\fP and \fB\-\-udevcookie\fP, as udev may start to process udev
the operation to be retried for a few seconds before failing. rules in the middle of error target replacement and result in nondeterministic
Do NOT combine \fB\-\-force\fP and \fB\-\-udevcookie\fP, result.
as udev may start to process udev rules in the middle of error target
replacement and result in nondeterministic result.
.br .br
.HP .HP
.B remove_all .B remove_all
.RB [ \-f | \-\-force ] .RB [ \-f | \-\-force ]
.RB [ \-\-deferred ]
.br .br
Attempts to remove all device definitions i.e. reset the driver. Attempts to remove all device definitions i.e. reset the driver. This also runs
Use with care! From version 4.8.0 onwards, if devices can't \fBmknodes\fP afterwards. Use with care! Open devices cannot be removed, but
be removed because uninterruptible processes are waiting for adding \fB\-\-force\fP will replace the table with one that fails all I/O.
I/O to return from them, adding \fB\-\-force\fP will replace the table \fB\-\-deferred\fP will enable deferred removal of open devices - the device
with one that fails all I/O, which might allow the will be removed when the last user closes it. The deferred removal feature is
process to be killed. This also runs \fBmknodes\fP afterwards. supported since version 4.27.0 of the device-mapper driver available in
upstream kernel version 3.13.
.br .br
.HP .HP
.B rename .B rename

View File

@ -120,6 +120,7 @@ enum {
ADD_NODE_ON_RESUME_ARG, ADD_NODE_ON_RESUME_ARG,
CHECKS_ARG, CHECKS_ARG,
COLS_ARG, COLS_ARG,
DEFERRED_ARG,
SELECT_ARG, SELECT_ARG,
EXEC_ARG, EXEC_ARG,
FORCE_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("Name: %s\n", dm_task_get_name(dmt));
printf("State: %s%s\n", printf("State: %s%s%s\n",
info->suspended ? "SUSPENDED" : "ACTIVE", 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. */ /* FIXME Old value is being printed when it's being changed. */
if (dm_task_get_read_ahead(dmt, &read_ahead)) 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) if (_switches[RETRY_ARG] && task == DM_DEVICE_REMOVE)
dm_task_retry_remove(dmt); 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); r = dm_task_run(dmt);
out: out:
@ -3071,7 +3076,7 @@ static struct command _commands[] = {
"\t [-u|uuid <uuid>] [{--addnodeonresume|--addnodeoncreate}]\n" "\t [-u|uuid <uuid>] [{--addnodeonresume|--addnodeoncreate}]\n"
"\t [--notable | --table <table> | <table_file>]", "\t [--notable | --table <table> | <table_file>]",
1, 2,0, _create}, 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}, {"remove_all", "[-f|--force]", 0, 0, 0, _remove_all},
{"suspend", "[--noflush] <device>", 0, -1, 1, _suspend}, {"suspend", "[--noflush] <device>", 0, -1, 1, _suspend},
{"resume", "<device> [{--addnodeonresume|--addnodeoncreate}]", 0, -1, 1, _resume}, {"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}, {"readonly", 0, &ind, READ_ONLY},
{"checks", 0, &ind, CHECKS_ARG}, {"checks", 0, &ind, CHECKS_ARG},
{"columns", 0, &ind, COLS_ARG}, {"columns", 0, &ind, COLS_ARG},
{"deferred", 0, &ind, DEFERRED_ARG},
{"select", 1, &ind, SELECT_ARG}, {"select", 1, &ind, SELECT_ARG},
{"exec", 1, &ind, EXEC_ARG}, {"exec", 1, &ind, EXEC_ARG},
{"force", 0, &ind, FORCE_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 */ /* FIXME Accept modes as per chmod */
_int_args[MODE_ARG] = (int) strtol(optarg, NULL, 8); _int_args[MODE_ARG] = (int) strtol(optarg, NULL, 8);
} }
if (ind == DEFERRED_ARG)
_switches[DEFERRED_ARG]++;
if (ind == EXEC_ARG) { if (ind == EXEC_ARG) {
_switches[EXEC_ARG]++; _switches[EXEC_ARG]++;
_command = optarg; _command = optarg;