From 0e814226e081d228c96a8cc43e5cec484dc78306 Mon Sep 17 00:00:00 2001
From: Heming Zhao <heming.zhao@suse.com>
Date: Fri, 8 Oct 2021 09:33:39 +0800
Subject: [PATCH 11/14] dlm_tool dlm_controld: add new feature set_config

set_config command makes dlm_controld could change options value dynamically.

Signed-off-by: Heming Zhao <heming.zhao@suse.com>
---
 dlm_controld/config.c        | 169 +++++++++++++++++++++++++++++++++++
 dlm_controld/dlm_controld.h  |   1 +
 dlm_controld/dlm_daemon.h    |  11 +++
 dlm_controld/helper.c        |   4 -
 dlm_controld/lib.c           |  38 +++++++-
 dlm_controld/libdlmcontrol.h |   1 +
 dlm_controld/main.c          |  22 ++++-
 dlm_tool/main.c              |  29 +++++-
 8 files changed, 264 insertions(+), 11 deletions(-)

diff --git a/dlm_controld/config.c b/dlm_controld/config.c
index c60be8d47ef0..a7ebb120a6b8 100644
--- a/dlm_controld/config.c
+++ b/dlm_controld/config.c
@@ -387,3 +387,172 @@ void set_opt_file(int update)
 	fclose(file);
 }
 
+/*
+ * do the clean/restore job:
+ * - clean up dlm_options[].dynamic_xx
+ * - using top priority item to set use option
+ */
+static void reset_dynamic(int index)
+{
+	struct dlm_option *o = &dlm_options[index];
+
+	if (!o->reload)
+		return;
+
+	o->dynamic_set = 0;
+	o->dynamic_int = 0;
+	if (o->dynamic_str){
+		free(o->dynamic_str);
+		o->dynamic_str = NULL;
+	}
+	o->dynamic_uint = 0;
+	reset_opt_value(index);
+
+	return;
+}
+
+/* copy code from exec_command() */
+void set_opt_online(char *cmd_str, int cmd_len)
+{
+	int i, ind, val = 0;
+	int av_count = 0;
+	int arg_len;
+	unsigned int uval = 0;
+	struct dlm_option *o;
+	char str[MAX_LINE];
+	char arg[ONE_ARG_LEN];
+	char *av[MAX_AV_COUNT + 1]; /* +1 for NULL */
+
+	if (cmd_len > RUN_COMMAND_LEN)
+		return;
+
+	for (i = 0; i < MAX_AV_COUNT + 1; i++)
+		av[i] = NULL;
+
+	if (!cmd_str[0])
+		return;
+
+	/* this should already be done, but make sure */
+	cmd_str[cmd_len - 1] = '\0';
+
+	memset(&arg, 0, sizeof(arg));
+	arg_len = 0;
+	cmd_len = strlen(cmd_str);
+
+	for (i = 0; i < cmd_len; i++) {
+		if (!cmd_str[i])
+			break;
+
+		if (av_count == MAX_AV_COUNT)
+			break;
+
+		if (cmd_str[i] == '\\') {
+			if (i == (cmd_len - 1))
+				break;
+			i++;
+
+			if (cmd_str[i] == '\\') {
+				arg[arg_len++] = cmd_str[i];
+				continue;
+			}
+			if (isspace(cmd_str[i])) {
+				arg[arg_len++] = cmd_str[i];
+				continue;
+			} else {
+				break;
+			}
+		}
+
+		if (isalnum(cmd_str[i]) || ispunct(cmd_str[i])) {
+			arg[arg_len++] = cmd_str[i];
+		} else if (isspace(cmd_str[i])) {
+			if (arg_len)
+				av[av_count++] = strdup(arg);
+
+			memset(arg, 0, sizeof(arg));
+			arg_len = 0;
+		} else {
+			break;
+		}
+	}
+
+	if ((av_count < MAX_AV_COUNT) && arg_len) {
+		av[av_count++] = strdup(arg);
+	}
+
+	/*
+	for (i = 0; i < MAX_AV_COUNT + 1; i++) {
+		if (!av[i])
+			break;
+
+		syslog(LOG_ERR, "command av[%d] \"%s\"", i, av[i]);
+	}
+	*/
+
+	if (!strcmp(av[0], "restore_all")) {
+		for (i = 0; i < dlm_options_max; i++)
+			reset_dynamic(i);
+		return;
+	}
+
+    i = -1;
+	while (++i < av_count) {
+
+		ind = get_ind_name(av[i]);
+		if (ind < 0)
+			continue;
+		o = &dlm_options[ind];
+		if (!o || !o->reload)
+			continue;
+
+		get_val_str(av[i], str);
+		if (!strcmp(str, "restore")) {
+			reset_dynamic(ind);
+			continue;
+		}
+
+		o->dynamic_set++;
+
+		if (!o->req_arg || o->req_arg == req_arg_int) {
+			get_val_int(av[i], &val);
+			if (!o->req_arg)
+				val = val ? 1 : 0;
+
+			o->dynamic_int = val;
+
+			log_debug("config dynamic %s = %d previous use %d",
+				  o->name, o->dynamic_int, o->use_int);
+			o->use_int = o->dynamic_int;
+
+		} else if (o->req_arg == req_arg_uint) {
+			get_val_uint(av[i], &uval);
+			o->dynamic_uint = uval;
+
+			log_debug("config dynamic %s = %u previous use %u",
+				  o->name, o->dynamic_uint, o->use_uint);
+			o->use_uint = o->dynamic_uint;
+
+		} else if (o->req_arg == req_arg_bool) {
+			get_val_int(av[i], &val);
+			o->dynamic_int = val ? 1 : 0;
+
+			log_debug("config dynamic %s = %d previous use %d",
+				  o->name, o->dynamic_int, o->use_int);
+			o->use_int = o->dynamic_int;
+
+		} else if (o->req_arg == req_arg_str) {
+			memset(str, 0, sizeof(str));
+			get_val_str(av[i], str);
+
+			o->dynamic_str = strdup(str);
+
+			log_debug("config dynamic %s = %s previous use %s",
+				  o->name, o->dynamic_str, o->use_str);
+			o->use_str = o->dynamic_str;
+		}
+
+		reload_setting(ind);
+	}
+
+	return;
+}
diff --git a/dlm_controld/dlm_controld.h b/dlm_controld/dlm_controld.h
index 0ea3548fce7d..94e5c49e88bd 100644
--- a/dlm_controld/dlm_controld.h
+++ b/dlm_controld/dlm_controld.h
@@ -36,6 +36,7 @@
 #define DLMC_CMD_RUN_CHECK		16
 #define DLMC_CMD_DUMP_RUN		17
 #define DLMC_CMD_RELOAD_CONFIG	18
+#define DLMC_CMD_SET_CONFIG		19
 
 struct dlmc_header {
 	unsigned int magic;
diff --git a/dlm_controld/dlm_daemon.h b/dlm_controld/dlm_daemon.h
index 9e68f8257cb5..da261774bee0 100644
--- a/dlm_controld/dlm_daemon.h
+++ b/dlm_controld/dlm_daemon.h
@@ -25,6 +25,7 @@
 #include <arpa/inet.h>
 #include <net/if.h>
 #include <stdio.h>
+#include <ctype.h>
 #include <errno.h>
 #include <string.h>
 #include <stdlib.h>
@@ -133,6 +134,7 @@ struct dlm_option {
 	char letter;
 	int req_arg;
 	char reload;
+	char dynamic;
 	const char *desc;
 
 	int use_int;
@@ -152,6 +154,11 @@ struct dlm_option {
 	int file_int;
 	char *file_str;
 	unsigned int file_uint;
+
+	int dynamic_set;
+	int dynamic_int;
+	char *dynamic_str;
+	unsigned int dynamic_uint;
 };
 
 EXTERN struct dlm_option dlm_options[dlm_options_max];
@@ -328,6 +335,9 @@ struct lockspace {
 
 #define RUN_COMMAND_LEN DLMC_RUN_COMMAND_LEN /* 1024 */
 
+#define MAX_AV_COUNT 32
+#define ONE_ARG_LEN 256
+
 struct run_info {
 	int dest_nodeid;
 	int start_nodeid;
@@ -390,6 +400,7 @@ int set_configfs_opt(const char *name, char *str, int num);
 void set_opt_file(int update);
 int get_weight(struct lockspace *ls, int nodeid);
 void setup_lockspace_config(struct lockspace *ls);
+void set_opt_online(char *cmd_str, int cmd_len);
 
 /* cpg.c */
 void process_lockspace_changes(void);
diff --git a/dlm_controld/helper.c b/dlm_controld/helper.c
index a20965b76195..469dd22095f0 100644
--- a/dlm_controld/helper.c
+++ b/dlm_controld/helper.c
@@ -20,7 +20,6 @@
 #include <time.h>
 #include <stdarg.h>
 #include <signal.h>
-#include <ctype.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -29,9 +28,6 @@
 
 #include "dlm_daemon.h"
 
-#define MAX_AV_COUNT 32
-#define ONE_ARG_LEN 256
-
 
 static int _log_stderr;
 
diff --git a/dlm_controld/lib.c b/dlm_controld/lib.c
index 951eb6561ba9..8cbdd27f15e2 100644
--- a/dlm_controld/lib.c
+++ b/dlm_controld/lib.c
@@ -189,7 +189,43 @@ int dlmc_reload_config(void)
 
 	rv = do_write(fd, &h, sizeof(h));
 	close(fd);
- out:
+out:
+	return rv;
+}
+
+int dlmc_set_config(char *command)
+{
+	struct dlmc_header h;
+	char *cmdbuf;
+	int fd, rv;
+
+	cmdbuf = malloc(DLMC_RUN_COMMAND_LEN);
+	if (!cmdbuf)
+		return -1;
+
+	memset(cmdbuf, 0, DLMC_RUN_COMMAND_LEN);
+	strncpy(cmdbuf, command, DLMC_RUN_COMMAND_LEN-1);
+
+	init_header(&h, DLMC_CMD_SET_CONFIG, NULL, DLMC_RUN_COMMAND_LEN);
+
+	fd = do_connect(DLMC_SOCK_PATH);
+	if (fd < 0) {
+		rv = fd;
+		goto out;
+	}
+
+	rv = do_write(fd, &h, sizeof(h));
+	if (rv < 0)
+		goto out_close;
+
+	rv = do_write(fd, cmdbuf, DLMC_RUN_COMMAND_LEN);
+	if (rv < 0)
+		goto out_close;
+
+out_close:
+	close(fd);
+out:
+	free(cmdbuf);
 	return rv;
 }
 
diff --git a/dlm_controld/libdlmcontrol.h b/dlm_controld/libdlmcontrol.h
index ac84e702fb58..a106171b1073 100644
--- a/dlm_controld/libdlmcontrol.h
+++ b/dlm_controld/libdlmcontrol.h
@@ -92,6 +92,7 @@ int dlmc_lockspace_nodes(char *lsname, int type, int max, int *count,
 			 struct dlmc_node *nodes);
 int dlmc_print_status(uint32_t flags);
 int dlmc_reload_config(void);
+int dlmc_set_config(char *command);
 
 #define DLMC_RESULT_REGISTER	1
 #define DLMC_RESULT_NOTIFIED	2
diff --git a/dlm_controld/main.c b/dlm_controld/main.c
index 8104d8f906ac..3a081c802056 100644
--- a/dlm_controld/main.c
+++ b/dlm_controld/main.c
@@ -919,7 +919,7 @@ static void copy_options(char *buf, int *len)
 {
 	struct dlm_option *o;
 	char tmp[256];
-	int i, ret, pos = 0;
+	int i, ret, pos = 0, l = 0;
 
 	for (i = 0; i < dlm_options_max; i++) {
 		o = &dlm_options[i];
@@ -927,9 +927,20 @@ static void copy_options(char *buf, int *len)
 		memset(tmp, 0, sizeof(tmp));
 
 		if (o->req_arg == req_arg_str)
-			snprintf(tmp, 255, "%s=%s\n", o->name, o->use_str);
+			l = snprintf(tmp, 250, "%s=%s", o->name, o->use_str);
+		else if (o->req_arg == req_arg_uint)
+			l = snprintf(tmp, 250, "%s=%u", o->name, o->use_uint);
+		else
+			l = snprintf(tmp, 250, "%s=%d", o->name, o->use_int);
+
+		if (o->dynamic_set)
+			snprintf(tmp + l, 15, " (set_config)\n");
+		else if (o->cli_set)
+			snprintf(tmp + l, 15, " (cli option)\n");
+		else if (o->file_set)
+			snprintf(tmp + l, 15, " (dlm.conf)\n");
 		else
-			snprintf(tmp, 255, "%s=%d\n", o->name, o->use_int);
+			snprintf(tmp + l, 15, "\n");
 
 		if (pos + strlen(tmp) >= LOG_DUMP_SIZE)
 			break;
@@ -1234,6 +1245,11 @@ static void process_connection(int ci)
 		set_opt_file(1);
 		break;
 
+	case DLMC_CMD_SET_CONFIG:
+		if (extra_len)
+			set_opt_online(extra, extra_len);
+		break;
+
 	default:
 		log_error("process_connection %d unknown command %d",
 			  ci, h.command);
diff --git a/dlm_tool/main.c b/dlm_tool/main.c
index 774835192bbf..bce5c1da3c95 100644
--- a/dlm_tool/main.c
+++ b/dlm_tool/main.c
@@ -48,6 +48,7 @@
 #define OP_RUN_LIST			18
 #define OP_DUMP_RUN			19
 #define OP_RELOAD_CONFIG	20
+#define OP_SET_CONFIG		21
 
 static char *prog_name;
 static char *lsname;
@@ -197,7 +198,8 @@ static void print_usage(void)
 	printf("dlm_tool [command] [options] [name]\n");
 	printf("\n");
 	printf("Commands:\n");
-	printf("ls, status, dump, dump_config, reload_config, fence_ack\n");
+	printf("ls, status, dump, fence_ack\n");
+	printf("dump_config, reload_config, set_config\n");
 	printf("log_plock, plocks\n");
 	printf("join, leave, lockdebug\n");
 	printf("run, run_start, run_check, run_cancel, run_list\n");
@@ -370,6 +372,13 @@ static void decode_arguments(int argc, char **argv)
 			opt_ind = optind + 1;
 			need_lsname = 0;
 			break;
+		} else if (!strncmp(argv[optind], "set_config", 10) &&
+			   (strlen(argv[optind]) == 10)) {
+			operation = OP_SET_CONFIG;
+			opt_ind = optind + 1;
+			need_lsname = 0;
+			need_command = 1;
+			break;
 		} else if (!strncmp(argv[optind], "plocks", 6) &&
 			   (strlen(argv[optind]) == 6)) {
 			operation = OP_PLOCKS;
@@ -477,8 +486,10 @@ static void decode_arguments(int argc, char **argv)
 			exit(EXIT_FAILURE);
 		}
 
-		strcat(run_command, argv[i]);
-		strcat(run_command, " ");
+		if (strlen(argv[i])) {
+			strcat(run_command, argv[i]);
+			strcat(run_command, " ");
+		}
 	}
 }
 
@@ -1487,6 +1498,14 @@ static void do_reload_config(void)
 		printf("reload_config done\n");
 }
 
+static void do_set_config(void)
+{
+	if (dlmc_set_config(run_command) < 0)
+		printf("set_config failed\n");
+	else
+		printf("set_config done\n");
+}
+
 static void do_log_plock(void)
 {
 	char buf[DLMC_DUMP_SIZE];
@@ -1589,6 +1608,10 @@ int main(int argc, char **argv)
 		do_reload_config();
 		break;
 
+	case OP_SET_CONFIG:
+		do_set_config();
+		break;
+
 	case OP_LOG_PLOCK:
 		do_log_plock();
 		break;
-- 
2.33.0

