From 6433cb9d8e1f083bd94c0d3aaf84378a887bdf82 Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Sun, 18 Jun 2006 11:35:04 +0000 Subject: [PATCH] Add --force to dmsetup remove* to load error target. [Untested.] Update dmsetup man page. --- WHATS_NEW | 2 + dmsetup/dmsetup.c | 146 +++++++++++++++++++++++++++++++++++++++++----- man/dmsetup.8 | 34 ++++++++--- 3 files changed, 160 insertions(+), 22 deletions(-) diff --git a/WHATS_NEW b/WHATS_NEW index 158b0c8..0aba42a 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,7 @@ Version 1.02.08 - ============================= + Update dmsetup man page. + Add --force to dmsetup remove* to load error target. dmsetup remove_all also performs mknodes. Don't suppress identical table reloads if permission changes. Fix corelog segment line. diff --git a/dmsetup/dmsetup.c b/dmsetup/dmsetup.c index 3a42a25..d2d7cb2 100644 --- a/dmsetup/dmsetup.c +++ b/dmsetup/dmsetup.c @@ -88,6 +88,7 @@ enum { READ_ONLY = 0, COLS_ARG, EXEC_ARG, + FORCE_ARG, GID_ARG, MAJOR_ARG, MINOR_ARG, @@ -108,6 +109,7 @@ enum { static int _switches[NUM_SWITCHES]; static int _values[NUM_SWITCHES]; +static int _num_devices; static char *_uuid; static char *_fields; static char *_target; @@ -386,7 +388,7 @@ static int _create(int argc, char **argv, void *data __attribute((unused))) if (argc == 3) file = argv[2]; - + if (!(dmt = dm_task_create(DM_DEVICE_CREATE))) return 0; @@ -602,16 +604,6 @@ static int _simple(int task, const char *name, uint32_t event_nr, int display) return r; } -static int _remove_all(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused))) -{ - return _simple(DM_DEVICE_REMOVE_ALL, "", 0, 0) | dm_mknodes(NULL); -} - -static int _remove(int argc, char **argv, void *data __attribute((unused))) -{ - return _simple(DM_DEVICE_REMOVE, argc > 1 ? argv[1] : NULL, 0, 0); -} - static int _suspend(int argc, char **argv, void *data __attribute((unused))) { return _simple(DM_DEVICE_SUSPEND, argc > 1 ? argv[1] : NULL, 0, 1); @@ -683,6 +675,127 @@ static int _process_all(int argc, char **argv, return r; } +static uint64_t _get_device_size(const char *name) +{ + uint64_t start, length, size = UINT64_C(0); + struct dm_info info; + char *target_type, *params; + struct dm_task *dmt; + void *next; + + if (!(dmt = dm_task_create(DM_DEVICE_TABLE))) + return 0; + + if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) + goto out; + + if (!dm_task_run(dmt)) + goto out; + + if (!dm_task_get_info(dmt, &info) || !info.exists) + goto out; + + do { + next = dm_get_next_target(dmt, next, &start, &length, + &target_type, ¶ms); + size += length; + } while (next); + + out: + dm_task_destroy(dmt); + return size; +} + +static int _error_device(int argc __attribute((unused)), char **argv __attribute((unused)), void *data) +{ + struct dm_names *names = (struct dm_names *) data; + struct dm_task *dmt; + const char *name; + uint64_t size; + + if (data) + name = names->name; + else + name = argv[1]; + + size = _get_device_size(name); + + if (!(dmt = dm_task_create(DM_DEVICE_RELOAD))) + return 0; + + if (!dm_task_add_target(dmt, 0, size, "error", "")) + goto err_task; + + if (_switches[READ_ONLY] && !dm_task_set_ro(dmt)) + goto err_task; + + if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) + goto err_task; + + if (!dm_task_run(dmt)) + goto err_task; + + if (!_simple(DM_DEVICE_RESUME, name, 0, 0)) + goto err_clear; + + return 1; + +err_task: + dm_task_destroy(dmt); + return 0; + +err_clear: + _simple(DM_DEVICE_CLEAR, name, 0, 0); + return 0; +} + +static int _remove(int argc, char **argv, void *data __attribute((unused))) +{ + int r; + + if (_switches[FORCE_ARG] && argc > 1) + r = _error_device(argc, argv, NULL); + + return _simple(DM_DEVICE_REMOVE, argc > 1 ? argv[1] : NULL, 0, 0); +} + +static int _count_devices(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused))) +{ + _num_devices++; + + return 1; +} + +static int _remove_all(int argc __attribute((unused)), char **argv __attribute((unused)), void *data __attribute((unused))) +{ + int r; + + /* Remove all closed devices */ + r = _simple(DM_DEVICE_REMOVE_ALL, "", 0, 0) | dm_mknodes(NULL); + + if (!_switches[FORCE_ARG]) + return r; + + _num_devices = 0; + r |= _process_all(argc, argv, _count_devices); + + /* No devices left? */ + if (!_num_devices) + return r; + + r |= _process_all(argc, argv, _error_device); + r |= _simple(DM_DEVICE_REMOVE_ALL, "", 0, 0) | dm_mknodes(NULL); + + _num_devices = 0; + r |= _process_all(argc, argv, _count_devices); + if (!_num_devices) + return r; + + fprintf(stderr, "Unable to remove %d devices.", _num_devices); + + return r; +} + static void _display_dev(struct dm_task *dmt, const char *name) { struct dm_info info; @@ -1355,8 +1468,8 @@ static struct command _commands[] = { "\t [-U|--uid ] [-G|--gid ] [-M|--mode ]\n" "\t [-u|uuid ] [--notable] []", 1, 2, _create}, - {"remove", "", 0, 1, _remove}, - {"remove_all", "", 0, 0, _remove_all}, + {"remove", "[-f|--force] ", 0, 1, _remove}, + {"remove_all", "[-f|--force]", 0, 0, _remove_all}, {"suspend", "", 0, 1, _suspend}, {"resume", "", 0, 1, _resume}, {"load", " []", 0, 2, _load}, @@ -1482,6 +1595,7 @@ static int _process_switches(int *argc, char ***argv) {"readonly", 0, &ind, READ_ONLY}, {"columns", 0, &ind, COLS_ARG}, {"exec", 1, &ind, EXEC_ARG}, + {"force", 0, &ind, FORCE_ARG}, {"gid", 1, &ind, GID_ARG}, {"major", 1, &ind, MAJOR_ARG}, {"minor", 1, &ind, MINOR_ARG}, @@ -1526,7 +1640,7 @@ static int _process_switches(int *argc, char ***argv) _values[MINOR_ARG] = atoi((*argv)[2]); *argc -= 2; *argv += 2; - } else if ((*argc == 2) && + } else if ((*argc == 2) && (2 == sscanf((*argv)[1], "%i:%i", &_values[MAJOR_ARG], &_values[MINOR_ARG]))) { @@ -1545,10 +1659,12 @@ static int _process_switches(int *argc, char ***argv) optarg = 0; optind = OPTIND_INIT; - while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCGj:m:Mno:ru:Uv", + while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfGj:m:Mno:ru:Uv", long_options, NULL)) != -1) { if (c == 'c' || c == 'C' || ind == COLS_ARG) _switches[COLS_ARG]++; + if (c == 'f' || ind == FORCE_ARG) + _switches[FORCE_ARG]++; if (c == 'r' || ind == READ_ONLY) _switches[READ_ONLY]++; if (c == 'j' || ind == MAJOR_ARG) { diff --git a/man/dmsetup.8 b/man/dmsetup.8 index a58dd15..42d452a 100644 --- a/man/dmsetup.8 +++ b/man/dmsetup.8 @@ -7,9 +7,10 @@ dmsetup \- low level logical volume management .I device_name [-u uuid] [--notable] [table_file] .br .B dmsetup remove -.I device_name +.I [-f|--force] device_name .br .B dmsetup remove_all +.I [-f|--force] .br .B dmsetup suspend .I [--nolockfs] device_name @@ -103,7 +104,7 @@ Set the table being loaded read-only. .IP \fB-u|--uuid .br Specify the uuid. -.IP \fB-v|--verbose [-v|--verbose] +.IP \fB-v|--verbose\ [-v|--verbose] .br Produce additional output. .IP \fB--version @@ -163,15 +164,34 @@ ascii, utf, vt100; compact, inverted, notrunc. .br Loads table_file into the inactive table slot for device_name. If table_file is not supplied, reads a table from standard input. -.IP \fBremove -.I device_name +.IP \fBmknodes +.I [device_name] .br -Removes a device. It will no longer be visible to dmsetup and -will be deleted when its open_count is zero. +Ensure that the node in /dev/mapper for device_name is correct. +If no device_name is supplied, ensure that all nodes in /dev/mapper +correspond to mapped devices currently loaded by the device-mapper kernel +driver, adding, changing or removing nodes as necessary. +.IP \fBremove +.I [-f|--force] 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 --force will replace the table +with one that fails all I/O, which might allow the +process to be killed. .IP \fBremove_all +.I [-f|--force] .br Attempts to remove all device definitions i.e. reset the driver. -Use with care! +Use with care! From version 4.8.0 onwards, if devices can't +be removed because uninterruptible processess are waiting for +I/O to return from them, adding --force 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. .IP \fBrename .I device_name new_name .br -- 2.43.5