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

lvmlockctl: use lvm.conf lvmlockctl_kill_command

which specifies a command to run by lvmlockctl --kill.
This commit is contained in:
David Teigland 2021-03-01 15:22:54 -06:00
parent e9d10f3711
commit 89a3440fc0
6 changed files with 184 additions and 52 deletions

3
configure vendored
View File

@ -693,6 +693,7 @@ MANGLING
LVM_RELEASE_DATE LVM_RELEASE_DATE
LVM_RELEASE LVM_RELEASE
LVM_PATH LVM_PATH
LVM_DIR
LVM_PATCHLEVEL LVM_PATCHLEVEL
LVM_MINOR LVM_MINOR
LVM_MAJOR LVM_MAJOR
@ -13766,9 +13767,11 @@ SYSCONFDIR="$(eval echo $(eval echo $sysconfdir))"
SBINDIR="$(eval echo $(eval echo $sbindir))" SBINDIR="$(eval echo $(eval echo $sbindir))"
LVM_PATH="$SBINDIR/lvm" LVM_PATH="$SBINDIR/lvm"
LVM_DIR="$SBINDIR/"
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
#define LVM_PATH "$LVM_PATH" #define LVM_PATH "$LVM_PATH"
#define LVM_DIR "$LVM_DIR"
_ACEOF _ACEOF

View File

@ -1607,7 +1607,9 @@ SYSCONFDIR="$(eval echo $(eval echo $sysconfdir))"
SBINDIR="$(eval echo $(eval echo $sbindir))" SBINDIR="$(eval echo $(eval echo $sbindir))"
LVM_PATH="$SBINDIR/lvm" LVM_PATH="$SBINDIR/lvm"
LVM_DIR="$SBINDIR/"
AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.]) AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.])
AC_DEFINE_UNQUOTED(LVM_DIR, ["$LVM_DIR"], [Path to lvm binary dir.])
LVMCONFIG_PATH="$SBINDIR/lvmconfig" LVMCONFIG_PATH="$SBINDIR/lvmconfig"
AC_DEFINE_UNQUOTED(LVMCONFIG_PATH, ["$LVMCONFIG_PATH"], [Path to lvmconfig binary.]) AC_DEFINE_UNQUOTED(LVMCONFIG_PATH, ["$LVMCONFIG_PATH"], [Path to lvmconfig binary.])

View File

@ -30,6 +30,7 @@ static int kill_vg = 0;
static int drop_vg = 0; static int drop_vg = 0;
static int gl_enable = 0; static int gl_enable = 0;
static int gl_disable = 0; static int gl_disable = 0;
static int use_stderr = 0;
static int stop_lockspaces = 0; static int stop_lockspaces = 0;
static char *arg_vg_name = NULL; static char *arg_vg_name = NULL;
@ -47,6 +48,22 @@ do { \
printf(fmt "\n", ##args); \ printf(fmt "\n", ##args); \
} while (0) } while (0)
#define log_sys_emerg(fmt, args...) \
do { \
if (use_stderr) \
fprintf(stderr, fmt "\n", ##args); \
else \
syslog(LOG_EMERG, fmt, ##args); \
} while (0)
#define log_sys_warn(fmt, args...) \
do { \
if (use_stderr) \
fprintf(stderr, fmt "\n", ##args); \
else \
syslog(LOG_WARNING, fmt, ##args); \
} while (0)
#define MAX_LINE 512 #define MAX_LINE 512
/* copied from lvmlockd-internal.h */ /* copied from lvmlockd-internal.h */
@ -502,51 +519,62 @@ static int do_stop_lockspaces(void)
return rv; return rv;
} }
static int do_kill(void) /* Returns -1 on error, 0 on success. */
static int _get_kill_command(char *kill_cmd)
{ {
daemon_reply reply; char config_cmd[PATH_MAX] = { 0 };
int result; char config_val[1024] = { 0 };
int rv; char line[PATH_MAX] = { 0 };
char type[4] = { 0 };
FILE *fp;
syslog(LOG_EMERG, "Lost access to sanlock lease storage in VG %s.", arg_vg_name); snprintf(config_cmd, PATH_MAX, "%s/lvmconfig --typeconfig full global/lvmlockctl_kill_command", LVM_DIR);
/* These two lines explain the manual alternative to the FIXME below. */ type[0] = 'r';
syslog(LOG_EMERG, "Immediately deactivate LVs in VG %s.", arg_vg_name);
syslog(LOG_EMERG, "Once VG is unused, run lvmlockctl --drop %s.", arg_vg_name);
/* if (!(fp = popen(config_cmd, type))) {
* It may not be strictly necessary to notify lvmlockd of the kill, but log_error("failed to run %s", config_cmd);
* lvmlockd can use this information to avoid attempting any new lock return -1;
* requests in the VG (which would fail anyway), and can return an
* error indicating that the VG has been killed.
*/
reply = _lvmlockd_send("kill_vg",
"cmd = %s", "lvmlockctl",
"pid = " FMTd64, (int64_t) getpid(),
"vg_name = %s", arg_vg_name,
NULL);
if (!_lvmlockd_result(reply, &result)) {
log_error("lvmlockd result %d", result);
rv = result;
} else {
rv = 0;
} }
daemon_reply_destroy(reply); if (!fgets(line, sizeof(line), fp)) {
log_error("no output from %s", config_cmd);
goto bad;
}
/* if (sscanf(line, "lvmlockctl_kill_command=\"%256[^\n\"]\"", config_val) != 1) {
* FIXME: here is where we should implement a strong form of log_error("unrecognized config value from %s", config_cmd);
* blkdeactivate, and if it completes successfully, automatically call goto bad;
* do_drop() afterward. (The drop step may not always be necessary }
* if the lvm commands run while shutting things down release all the
* leases.)
*
* run_strong_blkdeactivate();
* do_drop();
*/
return rv; if (!config_val[0] || (config_val[0] == ' ')) {
log_error("invalid config value from %s", config_cmd);
goto bad;
}
printf("Found lvmlockctl_kill_command: %s\n", config_val);
snprintf(kill_cmd, PATH_MAX, "%s %s", config_val, arg_vg_name);
pclose(fp);
return 0;
bad:
pclose(fp);
return -1;
}
/* Returns -1 on error, 0 on success. */
static int _run_kill_command(char *kill_cmd)
{
int status;
status = system(kill_cmd);
if (!WEXITSTATUS(status))
return 0;
return -1;
} }
static int do_drop(void) static int do_drop(void)
@ -555,7 +583,7 @@ static int do_drop(void)
int result; int result;
int rv; int rv;
syslog(LOG_WARNING, "Dropping locks for VG %s.", arg_vg_name); log_sys_warn("Dropping locks for VG %s.", arg_vg_name);
/* /*
* Check for misuse by looking for any active LVs in the VG * Check for misuse by looking for any active LVs in the VG
@ -583,6 +611,84 @@ static int do_drop(void)
return rv; return rv;
} }
static int do_kill(void)
{
char kill_cmd[PATH_MAX] = { 0 };
daemon_reply reply;
int no_kill_command = 0;
int result;
int rv;
log_sys_emerg("lvmlockd lost access to locks in VG %s.", arg_vg_name);
rv = _get_kill_command(kill_cmd);
if (rv < 0) {
log_sys_emerg("Immediately deactivate LVs in VG %s.", arg_vg_name);
log_sys_emerg("Once VG is unused, run lvmlockctl --drop %s.", arg_vg_name);
no_kill_command = 1;
}
/*
* It may not be strictly necessary to notify lvmlockd of the kill, but
* lvmlockd can use this information to avoid attempting any new lock
* requests in the VG (which would fail anyway), and can return an
* error indicating that the VG has been killed.
*/
_lvmlockd = lvmlockd_open(NULL);
if (_lvmlockd.socket_fd < 0 || _lvmlockd.error) {
log_error("Cannot connect to lvmlockd for kill_vg.");
goto run;
}
reply = _lvmlockd_send("kill_vg",
"cmd = %s", "lvmlockctl",
"pid = " FMTd64, (int64_t) getpid(),
"vg_name = %s", arg_vg_name,
NULL);
if (!_lvmlockd_result(reply, &result))
log_error("lvmlockd result %d kill_vg", result);
daemon_reply_destroy(reply);
lvmlockd_close(_lvmlockd);
run:
if (no_kill_command)
return 0;
rv = _run_kill_command(kill_cmd);
if (rv < 0) {
log_sys_emerg("Failed to run VG %s kill command %s", arg_vg_name, kill_cmd);
log_sys_emerg("Immediately deactivate LVs in VG %s.", arg_vg_name);
log_sys_emerg("Once VG is unused, run lvmlockctl --drop %s.", arg_vg_name);
return -1;
}
log_sys_warn("Successful VG %s kill command %s", arg_vg_name, kill_cmd);
/*
* If kill command was successfully, call do_drop(). (The drop step
* may not always be necessary if the lvm commands run while shutting
* things down release all the leases.)
*/
rv = 0;
_lvmlockd = lvmlockd_open(NULL);
if (_lvmlockd.socket_fd < 0 || _lvmlockd.error) {
log_sys_emerg("Failed to connect to lvmlockd to drop locks in VG %s.", arg_vg_name);
return -1;
}
reply = _lvmlockd_send("drop_vg",
"cmd = %s", "lvmlockctl",
"pid = " FMTd64, (int64_t) getpid(),
"vg_name = %s", arg_vg_name,
NULL);
if (!_lvmlockd_result(reply, &result)) {
log_sys_emerg("Failed to drop locks in VG %s", arg_vg_name);
rv = result;
}
daemon_reply_destroy(reply);
lvmlockd_close(_lvmlockd);
return rv;
}
static void print_usage(void) static void print_usage(void)
{ {
printf("lvmlockctl options\n"); printf("lvmlockctl options\n");
@ -600,7 +706,7 @@ static void print_usage(void)
printf("--force | -f 0|1>\n"); printf("--force | -f 0|1>\n");
printf(" Force option for other commands.\n"); printf(" Force option for other commands.\n");
printf("--kill | -k <vgname>\n"); printf("--kill | -k <vgname>\n");
printf(" Kill access to the VG when sanlock cannot renew lease.\n"); printf(" Kill access to the VG locks are lost (see lvmlockctl_kill_command).\n");
printf("--drop | -r <vgname>\n"); printf("--drop | -r <vgname>\n");
printf(" Clear locks for the VG when it is unused after kill (-k).\n"); printf(" Clear locks for the VG when it is unused after kill (-k).\n");
printf("--gl-enable | -E <vgname>\n"); printf("--gl-enable | -E <vgname>\n");
@ -609,6 +715,8 @@ static void print_usage(void)
printf(" Tell lvmlockd to disable the global lock in a sanlock VG.\n"); printf(" Tell lvmlockd to disable the global lock in a sanlock VG.\n");
printf("--stop-lockspaces | -S\n"); printf("--stop-lockspaces | -S\n");
printf(" Stop all lockspaces.\n"); printf(" Stop all lockspaces.\n");
printf("--stderr | -e\n");
printf(" Send kill and drop messages to stderr instead of syslog\n");
} }
static int read_options(int argc, char *argv[]) static int read_options(int argc, char *argv[])
@ -628,6 +736,7 @@ static int read_options(int argc, char *argv[])
{"gl-enable", required_argument, 0, 'E' }, {"gl-enable", required_argument, 0, 'E' },
{"gl-disable", required_argument, 0, 'D' }, {"gl-disable", required_argument, 0, 'D' },
{"stop-lockspaces", no_argument, 0, 'S' }, {"stop-lockspaces", no_argument, 0, 'S' },
{"stderr", no_argument, 0, 'e' },
{0, 0, 0, 0 } {0, 0, 0, 0 }
}; };
@ -637,7 +746,7 @@ static int read_options(int argc, char *argv[])
} }
while (1) { while (1) {
c = getopt_long(argc, argv, "hqidE:D:w:k:r:S", long_options, &option_index); c = getopt_long(argc, argv, "hqidE:D:w:k:r:Se", long_options, &option_index);
if (c == -1) if (c == -1)
break; break;
@ -680,6 +789,9 @@ static int read_options(int argc, char *argv[])
case 'S': case 'S':
stop_lockspaces = 1; stop_lockspaces = 1;
break; break;
case 'e':
use_stderr = 1;
break;
default: default:
print_usage(); print_usage();
exit(1); exit(1);
@ -698,8 +810,12 @@ int main(int argc, char **argv)
if (rv < 0) if (rv < 0)
return rv; return rv;
_lvmlockd = lvmlockd_open(NULL); /* do_kill handles lvmlockd connections itself */
if (kill_vg)
return do_kill();
_lvmlockd = lvmlockd_open(NULL);
if (_lvmlockd.socket_fd < 0 || _lvmlockd.error) { if (_lvmlockd.socket_fd < 0 || _lvmlockd.error) {
log_error("Cannot connect to lvmlockd."); log_error("Cannot connect to lvmlockd.");
return -1; return -1;
@ -720,11 +836,6 @@ int main(int argc, char **argv)
goto out; goto out;
} }
if (kill_vg) {
rv = do_kill();
goto out;
}
if (drop_vg) { if (drop_vg) {
rv = do_drop(); rv = do_drop();
goto out; goto out;

View File

@ -586,6 +586,9 @@
/* Path to lvm binary. */ /* Path to lvm binary. */
#undef LVM_PATH #undef LVM_PATH
/* Path to lvm binary dir. */
#undef LVM_DIR
/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>. /* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
*/ */
#undef MAJOR_IN_MKDEV #undef MAJOR_IN_MKDEV

View File

@ -1152,6 +1152,15 @@ cfg(global_sanlock_lv_extend_CFG, "sanlock_lv_extend", global_CFG_SECTION, CFG_D
"and can cause lvcreate to fail. Applicable only if LVM is compiled\n" "and can cause lvcreate to fail. Applicable only if LVM is compiled\n"
"with lockd support\n") "with lockd support\n")
cfg(global_lvmlockctl_kill_command_CFG, "lvmlockctl_kill_command", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, "", vsn(2, 3, 12), NULL, 0, NULL,
"The command that lvmlockctl --kill should use to force LVs offline.\n"
"The lvmlockctl --kill command is run when a shared VG has lost\n"
"access to locks (e.g. when sanlock has lost access to storage.)\n"
"An empty string means that there will be no automatic attempt by\n"
"lvmlockctl --kill to forcibly shut down LVs in the VG, and the user\n"
"can manually intervene as described in lvmlockd(8).\n"
"The VG name will be appended to the command specified here.\n")
cfg(global_thin_check_executable_CFG, "thin_check_executable", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, THIN_CHECK_CMD, vsn(2, 2, 94), "@THIN_CHECK_CMD@", 0, NULL, cfg(global_thin_check_executable_CFG, "thin_check_executable", global_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, THIN_CHECK_CMD, vsn(2, 2, 94), "@THIN_CHECK_CMD@", 0, NULL,
"The full path to the thin_check command.\n" "The full path to the thin_check command.\n"
"LVM uses this command to check that a thin metadata device is in a\n" "LVM uses this command to check that a thin metadata device is in a\n"

View File

@ -65,17 +65,21 @@ and prints it.
.SS kill .SS kill
This is run by sanlock when it loses access to the storage holding leases This is run by sanlock when it loses access to the storage holding leases
for a VG. It currently emits a syslog message stating that the VG must for a VG. It runs the command specified in lvm.conf
be immediately deactivated. In the future it may automatically attempt to lvmlockctl_kill_command to deactivate LVs in the VG. If the specified
forcibly deactivate the VG. For more, see command is successful, locks will be dropped for the VG in lvmlockd
(the equivalent of lvmlockctl --drop will be run.) If no command
is specified, or the command fails, then the user must intervene
to forcefully deactivate LVs in the VG, and if successful, run
lvmlockctl --drop. For more, see
.BR lvmlockd (8). .BR lvmlockd (8).
.SS drop .SS drop
This should only be run after a VG has been successfully deactivated This should only be run after a VG has been successfully deactivated
following an lvmlockctl --kill command. It clears the stale lockspace following an lvmlockctl --kill command. It clears the stale lockspace
from lvmlockd. In the future, this may become automatic along with an from lvmlockd. When lvmlockctl_kill_command is used, the --kill
automatic handling of --kill. For more, see command may run drop automatically. For more, see
.BR lvmlockd (8). .BR lvmlockd (8).
.SS gl-enable .SS gl-enable