Re: [PATCH] sanlock: host_message
by Nir Soffer
Hi David,
I'm working now on sanlock fencing feature for ovirt.
I have some questions and suggestions regarding the patch.
> A host can send a predefined msg_num to another host.
>
> The host messages are sent from one host to another via
> a lockspace that both hosts are using. If no lockspace
> name is specified, the sanlock daemon will search for a
> common lockspace to use. (N.B. hosts do not necessarily
> use the same host_id in all lockspaces, so not specifying
> the lockspace could result in targeting the wrong host.)
I think that making the lockspace a required parameter makes
more sense and will avoid fatal errors.
> The lockspace used to transmit the message may or may not
> have any other relation to the message itself.
>
> A host can send one message to a one other host at a time.
Can we increase this number, simplifying (unlikely) case where
more then one host need to be fenced?
> The message is placed in the sending host's delta lease,
> and remains there for two renewals. When the receiving
> host renews its own delta lease, it checks the delta leases
> of all other hosts, and sees itself addressed in the sending
> host's lease. It then processes the message from the
> sending host.
Why did you choose the keep the message for two renewals?
We would like to have this value configurable, to make
it easier to solve issues in the field.
I think we have to handle the (unlikely) case, where a host
lost its lease without seeing the WD_RESET message, then
acquire the lease again (not sure if this is possible in vdsm
currently). The fencing host may assume wrongly that the host
was fenced in this case.
What if we leave the WD_RESET message until the fencing host
send a WD_UNRESET message?
This way I can send a WD_RESET message, wait for some renwals,
ensuring that the host either lost it's lease, or will *not*
get a new lease, until I decide to allow the host to get one.
We may have a case where we cannot access a host, we fence it,
ensuring that it cannot access the storage, but the host never
see the fence request, and keeping it in "fenced" mode is
required until we can reboot the bost using power management
or manually.
>
> If a message is currently active in a lockspace, the
> sending host_message call will return -EBUSY. After two
> renewals (around 40 seconds), another message may be sent.
>
> An optional host generation can be included, in which
> case the receiving host_id will accept the message only
> if its current generation matches.
>
> The single msg_num defined here is WD_RESET (1), which
> means that the host receiving the message should use
> its watchdog device to reset itself as soon as possible.
> The WD_RESET message has no effect on any lockspaces
> or resources that may exist. Existing lockspaces and
> resources continue to operate as usual until the reset.
> (A watchdog reset due to "standard" lockspace failure
> could in fact occur before the watchdog reset caused
> by the host message.)
>
> Because host messages may not be received if the
> destination host fails, or looses storage access,
> there are no guaranteed times associated with the
> delivery, processing or effect of a host message.
> Guaranteed times for another host being dead should
> continue to be based on either acquiring a resource,
> or sanlock_get_hosts().
What would be the best way to detect that the host was fenced?
>
> TODO: will be adding another msg_num to cause the
> destination to use /proc/sysrq-trigger to reboot itself.
> (After setting up the watchdog to reset the machine in
> case the sysrq mechanism fails.) The sysrq reboot is
> immediate, whereas the watchdog takes a minute to reset.
Maybe use WD_FENCE, and let sanlock use the best available
method for fencing?
Can we customize the actions taken by sanlock when receiving
the WD_RESET message? For example, running a script after
the message was received?
What would be the best way to detect if a host supports
the new fencing feature - check its sanlock version?
Regards,
Nir
10 years
src/client.c src/cmd.c src/main.c src/sanlock_admin.h src/sanlock_internal.h src/sanlock_sock.h
by David Teigland
src/client.c | 33 +++++++++++++++++
src/cmd.c | 43 +++++++++++++++++++++-
src/main.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++--
src/sanlock_admin.h | 2 +
src/sanlock_internal.h | 8 ++++
src/sanlock_sock.h | 2 +
6 files changed, 178 insertions(+), 4 deletions(-)
New commits:
commit 78885dec2747e17af7e648146b0fe7ab5b388483
Author: David Teigland <teigland(a)redhat.com>
Date: Mon Jan 27 15:53:58 2014 -0600
sanlock: version interface
Add the ability for a client to get the version
of the running daemon.
Start using the "version" field in the sm_header
struct used for daemon/client ipc. This is not
the sanlock version, but the socket ipc protocol
version.
Signed-off-by: David Teigland <teigland(a)redhat.com>
diff --git a/src/client.c b/src/client.c
index 14c70d1..9e523ae 100644
--- a/src/client.c
+++ b/src/client.c
@@ -71,6 +71,7 @@ static int send_header(int sock, int cmd, uint32_t cmd_flags, int datalen,
memset(&header, 0, sizeof(struct sm_header));
header.magic = SM_MAGIC;
+ header.version = SM_PROTO;
header.cmd = cmd;
header.cmd_flags = cmd_flags;
header.length = sizeof(header) + datalen;
@@ -741,6 +742,38 @@ int sanlock_restrict(int sock, uint32_t flags)
return rv;
}
+int sanlock_version(uint32_t flags, uint32_t *version, uint32_t *proto)
+{
+ struct sm_header h;
+ int fd, rv;
+
+ rv = connect_socket(&fd);
+ if (rv < 0)
+ return rv;
+
+ rv = send_header(fd, SM_CMD_VERSION, flags, 0, 0, 0);
+ if (rv < 0)
+ return rv;
+
+ memset(&h, 0, sizeof(struct sm_header));
+
+ rv = recv(fd, &h, sizeof(h), MSG_WAITALL);
+ if (rv < 0)
+ return -errno;
+ if (rv != sizeof(h))
+ return -1;
+
+ if (proto)
+ *proto = h.version;
+
+ rv = (int)h.data;
+ if (rv < 0)
+ return rv;
+
+ *version = h.data2;
+ return 0;
+}
+
int sanlock_killpath(int sock, uint32_t flags, const char *path, char *args)
{
char path_max[SANLK_HELPER_PATH_LEN];
diff --git a/src/cmd.c b/src/cmd.c
index 13ad405..f19e8fb 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -826,6 +826,7 @@ static void cmd_inquire(struct task *task, struct cmd_args *ca)
}
memcpy(&h, &ca->header, sizeof(struct sm_header));
+ h.version = SM_PROTO;
h.data = result;
h.data2 = res_count;
@@ -1143,6 +1144,7 @@ static void cmd_get_lvb(struct task *task GNUC_UNUSED, struct cmd_args *ca)
result = res_get_lvb(&res, &lvb, &lvblen);
reply:
memcpy(&h, &ca->header, sizeof(struct sm_header));
+ h.version = SM_PROTO;
h.data = result;
h.data2 = 0;
h.length = sizeof(h) + lvblen;
@@ -1439,6 +1441,7 @@ static void cmd_read_lockspace(struct task *task, struct cmd_args *ca)
log_debug("cmd_read_lockspace %d,%d done %d", ca->ci_in, fd, result);
memcpy(&h, &ca->header, sizeof(struct sm_header));
+ h.version = SM_PROTO;
h.data = result;
h.data2 = io_timeout;
h.length = sizeof(h) + sizeof(lockspace);
@@ -1531,6 +1534,7 @@ static void cmd_read_resource(struct task *task, struct cmd_args *ca)
log_debug("cmd_read_resource %d,%d done %d", ca->ci_in, fd, result);
memcpy(&h, &ca->header, sizeof(struct sm_header));
+ h.version = SM_PROTO;
h.data = result;
h.data2 = 0;
h.length = sizeof(h) + sizeof(res);
@@ -1626,6 +1630,7 @@ static void cmd_read_resource_owners(struct task *task, struct cmd_args *ca)
log_debug("cmd_read_resource_owners %d,%d count %d done %d", ca->ci_in, fd, count, result);
memcpy(&h, &ca->header, sizeof(struct sm_header));
+ h.version = SM_PROTO;
h.data = result;
h.data2 = count;
h.length = sizeof(h) + sizeof(res) + send_len;
@@ -1938,7 +1943,11 @@ static int print_state_daemon(char *str)
"helper_kill_fd=%d "
"helper_full_count=%u "
"helper_last_status=%llu "
- "monotime=%llu",
+ "monotime=%llu "
+ "version_str=%s "
+ "version_num=%u.%u.%u "
+ "version_hex=%08x "
+ "smproto_hex=%08x",
our_host_name_global,
main_task.use_aio,
kill_grace_seconds,
@@ -1946,7 +1955,13 @@ static int print_state_daemon(char *str)
helper_kill_fd,
helper_full_count,
(unsigned long long)helper_last_status,
- (unsigned long long)monotime());
+ (unsigned long long)monotime(),
+ VERSION,
+ sanlock_version_major,
+ sanlock_version_minor,
+ sanlock_version_patch,
+ sanlock_version_combined,
+ SM_PROTO);
return strlen(str) + 1;
}
@@ -2195,6 +2210,7 @@ static void cmd_status(int fd, struct sm_header *h_recv, int client_maxi)
memset(&h, 0, sizeof(h));
memcpy(&h, h_recv, sizeof(struct sm_header));
+ h.version = SM_PROTO;
h.length = sizeof(h);
h.data = 0;
@@ -2248,6 +2264,7 @@ static void cmd_host_status(int fd, struct sm_header *h_recv)
memset(&h, 0, sizeof(h));
memcpy(&h, h_recv, sizeof(struct sm_header));
+ h.version = SM_PROTO;
h.length = sizeof(h);
h.data = 0;
@@ -2303,6 +2320,7 @@ static void cmd_log_dump(int fd, struct sm_header *h_recv)
copy_log_dump(send_data_buf, &len);
+ h_recv->version = SM_PROTO;
h_recv->data = len;
send(fd, h_recv, sizeof(struct sm_header), MSG_NOSIGNAL);
@@ -2315,6 +2333,7 @@ static void cmd_get_lockspaces(int fd, struct sm_header *h_recv)
rv = get_lockspaces(send_data_buf, &len, &count, LOG_DUMP_SIZE);
+ h_recv->version = SM_PROTO;
h_recv->length = sizeof(struct sm_header) + len;
h_recv->data = rv;
h_recv->data2 = count;
@@ -2331,6 +2350,7 @@ static void cmd_get_hosts(int fd, struct sm_header *h_recv)
memset(&h, 0, sizeof(h));
memcpy(&h, h_recv, sizeof(struct sm_header));
+ h.version = SM_PROTO;
h.length = sizeof(h);
h.data = 0;
@@ -2358,9 +2378,24 @@ static void cmd_restrict(int ci, int fd, struct sm_header *h_recv)
client[ci].restricted = h_recv->cmd_flags;
+ h_recv->version = SM_PROTO;
send_result(fd, h_recv, 0);
}
+static void cmd_version(int ci GNUC_UNUSED, int fd, struct sm_header *h_recv)
+{
+ h_recv->magic = SM_MAGIC;
+ h_recv->version = SM_PROTO;
+ h_recv->cmd = SM_CMD_VERSION;
+ h_recv->cmd_flags = 0;
+ h_recv->length = sizeof(struct sm_header);
+ h_recv->seq = 0;
+ h_recv->data = 0;
+ h_recv->data2 = sanlock_version_combined;
+
+ send(fd, h_recv, sizeof(struct sm_header), MSG_NOSIGNAL);
+}
+
static int get_peer_pid(int fd, int *pid)
{
struct ucred cred;
@@ -2409,6 +2444,10 @@ void call_cmd_daemon(int ci, struct sm_header *h_recv, int client_maxi)
cmd_restrict(ci, fd, h_recv);
auto_close = 0;
break;
+ case SM_CMD_VERSION:
+ cmd_version(ci, fd, h_recv);
+ auto_close = 0;
+ break;
case SM_CMD_SHUTDOWN:
strcpy(client[ci].owner_name, "shutdown");
if (h_recv->data) {
diff --git a/src/main.c b/src/main.c
index 421ea67..5f3c6ed 100644
--- a/src/main.c
+++ b/src/main.c
@@ -436,6 +436,7 @@ void send_result(int fd, struct sm_header *h_recv, int result)
struct sm_header h;
memcpy(&h, h_recv, sizeof(struct sm_header));
+ h.version = SM_PROTO;
h.length = sizeof(h);
h.data = result;
h.data2 = 0;
@@ -1158,12 +1159,19 @@ static void process_connection(int ci)
ci, client[ci].fd, client[ci].pid, h.cmd);
goto dead;
}
+ if (h.version && (h.cmd != SM_CMD_VERSION) &&
+ (h.version & 0xFFFF0000) > (SM_PROTO & 0xFFFF0000)) {
+ log_error("ci %d recv %d proto %x vs %x",
+ ci, rv, h.version , SM_PROTO);
+ goto dead;
+ }
client[ci].cmd_last = h.cmd;
switch (h.cmd) {
case SM_CMD_REGISTER:
case SM_CMD_RESTRICT:
+ case SM_CMD_VERSION:
case SM_CMD_SHUTDOWN:
case SM_CMD_STATUS:
case SM_CMD_HOST_STATUS:
@@ -1864,8 +1872,14 @@ static int read_command_line(int argc, char *argv[])
exit(EXIT_SUCCESS);
}
- if (!strcmp(arg1, "version") || !strcmp(arg1, "--version") ||
- !strcmp(arg1, "-V")) {
+ if (!strcmp(arg1, "version")) {
+ printf("%u.%u.%u\n",
+ sanlock_version_major, sanlock_version_minor,
+ sanlock_version_patch);
+ exit(EXIT_SUCCESS);
+ }
+
+ if (!strcmp(arg1, "--version") || !strcmp(arg1, "-V")) {
printf("%s %s (built %s %s)\n",
argv[0], VERSION, __DATE__, __TIME__);
exit(EXIT_SUCCESS);
@@ -1939,6 +1953,8 @@ static int read_command_line(int argc, char *argv[])
com.action = ACT_CLIENT_INIT;
else if (!strcmp(act, "read"))
com.action = ACT_CLIENT_READ;
+ else if (!strcmp(act, "version"))
+ com.action = ACT_VERSION;
else {
log_tool("client action \"%s\" is unknown", act);
exit(EXIT_FAILURE);
@@ -2315,6 +2331,38 @@ static int do_client_read(void)
return rv;
}
+static void do_client_version(void)
+{
+ uint32_t version = 0;
+ uint32_t proto = 0;
+ int rv;
+
+ rv = sanlock_version(0, &version, &proto);
+ if (rv < 0) {
+ log_tool("daemon version error %d", rv);
+ }
+
+ log_tool("client version %u.%u.%u (0x%08x)",
+ sanlock_version_major,
+ sanlock_version_minor,
+ sanlock_version_patch,
+ sanlock_version_combined);
+
+ log_tool("daemon version %u.%u.%u (0x%08x)",
+ (version & 0xFF000000) >> 24,
+ (version & 0x00FF0000) >> 16,
+ (version & 0x0000FF00) >> 8,
+ version);
+
+ log_tool("client socket protocol %u.%u",
+ (SM_PROTO & 0xFFFF0000) >> 16,
+ (SM_PROTO & 0x0000FFFF));
+
+ log_tool("daemon socket protocol %u.%u",
+ (proto & 0xFFFF0000) >> 16,
+ (proto & 0x0000FFFF));
+}
+
static int do_client(void)
{
struct sanlk_resource **res_args = NULL;
@@ -2499,6 +2547,10 @@ static int do_client(void)
rv = do_client_read();
break;
+ case ACT_VERSION:
+ do_client_version();
+ break;
+
default:
log_tool("action not implemented");
rv = -1;
@@ -2608,6 +2660,42 @@ static int do_direct(void)
return rv;
}
+static void set_sanlock_version(void)
+{
+ char version_str[64];
+ char *major_str, *minor_str, *patch_str;
+ char *d1, *d2;
+
+ strncpy(version_str, VERSION, 64);
+
+ d1 = strstr(version_str, ".");
+ if (!d1)
+ return;
+
+ d2 = strstr(d1 + 1, ".");
+ if (!d2)
+ return;
+
+ major_str = version_str;
+ minor_str = d1 + 1;
+ patch_str = d2 + 1;
+
+ *d1 = '\0';
+ *d2 = '\0';
+
+ sanlock_version_major = atoi(major_str);
+ sanlock_version_minor = atoi(minor_str);
+ sanlock_version_patch = atoi(patch_str);
+
+ sanlock_version_build = 0; /* TODO */
+
+ sanlock_version_combined = 0;
+ sanlock_version_combined |= sanlock_version_major << 24;
+ sanlock_version_combined |= sanlock_version_minor << 16;
+ sanlock_version_combined |= sanlock_version_patch << 8;
+ sanlock_version_combined |= sanlock_version_build;
+}
+
int main(int argc, char *argv[])
{
int rv;
@@ -2618,6 +2706,8 @@ int main(int argc, char *argv[])
/* initialize global EXTERN variables */
+ set_sanlock_version();
+
kill_count_max = 100;
kill_grace_seconds = DEFAULT_GRACE_SEC;
helper_ci = -1;
diff --git a/src/sanlock_admin.h b/src/sanlock_admin.h
index 1a781b1..f76b2dc 100644
--- a/src/sanlock_admin.h
+++ b/src/sanlock_admin.h
@@ -276,4 +276,6 @@ int sanlock_test_resource_owners(struct sanlk_resource *res, uint32_t flags,
struct sanlk_host *hosts, int hosts_count,
uint32_t *test_flags);
+int sanlock_version(uint32_t flags, uint32_t *version, uint32_t *proto);
+
#endif
diff --git a/src/sanlock_internal.h b/src/sanlock_internal.h
index a448a5c..c3fa574 100644
--- a/src/sanlock_internal.h
+++ b/src/sanlock_internal.h
@@ -325,6 +325,7 @@ enum {
ACT_CLIENT_ALIGN,
ACT_EXAMINE,
ACT_GETS,
+ ACT_VERSION,
};
EXTERN int external_shutdown;
@@ -344,5 +345,12 @@ EXTERN struct list_head spaces_rem;
EXTERN struct list_head spaces_add;
EXTERN pthread_mutex_t spaces_mutex;
+/* major.minor.patch-build (TODO: get build) */
+EXTERN uint8_t sanlock_version_major;
+EXTERN uint8_t sanlock_version_minor;
+EXTERN uint8_t sanlock_version_patch;
+EXTERN uint8_t sanlock_version_build;
+EXTERN uint32_t sanlock_version_combined;
+
#endif
diff --git a/src/sanlock_sock.h b/src/sanlock_sock.h
index b2f7304..c5c1ec9 100644
--- a/src/sanlock_sock.h
+++ b/src/sanlock_sock.h
@@ -14,6 +14,7 @@
#define SANLK_SOCKET_NAME "sanlock.sock"
#define SM_MAGIC 0x04282010
+#define SM_PROTO 0x00000001
#define MAX_CLIENT_MSG (1024 * 1024) /* TODO: this is random */
@@ -45,6 +46,7 @@ enum {
SM_CMD_SET_LVB = 25,
SM_CMD_GET_LVB = 26,
SM_CMD_CONVERT = 27,
+ SM_CMD_VERSION = 28,
};
struct sm_header {
10 years, 1 month
[PATCH] sanlock: host_message
by David Teigland
A host can send a predefined msg_num to another host.
The host messages are sent from one host to another via
a lockspace that both hosts are using. If no lockspace
name is specified, the sanlock daemon will search for a
common lockspace to use. (N.B. hosts do not necessarily
use the same host_id in all lockspaces, so not specifying
the lockspace could result in targeting the wrong host.)
The lockspace used to transmit the message may or may not
have any other relation to the message itself.
A host can send one message to a one other host at a time.
The message is placed in the sending host's delta lease,
and remains there for two renewals. When the receiving
host renews its own delta lease, it checks the delta leases
of all other hosts, and sees itself addressed in the sending
host's lease. It then processes the message from the
sending host.
If a message is currently active in a lockspace, the
sending host_message call will return -EBUSY. After two
renewals (around 40 seconds), another message may be sent.
An optional host generation can be included, in which
case the receiving host_id will accept the message only
if its current generation matches.
The single msg_num defined here is WD_RESET (1), which
means that the host receiving the message should use
its watchdog device to reset itself as soon as possible.
The WD_RESET message has no effect on any lockspaces
or resources that may exist. Existing lockspaces and
resources continue to operate as usual until the reset.
(A watchdog reset due to "standard" lockspace failure
could in fact occur before the watchdog reset caused
by the host message.)
Because host messages may not be received if the
destination host fails, or looses storage access,
there are no guaranteed times associated with the
delivery, processing or effect of a host message.
Guaranteed times for another host being dead should
continue to be based on either acquiring a resource,
or sanlock_get_hosts().
TODO: will be adding another msg_num to cause the
destination to use /proc/sysrq-trigger to reboot itself.
(After setting up the watchdog to reset the machine in
case the sysrq mechanism fails.) The sysrq reboot is
immediate, whereas the watchdog takes a minute to reset.
Signed-off-by: David Teigland <teigland(a)redhat.com>
---
src/client.c | 51 +++++++++++++++++++++++++++
src/cmd.c | 30 ++++++++++++++++
src/delta_lease.c | 15 +++++++-
src/delta_lease.h | 1 +
src/direct.c | 1 +
src/lockspace.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++--
src/lockspace.h | 1 +
src/main.c | 23 +++++++++++--
src/resource.c | 58 +++++++++++++++++++++++++++++++
src/resource.h | 3 ++
src/sanlock.8 | 15 ++++++++
src/sanlock.h | 10 ++++++
src/sanlock_admin.h | 15 ++++++++
src/sanlock_internal.h | 9 +++--
src/sanlock_sock.h | 1 +
src/watchdog.c | 65 +++++++++++++++++++++++++++++++++++
src/watchdog.h | 1 +
17 files changed, 383 insertions(+), 9 deletions(-)
diff --git a/src/client.c b/src/client.c
index 14c70d1788d4..87100e59cf5b 100644
--- a/src/client.c
+++ b/src/client.c
@@ -701,6 +701,57 @@ int sanlock_test_resource_owners(struct sanlk_resource *res GNUC_UNUSED,
return 0;
}
+int sanlock_host_message(const char *ls_name, uint32_t flags,
+ int hm_size, struct sanlk_host_message *hm)
+{
+ struct sanlk_lockspace ls;
+ struct sanlk_host_message msg;
+ int rv, fd;
+
+ if (!hm || !hm_size)
+ return -EINVAL;
+
+ memset(&ls, 0, sizeof(struct sanlk_lockspace));
+ if (ls_name)
+ strncpy(ls.name, ls_name, SANLK_NAME_LEN);
+
+ rv = connect_socket(&fd);
+ if (rv < 0)
+ return rv;
+
+ memset(&msg, 0, sizeof(msg));
+
+ if (hm_size < sizeof(msg))
+ memcpy(&msg, hm, hm_size);
+ else if (hm_size > sizeof(msg))
+ memcpy(&msg, hm, sizeof(msg));
+ else
+ memcpy(&msg, hm, sizeof(msg));
+
+ rv = send_header(fd, SM_CMD_HOST_MESSAGE, flags,
+ sizeof(struct sanlk_lockspace) + sizeof(struct sanlk_host_message),
+ 0, 0);
+ if (rv < 0)
+ goto out;
+
+ rv = send(fd, &ls, sizeof(struct sanlk_lockspace), 0);
+ if (rv < 0) {
+ rv = -errno;
+ goto out;
+ }
+
+ rv = send(fd, &msg, sizeof(struct sanlk_host_message), 0);
+ if (rv < 0) {
+ rv = -errno;
+ goto out;
+ }
+
+ rv = recv_result(fd);
+out:
+ close(fd);
+ return rv;
+}
+
/* old api */
int sanlock_init(struct sanlk_lockspace *ls,
struct sanlk_resource *res,
diff --git a/src/cmd.c b/src/cmd.c
index 13ad405670a0..d18d8daaba41 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -2351,6 +2351,32 @@ out:
send(fd, send_data_buf, len, MSG_NOSIGNAL);
}
+static void cmd_host_message(int fd, struct sm_header *h_recv)
+{
+ struct sanlk_lockspace lockspace;
+ struct sanlk_host_message msg;
+ int rv;
+
+ rv = recv(fd, &lockspace, sizeof(struct sanlk_lockspace), MSG_WAITALL);
+ if (rv != sizeof(struct sanlk_lockspace)) {
+ rv = -ENOTCONN;
+ goto out;
+ }
+
+ rv = recv(fd, &msg, sizeof(struct sanlk_host_message), MSG_WAITALL);
+ if (rv != sizeof(struct sanlk_host_message)) {
+ rv = -ENOTCONN;
+ goto out;
+ }
+
+ rv = host_message(&lockspace, &msg);
+out:
+ h_recv->length = sizeof(struct sm_header);
+ h_recv->data = rv;
+ h_recv->data2 = 0;
+ send(fd, h_recv, sizeof(struct sm_header), MSG_NOSIGNAL);
+}
+
static void cmd_restrict(int ci, int fd, struct sm_header *h_recv)
{
log_debug("cmd_restrict ci %d fd %d pid %d flags %x",
@@ -2445,6 +2471,10 @@ void call_cmd_daemon(int ci, struct sm_header *h_recv, int client_maxi)
strcpy(client[ci].owner_name, "get_hosts");
cmd_get_hosts(fd, h_recv);
break;
+ case SM_CMD_HOST_MESSAGE:
+ strcpy(client[ci].owner_name, "host_message");
+ cmd_host_message(fd, h_recv);
+ break;
};
if (auto_close)
diff --git a/src/delta_lease.c b/src/delta_lease.c
index 91d0a83bc811..d973094ae569 100644
--- a/src/delta_lease.c
+++ b/src/delta_lease.c
@@ -410,6 +410,7 @@ int delta_lease_renew(struct task *task,
struct sync_disk *disk,
char *space_name,
char *bitmap,
+ struct sanlk_host_message *message,
int prev_result,
int *read_result,
struct leader_record *leader_last,
@@ -419,7 +420,7 @@ int delta_lease_renew(struct task *task,
char **p_iobuf;
char **p_wbuf;
char *wbuf;
- uint64_t host_id, id_offset, new_ts;
+ uint64_t host_id, id_offset, new_ts, msg64;
int rv, iobuf_len, sector_size;
if (!leader_last) {
@@ -567,6 +568,18 @@ int delta_lease_renew(struct task *task,
leader.timestamp = new_ts;
leader.checksum = leader_checksum(&leader);
+ if (message && message->host_id) {
+ msg64 = message->msg_num;
+ msg64 = (msg64 << 32) | message->msg_data;
+ leader.write_id = message->host_id;
+ leader.write_generation = message->generation;
+ leader.write_timestamp = msg64;
+ } else {
+ leader.write_id = 0;
+ leader.write_generation = 0;
+ leader.write_timestamp = 0;
+ }
+
p_wbuf = &wbuf;
rv = posix_memalign((void *)p_wbuf, getpagesize(), sector_size);
if (rv) {
diff --git a/src/delta_lease.h b/src/delta_lease.h
index f015d1eecb23..243b22b19365 100644
--- a/src/delta_lease.h
+++ b/src/delta_lease.h
@@ -30,6 +30,7 @@ int delta_lease_renew(struct task *task,
struct sync_disk *disk,
char *space_name,
char *bitmap,
+ struct sanlk_host_message *message,
int prev_result,
int *read_result,
struct leader_record *leader_last,
diff --git a/src/direct.c b/src/direct.c
index ed6cca458364..3989da542877 100644
--- a/src/direct.c
+++ b/src/direct.c
@@ -240,6 +240,7 @@ static int do_delta_action(int action,
rv = delta_lease_renew(task, &space, &sd,
ls->name,
bitmap,
+ NULL,
-1,
&read_result,
&leader,
diff --git a/src/lockspace.c b/src/lockspace.c
index e96e1e1e7983..0dada49d9660 100644
--- a/src/lockspace.c
+++ b/src/lockspace.c
@@ -78,6 +78,20 @@ struct space *find_lockspace(const char *name)
return _search_space(name, NULL, 0, &spaces, &spaces_rem, &spaces_add, NULL);
}
+/* find any space where host_id is a member */
+static struct space *get_hostid_space(uint64_t host_id)
+{
+ struct space *sp;
+ struct host_status *hs;
+
+ list_for_each_entry(sp, &spaces, list) {
+ hs = &sp->host_status[host_id-1];
+ if (hs->owner_id && hs->timestamp && hs->last_live)
+ return sp;
+ }
+ return NULL;
+}
+
int _lockspace_info(const char *space_name, struct space_info *spi)
{
struct space *sp;
@@ -222,7 +236,8 @@ int host_info(char *space_name, uint64_t host_id, struct host_status *hs_out)
return 0;
}
-static void create_bitmap(struct space *sp, char *bitmap)
+static void create_bitmap_and_message(struct space *sp, char *bitmap,
+ struct sanlk_host_message *message)
{
uint64_t now;
int i;
@@ -247,6 +262,16 @@ static void create_bitmap(struct space *sp, char *bitmap)
log_space(sp, "bitmap set host_id %d byte %x", i+1, c);
}
}
+
+ if (sp->host_message.host_id) {
+ memcpy(message, &sp->host_message, sizeof(struct sanlk_host_message));
+ sp->host_message_written++;
+
+ if (sp->host_message_written >= 2) {
+ memset(&sp->host_message, 0, sizeof(struct sanlk_host_message));
+ sp->host_message_written = 0;
+ }
+ }
pthread_mutex_unlock(&sp->mutex);
}
@@ -289,6 +314,23 @@ void check_other_leases(struct space *sp, char *buf)
if (i+1 == sp->host_id)
continue;
+ /*
+ * check if we are target of message
+ */
+
+ if (leader->write_id == sp->host_id &&
+ leader->write_generation == sp->host_generation) {
+ log_space(sp, "message from host_id %d 0x%llx", i+1,
+ (unsigned long long)leader->write_timestamp);
+ set_message_examine(sp->space_name, leader->owner_id,
+ (leader->write_timestamp >> 32),
+ (leader->write_timestamp & 0xFFFFFFFF));
+ }
+
+ /*
+ * check if we are notified in bitmap
+ */
+
bitmap = (char *)leader + HOSTID_BITMAP_OFFSET;
if (!test_id_bit(sp->host_id, bitmap))
@@ -384,6 +426,7 @@ static int corrupt_result(int result)
static void *lockspace_thread(void *arg_in)
{
+ struct sanlk_host_message message;
char bitmap[HOSTID_BITMAP_SIZE];
struct task task;
struct space *sp;
@@ -502,12 +545,14 @@ static void *lockspace_thread(void *arg_in)
*/
memset(bitmap, 0, sizeof(bitmap));
- create_bitmap(sp, bitmap);
+ memset(&message, 0, sizeof(message));
+ create_bitmap_and_message(sp, bitmap, &message);
delta_begin = monotime();
delta_result = delta_lease_renew(&task, sp, &sp->host_id_disk,
- sp->space_name, bitmap,
+ sp->space_name,
+ bitmap, &message,
delta_result, &read_result,
&leader, &leader);
delta_length = monotime() - delta_begin;
@@ -1109,6 +1154,48 @@ int get_hosts(struct sanlk_lockspace *ls, char *buf, int *len, int *count, int m
return rv;
}
+int host_message(struct sanlk_lockspace *ls, struct sanlk_host_message *hm)
+{
+ struct space *sp;
+ struct host_status *hs;
+
+ if (!hm->host_id)
+ return -EINVAL;
+
+ pthread_mutex_lock(&spaces_mutex);
+
+ if (!ls->name[0]) {
+ sp = get_hostid_space(hm->host_id);
+ } else {
+ sp = _search_space(ls->name, NULL, 0, &spaces, NULL, NULL, NULL);
+ }
+ if (!sp) {
+ pthread_mutex_unlock(&spaces_mutex);
+ return -ENOENT;
+ }
+
+ /* this lockspace is currently sending a message */
+ if (sp->host_message.host_id) {
+ pthread_mutex_unlock(&spaces_mutex);
+ return -EBUSY;
+ }
+
+ /* supply the current generation if caller did not specify the generation */
+ if (!hm->generation) {
+ hs = &(sp->host_status[hm->host_id-1]);
+ hm->generation = hs->owner_generation;
+ }
+
+ log_erros(sp, "set host_message %u for host %llu %llu", hm->msg_num,
+ (unsigned long long)hm->host_id,
+ (unsigned long long)hm->generation);
+
+ memcpy(&sp->host_message, hm, sizeof(struct sanlk_host_message));
+ pthread_mutex_unlock(&spaces_mutex);
+
+ return 0;
+}
+
/*
* we call stop_host_id() when all pids are gone and we're in a safe state, so
* it's safe to unlink the watchdog right away here. We want to sp the unlink
diff --git a/src/lockspace.h b/src/lockspace.h
index 3ffe17ffc048..0b7e22f83b94 100644
--- a/src/lockspace.h
+++ b/src/lockspace.h
@@ -27,5 +27,6 @@ int rem_lockspace_wait(struct sanlk_lockspace *ls, unsigned int space_id);
void free_lockspaces(int wait);
int get_lockspaces(char *buf, int *len, int *count, int maxlen);
int get_hosts(struct sanlk_lockspace *ls, char *buf, int *len, int *count, int maxlen);
+int host_message(struct sanlk_lockspace *ls, struct sanlk_host_message *hm);
#endif
diff --git a/src/main.c b/src/main.c
index 421ea670823d..b5e736744e5a 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1170,6 +1170,7 @@ static void process_connection(int ci)
case SM_CMD_LOG_DUMP:
case SM_CMD_GET_LOCKSPACES:
case SM_CMD_GET_HOSTS:
+ case SM_CMD_HOST_MESSAGE:
call_cmd_daemon(ci, &h, client_maxi);
break;
case SM_CMD_ADD_LOCKSPACE:
@@ -1805,6 +1806,7 @@ static void print_usage(void)
printf("sanlock client status [-D] [-o p|s]\n");
printf("sanlock client gets [-h 0|1]\n");
printf("sanlock client host_status -s LOCKSPACE [-D]\n");
+ printf("sanlock client host_message -i <host_id> -n <num> [-g gen] [-m data] [-s LOCKSPACE]\n");
printf("sanlock client log_dump\n");
printf("sanlock client shutdown [-f 0|1]\n");
printf("sanlock client init -s LOCKSPACE | -r RESOURCE\n");
@@ -1939,6 +1941,8 @@ static int read_command_line(int argc, char *argv[])
com.action = ACT_CLIENT_INIT;
else if (!strcmp(act, "read"))
com.action = ACT_CLIENT_READ;
+ else if (!strcmp(act, "host_message"))
+ com.action = ACT_HOST_MESSAGE;
else {
log_tool("client action \"%s\" is unknown", act);
exit(EXIT_FAILURE);
@@ -2052,9 +2056,11 @@ static int read_command_line(int argc, char *argv[])
break;
case 'n':
com.num_hosts = atoi(optionarg);
+ com.msg_num = strtoul(optionarg, NULL, 0);
break;
case 'm':
com.max_hosts = atoi(optionarg);
+ com.msg_data = strtoul(optionarg, NULL, 0);
break;
case 'p':
com.pid = atoi(optionarg);
@@ -2063,7 +2069,7 @@ static int read_command_line(int argc, char *argv[])
strncpy(com.our_host_name, optionarg, NAME_ID_SIZE);
break;
case 'i':
- com.local_host_id = atoll(optionarg);
+ com.host_id = atoll(optionarg);
break;
case 'g':
if (com.type == COM_DAEMON) {
@@ -2071,7 +2077,7 @@ static int read_command_line(int argc, char *argv[])
if (sec <= 60 && sec >= 0)
kill_grace_seconds = sec;
} else {
- com.local_host_generation = atoll(optionarg);
+ com.host_generation = atoll(optionarg);
}
break;
case 'f':
@@ -2317,6 +2323,7 @@ static int do_client_read(void)
static int do_client(void)
{
+ struct sanlk_host_message hm;
struct sanlk_resource **res_args = NULL;
struct sanlk_resource *res;
char *res_state = NULL;
@@ -2499,6 +2506,16 @@ static int do_client(void)
rv = do_client_read();
break;
+ case ACT_HOST_MESSAGE:
+ log_tool("host_message %llu %u", (unsigned long long)com.host_id, com.msg_num);
+ hm.host_id = com.host_id;
+ hm.generation = com.host_generation;
+ hm.msg_num = com.msg_num;
+ hm.msg_data = com.msg_data;
+ rv = sanlock_host_message(com.lockspace.name, 0, sizeof(struct sanlk_host_message), &hm);
+ log_tool("host_message done %d", rv);
+ break;
+
default:
log_tool("action not implemented");
rv = -1;
@@ -2570,7 +2587,7 @@ static int do_direct(void)
case ACT_ACQUIRE:
rv = direct_acquire(&main_task, com.io_timeout_arg,
com.res_args[0], com.num_hosts,
- com.local_host_id, com.local_host_generation,
+ com.host_id, com.host_generation,
&leader);
log_tool("acquire done %d", rv);
break;
diff --git a/src/resource.c b/src/resource.c
index 98a07114bf5c..c118fbb5ba29 100644
--- a/src/resource.c
+++ b/src/resource.c
@@ -33,6 +33,7 @@
#include "timeouts.h"
#include "mode_block.h"
#include "helper.h"
+#include "watchdog.h"
/* from cmd.c */
void send_state_resource(int fd, struct resource *r, const char *list_name, int pid, uint32_t token_id);
@@ -49,6 +50,7 @@ static struct list_head resources_add;
static struct list_head resources_rem;
static pthread_mutex_t resource_mutex;
static pthread_cond_t resource_cond;
+static struct list_head host_messages;
static void free_resource(struct resource *r)
@@ -1693,6 +1695,57 @@ int set_resource_examine(char *space_name, char *res_name)
return count;
}
+struct recv_message {
+ struct list_head list;
+ uint64_t from_host_id;
+ uint32_t msg_num;
+ uint32_t msg_data;
+};
+
+void set_message_examine(char *space_name GNUC_UNUSED, uint64_t from_host_id,
+ uint32_t msg_num, uint32_t msg_data)
+{
+ struct recv_message *rm;
+
+ rm = malloc(sizeof(struct recv_message));
+ if (!rm) {
+ log_error("set_message_examine no mem");
+ return;
+ }
+
+ memset(rm, 0, sizeof(struct recv_message));
+ rm->from_host_id = from_host_id;
+ rm->msg_num = msg_num;
+ rm->msg_data = msg_data;
+
+ pthread_mutex_lock(&resource_mutex);
+ list_add_tail(&rm->list, &host_messages);
+ resource_thread_work = 1;
+ pthread_cond_signal(&resource_cond);
+ pthread_mutex_unlock(&resource_mutex);
+}
+
+static void resource_thread_messages(void)
+{
+ struct recv_message *rm, *safe;
+
+ list_for_each_entry_safe(rm, safe, &host_messages, list) {
+ list_del(&rm->list);
+
+ log_debug("message %u %u from %llu",
+ rm->msg_num, rm->msg_data,
+ (unsigned long long)rm->from_host_id);
+
+ if (rm->msg_num == SANLK_HM_WD_RESET) {
+ log_error("Host reset request from host_id %llu",
+ (unsigned long long)rm->from_host_id);
+ watchdog_reset_host();
+ }
+
+ free(rm);
+ }
+}
+
/*
* resource_thread
* - on-disk lease release for pid's that exit without doing release
@@ -1896,6 +1949,10 @@ static void *resource_thread(void *arg GNUC_UNUSED)
pthread_cond_wait(&resource_cond, &resource_mutex);
}
+ /* process any host messages that have been received */
+ resource_thread_messages();
+
+
/* FIXME: it's not nice how we copy a bunch of stuff
* from token to r so that we can later copy it back from
* r into a temp token. The whole duplication of stuff
@@ -1994,6 +2051,7 @@ int setup_token_manager(void)
INIT_LIST_HEAD(&resources_add);
INIT_LIST_HEAD(&resources_rem);
INIT_LIST_HEAD(&resources_held);
+ INIT_LIST_HEAD(&host_messages);
rv = pthread_create(&resource_pt, NULL, resource_thread, NULL);
if (rv)
diff --git a/src/resource.h b/src/resource.h
index e5c7d4184646..a062df712ccf 100644
--- a/src/resource.h
+++ b/src/resource.h
@@ -27,6 +27,9 @@ int request_token(struct task *task, struct token *token, uint32_t force_mode,
int set_resource_examine(char *space_name, char *res_name);
+void set_message_examine(char *space_name, uint64_t from_host_id,
+ uint32_t msg_num, uint32_t msg_data);
+
int res_set_lvb(struct sanlk_resource *res, char *lvb, int lvblen);
int res_get_lvb(struct sanlk_resource *res, char **lvb_out, int *lvblen);
diff --git a/src/sanlock.8 b/src/sanlock.8
index 0d2b63ca60c3..08e6771e12e3 100644
--- a/src/sanlock.8
+++ b/src/sanlock.8
@@ -372,6 +372,21 @@ out the action specified by the requested force_mode.
Examine requests for all resource leases currently held in the named
lockspace. Only lockspace_name is used from the LOCKSPACE argument.
+.BR "sanlock client host_message -s" " LOCKSPACE " \
+\fB-i\fP " " \fIhost_id\fP " " \
+\fB-n\fP " " \fImsg_num\fP
+
+Tell the sanlock daemon to send a msg_num type message to a host_id.
+Both hosts must be members of LOCKSPACE (only the name is used,
+the host_id in LOCKSPACE is unused).
+If no lockspace name is provided, any lockspace will
+be chosen that contains the host_id (N.B if hosts do not use the same
+id in all lockspaces, this could target the wrong host.)
+If an optional "-g host_generation" is specified, the message will only
+apply if the target host has the specified generation.
+.br
+msg_num 1: the host should use its watchdog to reset itself.
+
.B "sanlock direct"
.I action
[options]
diff --git a/src/sanlock.h b/src/sanlock.h
index 58779b128e3f..b3f86101ccf9 100644
--- a/src/sanlock.h
+++ b/src/sanlock.h
@@ -101,6 +101,16 @@ struct sanlk_host {
uint32_t flags;
};
+
+#define SANLK_HM_WD_RESET 0x00000001
+
+struct sanlk_host_message {
+ uint64_t host_id;
+ uint64_t generation;
+ uint32_t msg_num;
+ uint32_t msg_data;
+};
+
size_t sanlock_path_export(char *dst, const char *src, size_t dstlen);
size_t sanlock_path_import(char *dst, const char *src, size_t dstlen);
diff --git a/src/sanlock_admin.h b/src/sanlock_admin.h
index 1a781b1bda71..0e2671374469 100644
--- a/src/sanlock_admin.h
+++ b/src/sanlock_admin.h
@@ -276,4 +276,19 @@ int sanlock_test_resource_owners(struct sanlk_resource *res, uint32_t flags,
struct sanlk_host *hosts, int hosts_count,
uint32_t *test_flags);
+/*
+ * Send a predefined message to another host.
+ *
+ * If ls is NULL, then a suitable lockspace is chosen
+ * that both src and dst hosts are members of.
+ *
+ * msg_num values:
+ *
+ * WD_RESET: the host should use its watchdog device
+ * to reset itself as soon as possible.
+ */
+
+int sanlock_host_message(const char *ls_name, uint32_t flags,
+ int len, struct sanlk_host_message *hm);
+
#endif
diff --git a/src/sanlock_internal.h b/src/sanlock_internal.h
index a448a5cc79a3..4cceff87eaab 100644
--- a/src/sanlock_internal.h
+++ b/src/sanlock_internal.h
@@ -169,6 +169,8 @@ struct space {
pthread_mutex_t mutex; /* protects lease_status, thread_stop */
struct lease_status lease_status;
struct host_status host_status[DEFAULT_MAX_HOSTS];
+ struct sanlk_host_message host_message;
+ int host_message_written;
};
/* Update lockspace_info() to copy any fields from struct space
@@ -278,13 +280,15 @@ struct command_line {
int gid; /* -G */
int pid; /* -p */
char sort_arg;
- uint64_t local_host_id; /* -i */
- uint64_t local_host_generation; /* -g */
+ uint64_t host_id; /* -i */
+ uint64_t host_generation; /* -g */
int num_hosts; /* -n */
int max_hosts; /* -m */
int res_count;
int sh_retries;
uint32_t force_mode;
+ uint32_t msg_num; /* -n */
+ uint32_t msg_data; /* -m */
char our_host_name[SANLK_NAME_LEN+1];
char *dump_path;
struct sanlk_lockspace lockspace; /* -s LOCKSPACE */
@@ -325,6 +329,7 @@ enum {
ACT_CLIENT_ALIGN,
ACT_EXAMINE,
ACT_GETS,
+ ACT_HOST_MESSAGE,
};
EXTERN int external_shutdown;
diff --git a/src/sanlock_sock.h b/src/sanlock_sock.h
index b2f73047e1b1..0fb24d466f8d 100644
--- a/src/sanlock_sock.h
+++ b/src/sanlock_sock.h
@@ -45,6 +45,7 @@ enum {
SM_CMD_SET_LVB = 25,
SM_CMD_GET_LVB = 26,
SM_CMD_CONVERT = 27,
+ SM_CMD_HOST_MESSAGE = 28,
};
struct sm_header {
diff --git a/src/watchdog.c b/src/watchdog.c
index a8798802d75f..df569dbff57d 100644
--- a/src/watchdog.c
+++ b/src/watchdog.c
@@ -28,6 +28,8 @@
#include "log.h"
#include "watchdog.h"
+static int watchdog_reset_con;
+
/*
* Purpose of watchdog: to forcibly reset the host in the case where a
* supervised pid is running but sanlock daemon does not renew its lease
@@ -152,3 +154,66 @@ void close_watchdog_file(struct space *sp)
close(sp->wd_fd);
}
+/*
+ * Use the watchdog to reset the host as soon as possible.
+ * Intentionally set the expire time on the connection to
+ * the current time so that the watchdog will expire and
+ * reset as soon as possible.
+ */
+
+void watchdog_reset_host(void)
+{
+ char name[WDMD_NAME_SIZE];
+ uint64_t now;
+ int con, rv;
+
+ if (!com.use_watchdog)
+ return;
+
+ if (watchdog_reset_con) {
+ log_debug("watchdog_reset_host already active");
+ return;
+ }
+
+ con = wdmd_connect();
+ if (con < 0) {
+ log_error("watchdog_reset_host connect failed %d", con);
+ return;
+ }
+
+ memset(name, 0, sizeof(name));
+
+ snprintf(name, WDMD_NAME_SIZE - 1, "sanlock_reset_host");
+
+ rv = wdmd_register(con, name);
+ if (rv < 0) {
+ log_error("watchdog_reset_host register failed %d", rv);
+ goto fail_close;
+ }
+
+ /* the refcount tells wdmd that it should not cleanly exit */
+
+ rv = wdmd_refcount_set(con);
+ if (rv < 0) {
+ log_error("watchdog_reset_host refcount_set failed %d", rv);
+ goto fail_close;
+ }
+
+ now = monotime();
+
+ rv = wdmd_test_live(con, now, now);
+ if (rv < 0) {
+ log_error("watchdog_reset_host test_live failed %d", rv);
+ goto fail_clear;
+ }
+
+ log_error("Resetting host with watchdog");
+ watchdog_reset_con = con;
+ return;
+
+ fail_clear:
+ wdmd_refcount_clear(con);
+ fail_close:
+ close(con);
+}
+
diff --git a/src/watchdog.h b/src/watchdog.h
index 90e82eb0a44e..794ec30ff9ed 100644
--- a/src/watchdog.h
+++ b/src/watchdog.h
@@ -15,5 +15,6 @@ int create_watchdog_file(struct space *sp, uint64_t timestamp,
int id_renewal_fail_seconds);
void unlink_watchdog_file(struct space *sp);
void close_watchdog_file(struct space *sp);
+void watchdog_reset_host(void);
#endif
--
1.8.3.1
10 years, 2 months
VERSION
by David Teigland
VERSION | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
New commits:
commit 7c9516cc8a19b9c298ef791640b2aa857454cd77
Author: David Teigland <teigland(a)redhat.com>
Date: Tue Jan 7 11:15:46 2014 -0600
release 3.1.0
Signed-off-by: David Teigland <teigland(a)redhat.com>
diff --git a/VERSION b/VERSION
index cb2b00e..fd2a018 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.0.1
+3.1.0
10 years, 2 months
Changes to 'refs/tags/sanlock-3.1.0'
by David Teigland
Changes since the dawn of time:
Daniel P. Berrange (15):
Fix const-ness of many APIs.
Fix warnings in watchdog module
Fix function prototypes for no-arg methods
Remove use of 'index' as a variable name
Make many functions static
Fix missing include in logging file
Annotate many unused parameters to avoid warnings
Remove redundant redeclaration of 'to' variable
Fix args to execv()
Remove redundant arg to 'run_command'
Rename optarg to optionarg to avoid clashing with getopt.h
Disable the read_request method since it is unused
Add many more compiler warning flags & safety checks
Hard code a sector size of 512 if the lease volume is a regular file
Ensure libsanlock.so is built with debug/warning flags
David Teigland (438):
sync_manager: initial commit
sync_manager: misc updates
sync_manager: misc updates
sync_manager: misc updates
sync_manager: misc updates
sync_manager: add more logging
sync_manager: misc updates
sync_manager: misc updates
sync_manager: num_hosts/MAX_HOSTS stuff
daemon: reworking notions of resource_id/token_name
sync_manager: resource lockfiles
sync_manager: lease arg processing
sync_manager: Began multiple lease support
sync_manager: use first command line arg as action
sync_manager: leader record changes and verify
sync_manager: clean up released leases
sync_manager: move functions around
sync_manager: add more tool actions
sync_manager: naming changes
sync_manager: separate token index and id
sync_manager: fix index usage and other misc
sync_manager: use pthread cond in acquire
sync_manager: write all log entries
sync_manager: simplify polling
sync_manager: fix waitpid use
sync_manager: acquire can fail early
sync_manager: write log entries at exit
sync_manager: add test program
sync_manager: move secondary pid check
sync_manager: fix disk paxos contention
devcount: fix verify checks
sync_manager: add GPL license file
sync_manager: fix leader block offsets
sync_manager: increase COMMAND_MAX
sync_manager: renewal should verify
sync_manager: use sector size from libblkid
sync_manager: use a real checksum function
sync_manager: add libblkid to spec file
sync_manager: print status info
sync_manager: one watchdog file per lease
sync_manager: lease_threads handle watchdog files
sync_manager: fix/add some text/comments
sync_manager: refactor read/write
sync_manager: move disk io functions
sync_manager: remove token arg
sync_manager: rename paxos_disk sync_disk
sync_manager: add aio read/write
sync_manager: make io_timeout_seconds a diskio arg
sync_manager: forgot to add new files
sync_manager: use log thread
sync_manager: client connections
sync_manager: connection processing
sync_manager: send/recv pid
sync_manager: add write_sectors
sync_manager: restructuring
sync_manager: write_sectors code factoring
sync_manager: daemonize
sync_manager: releasing leases
sync_manager: async releasing
sync_manager: release fixes
sync_manager: add direct and indirect acquire/release
sync_manager: reacquire resources
sync_manager: move code
sync_manager: same pid may reacquire resource
sync_manager: lease migration
sync_manager: handle client errors
sync_manager: improve error handling
sync_manager: host_id leases
sync_manager: remove empty files
sync_manager: print initialization info
sync_manager: rename files
sync_manager: clean up header org
sync_manager: delta_lease implementation
sync_manager: accept offset units
sync_manager: fix up init output
sync_manager: put back watchdog calls
sync_manager: fix start_host_id error paths
sync_manager: add log_error's for watchdog file errors
sync_manager: actual timeouts
sync_manager: change timeouts on cmd line
sanlock: create new external api
sanlock: build libsanlock
sanlock: use MAX_LEASES everywhere
sanlock: add libvirt plugin
sanlock plugin: couple minor fixes
sanlock: clean up /var file names
sanlock plugin: fix symbol needed by libvirt
sanlock: add some debug output
sanlock plugin: fix uuid copy
sanlock plugin: fix names
sanlock: add "owner_name"
sanlock: fix renewal checks
sanlock: clean up host_id types
sanlock: set_host_id command
sanlock: fix killing pids
sanlock: add status command
sanlock: set version to 1.0
sanlock: delta_lease cleanup
sanlock: changing num_hosts
sanlock: add dump command
sanlock: renewal timings
sanlock: add direct option
sanlock: check for watchdog file
sanlock: recovery fixes
lock_driver_sanlock: fix compile problems
sanlock: improve command options
sanlock: tidying help text
sanlock: move binary to /usr/sbin
sanlock: add init script
sanlock: fix sigterm shutdown
sanlock: init stop
sanlock: add wdtest command
sanlock.spec: new url
lock_driver_sanlock: remove close
sanlock: introduce lockspaces
lock_driver_sanlock: remove files
sanlock: better logging functions
sanlock: misc log message
sanlock.spec: sbin not libexec
sanlock init: remove watchdog reference
wdmd: watchdog multiplexing daemon
sanlock: add code to use wdmd
sanlock/wdmd: use wdmd in sanlock
sanlock/wdmd: add copyright header to source files
sanlock: rename sanlock source dir
sanlock: move tests dir
move COPYING file
wdmd: use signalfd for signal handling
Fix Makefile comments
wdmd: fix daemon debug option
wdmd: add init script
sanlock.spec: updates
sanlock.spec: src dir
sanlock: build with uninstalled libwdmd
sanlock: version 1.1
sanlock: high priority options
wdmd: high priority options
sanlock: return migration state
sanlock: migration.txt describes libvirt/sanlock steps
libsanlock: include admin functions
sanlock: fix host_id expiration check
sanlock: migration working
devcount: migrate test
sanlock: setowner improvements
sanlock: migrate to target fix
sanlock: fix wdmd stop order
sanlock: various fixes
sanlock: remove wdtest
sanlock: remove migration
sanlock: clean up command return data
sanlock: add resource string conversion functions
sanlock: rework internal structs
devcount: add relock test
sanlock: fix release and inquire
sanlock: add_lockspace EEXIST
sanlock: rework client handling
sanlock: clean up warnings
sanlock: debug message changes
sanlock: add lockspace checks
wdmd: enable test scripts
sanlock: add str_to_lockspace to lib
WIP devcount migrate
devcount: new migrate test
sanlock: read_id and live_id commands
sanlock: check lockspace name and host_id
sanlock: remove remaining cluster_mode
sanlock: add libsanlock_direct
devcountn: start multiple devcount tests
devcount: small changes
sanlock: new return values
sanlock: misc changes and fix
sanlock: log error of full bad block
sanlock: interval between renewal checks
sanlock: renewal changes
sanlock: fix log_dump
sanlock: fix find_client_pid
sanlock: fix host_id reads from paxos_acquire
sanlock: init with one write
devcount: improve output
devcount: new pause/resume
devcount: add expire test
sanlock: correct paxos usage
sanlock: direct read_leader
sanlock: paxos delays
sanlock: use thread pool
sanlock: client status output format changes
sanlock: fix inquire of dead pid
sanlock: use native linux aio
sanlock: i/o changes
sanlock: aio changes
sanlock: reduce paxos acquire read ops
sanlock: quiet error case
sanlock: don't free aio buf until event completes
sanlock: io timeout related changes
sanlock: read dblocks in single aligned io
sanlock: add sanlock_restrict api
sanlock: add sanlock_direct_sector_size api
sanlock: add checksum to dblocks
sanlock: fix init restart
sanlock: don't release tokens in dead lockspace
sanlock: fix adding lockspace
sanlock: official 1MB/8MB alignment
devcount: use aio in init
libsanlock: link with LDFLAGS
sanlock: increase version to 1.3
sanlock/wdmd: shut up warnings
sanlock: fix libwdmd linking
remove spec file
sanlock: use a completed read after renewal timeout
sanlock: use unique host name in delta leases
sanlock: remove sector_size api
sanlock: abort delta wait on shutdown
sanlock: fix add_lockspace failure
sanlk_load: add new test
sanlock: fix recv and inquire
sanlock: initial pid_dead check in acquire
sanlock: release 1.4
sanlock: generate a uuid for host id
sanlock: return -EINPROGRESS from add_lockspace
sanlk_load: periodically kill and replace a pid
sanlock: zero num_hosts uses DEFAULT_MAX_HOSTS
tests: misc changes
sanlock: break paxos_acquire wait loop
sanlock: increase log line to 512 bytes
sanlock: change a log_error to log_debug
sanlock: fail host_id when corrupted
sanlock: release 1.5
sanlock: release 1.6
sanlock: handle colon escaping in path strings
wdmd: add option for high priority
wdmd: use accept4 with SOCK_NONBLOCK
wdmd: tidy sun_addr snprintf
wdmd: pid and sock file changes
wdmd: add man page
wdmd: disable test scripts
sanlock: use accept4 with SOCK_NONBLOCK
sanlock: tidy sun_addr snprintf
sanlock: add explicit -luuid
sanlock: pid and sock file changes
sanlock: add man page
sanlock/wdmd: improve mkdir of run dir
wdmd: new build flags
sanlock: new build flags
sanlock/wdmd: use monotonic time
sanlock: build with pie
sanlock/wdmd: nonblocking listening/accept
sanlock: add missing monotime files
sanlock: update man page
sanlock: man page update
sanlock: update man page and help text
sanlock: print connections limit
release: sanlock 1.7
makefile: install mode for man pages
sanlock: read align_size in renewal
sanlock: check other host_id leases
sanlock: minor fixes and cleanups
sanlock: add request api/cmd
sanlock: crc code tidying
sanlock/wdmd: add license header to files
sanlock: create libsanlock_client
sanlock: move client code
remove COPYING file
sanlock: remove internal header from sanlock_sock
libsanlock_client: use LGPLv2+
libwdmd: use LGPLv2+
sanlock_rv.h: switch to LGPLv2+
README.license: document licenses
sanlock: client align and init
sanlock: write request record
sanlock: request struct magic and version numbers
sanlock: set bitmap for requests
sanlock: examine resource requests
sanlock: update man page
sanlock: remove old comment
sanlock: renaming functions
sanlock: optimize paxos wait
sanlock: use flags in struct resource
sanlock: restructure lockspace checks
sanlock: remove BLOCK_WD force mode
libsanlock: fix function stubs
sanlock: new status and host_status
sanlock: improve status output
sanlock: status output sorting
sanlock: SIGTERM and SIGKILL for REQ_KILL_PID
sanlock: add flag RESTRICT_SIGKILL
sanlock: setup fewer aio events
sanlock: move cmd processing
sanlock: suppress log messages
sanlock: rename source files
sanlock: improve killing pids
sanlock: fix log_dump
version 1.8
sanlock: quick host_id reacquire
sanlock: add force option to shutdown command
simpler copyright line
default to GPLv2+ for our original files
sanlock: improve daemon permission errors
add systemd files
fixing up init stuff
release 1.9
sanlock: setmode
Revert "sanlock: setmode"
sanlock: fix error exit
sanlock: fix debug line
init scripts: fix path to restorecon
sanlock: shared mode for leases
sanlock: fix missing close_disks
sanlock: fix problem in paxos
sanlock: add paxos sanity check
sanlock: fix leaking fd
sanlock: change to paxos algorithm
sanlock: change ondisk version
sanlock: remove log noise
sanlock: ignore SIGTERM if lockspaces exist
sanlock: quiet more error messages
sanlk_load: munging variable names
sanlk_load: add shared locks
sanlock: kill client connection on recv error
sanlk_load: ignore release errors
sanlock: set sector_size in shared tokens
sanlock man page: mention SH
release 2.0
sanlock: clean up warnings
sanlock: fix inquire state string
sanlock: retry transient sh failures
sanlock: status for all shared tokens
sanlock: add a logrotate file
release 2.1
python: fix path strncpy
sanlock: remove physical sector size requirement
sanlock: add sample sysconfig file
sanlock: ASYNC flag for lockspace add and rem
sanlock: UNUSED flag for lockspace rem
release 2.2
sanlock.log: empty file to install from rpm
Revert "sanlock.log: empty file to install from rpm"
sanlock: remove limits.conf
sysconfig: remove user option
init: root user
release 2.3
latest spec file
sanlock.spec: fix exclusive arch
sanlock/wdmd: use /var/log/subsys/file
daemon: skip setup_groups when no -U or -G
sanlock.spec: require useradd and groupadd
sanlock.spec updated
daemon: don't put struct space on stack
daemon: fix add_lockspace that has been removed
daemon: fix inquire lver
daemon: graceful pid handling
Revert "init: make explicit to run sanlock as root"
remove spec file
release 2.4
daemon: include resource.h
daemon: fix lockfile ownership
wdmd: use lockfile mode 644
sanlock: use lockfile mode 644
wdmd: use shm_open to prevent restart
sanlock: remove umask 0
sanlock/wdmd: remove global connection
daemon: extend grace time
wdmd: close device when test fails
wdmd: preemptive close before test fails
wdmd: pet after reopen and use 1 sec interval after failure
sanlock: base kill sig on last renewal
clientn: add tests
tests: add test-recovery script
sanlock: fix paxos acquire host_id check
daemon: use helper for examine request kill
sanlock: show host_status for all lockspaces
sanlock: fix status of lockspaces in add and rem
sanlock: adjustable io timeouts
sanlock: add direct next_free command
sanlock: request force_mode 2 is SIGUSR1
sanlock: print escape chars in path from status
release 2.5
sanlock: configurable mlockall level
sanlock: change log level for startup and io timeouts
sanlock: update man page
sanlock: fix aborted command clearing
sanlock: client add_lockspace with timeout
sanlock: print command output to stdout
wdmd: new script handling
fence_sanlock: new code
fence_sanlock: various fixes and changes
fence_sanlock: variable alignment
fence_sanlockd: use init script
fence_sanlock: add man pages
fence_sanlock: use SIGHUP for shutdown
fence_sanlock: handle two node fence duel
sanlock/wdmd: get version from common file
wdmd: show option values in start message
release 2.6
fix systemd service files
wdmd: use mode 775 for run dir
sanlock: clean up daemon exit error path
sanlock: read and write apis for lockspace and resource
sanlock: new get_lockspaces api
sanlock: get_lockspaces count only
sanlock: make get_lockspaces allocate space for data
wdmd: dynamically select working watchdog device
fence_sanlock: fix man page name of path arg
sanlock: shutdown or rem_lockspace should SIGKILL
sanlock: fix usage output typos
release 2.7
sanlock: add request killpath
sanlock/fence_sanlock: request modes FORCE and GRACEFUL
sanlock: update request types in man page
sanlock: add get_hosts api
sanlock: remove direct read_id and live_id
sanlock: add read_resource_owners
sanlock: add test_resource_owners
sanlock: add flag SANLK_REQUEST_NEXT_LVER
sanlock: improve check of max_hosts and num_hosts
sanlock: add a comment
test: add another test program
sanlock: check for null arg in sanlock_request
release 2.8
sanlock: add lvb feature
sanlock: add SANLK_REL_RENAME
release 3.0.0
sanlock: free hss on error
sanlock: reinit hss in loop
sanlock: fix read_lockspace name comparison
sanlock: initialize owner_id
sanlock: initialize send_len and send_buf
release 3.0.1
sanlock: fix debug status for add/rem lockspace
sanlock: add_lockspace error for conflicting lockspace definitions
sanlock: add some acquire error descriptions
sanlock: use ADD and REM suffix in status output
sanlock: transient timeout handling in acquire and release
sanlock: add convert
sanlock: allow more than 8 resources per client
tests: sanlk_load
sanlock: fix spaces in path names
wdmd: add probe option
release 3.1.0
David Weber (3):
Fix order of linking
Install another symlink to shared library
Replace restrict field name with restricted
Fabio M. Di Nitto (15):
build: sanlock should link with libsanlock
build: install shared lib header files and fix DESTDIR usage
build: drop rpm target
spec file: do first cut for total spec file
build: fix linking with libsanlock and install target
fence_sanlock: add install bits
fence_sanlockd: add missing \n
fence_sanlock: cleanup shell usage
fence_sanlock: don't restart fence_sanlockd if it's already running
fence_sanlock: add basic metadata to integrate with ccs_config_validate
fence_sanlock: improve action_on error checking and report
fence_sanlock: unify code and silence some operations
fence_sanlockd init: cleanup, remove hardcoded paths and use system service
fence_sanlock: fix build to be selfcontained
systemd: add fence_sanlockd service file
Federico Simoncelli (76):
rpm: sync specfile with fedora
rpm: add sanlock_admin.h header
rpm: add the lib package, install the initscripts
python: remove unused python code
python: add python binding
python: release the gil during sanlock operations
python: wrap sanlock extension with a module
rpm: add python binding package
python: pass a lockspace copy to str_to_lockspace
makefile: fix install typo
rpm: add sanlock_direct header
python: add sanlock init functions and exception
direct: close disks after initialization
python: register process only once
daemon: configurable socket permissions
rpm: add sanlock user and group
python: exceptions must contain the errno
rpm: add missing libaio-devel dependency
rpm: add daemon options in the init file
python: add missing aio library
python: add get_alignment function
libs: include libsanlock_direct into libsanlock
python: align num_hosts and max_hosts defaults
python: expose sanlock file descriptor
python: improve error reporting
python: parse lockspaces and resources natively
python: add usage example
python: initial support for sanlock errors
python: document the sanlock module
python: module cleanup
build: fix documentation install path
client: return appropriate errno on failure
python: expose errno in the exception
python: acquire leases for other processes
sanlock: implement the inq_lockspace command
python: add the inq_lockspace command binding
misc: run sanlock daemon as sanlock user
wdmd: use getopt to parse the command line
wdmd: make socket group ownership configurable
python: add shared resource parameter to acquire
python: release leases for other processes
python: ASYNC flag for lockspace add and rem
python: UNUSED flag for lockspace rem
log: add full time and date to the log messages
sanlock: set the supplementary groups at startup
log: add the thread id in the log messages
sanlock: fix an rv check typo in setup_groups
init: add a stop timeout for the sanlock service
build: add a generic rpm spec file
init: make explicit to run sanlock as root
wdmd: load the softdog module when needed
sanlock: WAIT flag for sanlock_inq_lockspace
daemon: drop root privileges and use the helper
init: use checkpid when stopping the services
sanlock: expose sanlock path import and export utils
sanlock: configuring the core dump output
python: fix the tuple parsing for py_add_lockspace
sanlock: use signal handler for all terminating signals
systemd: add wdmd dependency for sanlock
wdmd: trap also SIGINT for a clean exit
wdmd: make the watchdog device configurable
python: fix typo for the offset parameter
python: add write lockspace and resource
python: add read lockspace and resource
wdmd: fix miscellaneous build warnings
misc: add wdmd to gitignore
python: fix multiple issues reported by cpychecker
python: add get_lockspaces
python: use the write commands in example.py
python: add the versioning support to acquire
python: return lease version in read_resource
python: rename SANLK_LSF flags and constants macro
python: improve example with signals and exceptions
python: add the support for the resource request
python: add the get_hosts support
python: add support to read resource owners
Saggi Mizrahi (25):
Added the begining of the testing and debugging tools
Better handling of max hosts
sync_manager: Updated tests to work with new lease struct
sync_manager: fixed skipping first arg in command
sync_manager: acquire and release actions
sync_manager: minor fixes
sync_manager: renamed stuff
sync_manager: made acquire synchronous again
sync_manager: added set_host_id action
sync_manager: use kill(0) for secondary pid check
sync_manager: make rpm and install
sync_manager: spec file update
sync_manager: Allow longer resource names
sync_manager: allow repeated set_host_id
sync_manager: Added escaping for the leases arg
sync_manager: Created the python bindings for sync_manager
sync_manager: listener socket permissions
sync_manager: Updated python binding and tests
sync_manager: Made 'token' a const in log_level
sync_manager: refactor messaging system
sync_manager: use getsockopt PEERCRED
Fix various build warnings
Tidy up some copy pasted code
Set constness in some places
Add a gitignore file
10 years, 2 months
init.d/wdmd wdmd/main.c wdmd/wdmd.8
by David Teigland
init.d/wdmd | 23 ++++++++--
wdmd/main.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
wdmd/wdmd.8 | 10 ++++
3 files changed, 158 insertions(+), 5 deletions(-)
New commits:
commit 7507b61f3539a2c688c96faa4b7153fd4d62251d
Author: David Teigland <teigland(a)redhat.com>
Date: Thu Jan 2 13:04:13 2014 -0600
wdmd: add probe option
The probe option will look for a watchdog device that the
daemon can use. If a good device is found, the path is printed
and the command exits with 0. If a good device is not found,
the command exits with 1.
The init script uses this new probe function to determine
if it needs to load the softdog module or not.
Signed-off-by: David Teigland <teigland(a)redhat.com>
diff --git a/init.d/wdmd b/init.d/wdmd
index af45561..6ca9279 100644
--- a/init.d/wdmd
+++ b/init.d/wdmd
@@ -3,7 +3,7 @@
# wdmd - watchdog multiplexing daemon
#
# chkconfig: 2345 97 03
-# description: starts and stops sanlock daemon
+# description: starts and stops wdmd daemon
#
@@ -31,12 +31,27 @@ WDMDOPTS="-G $WDMDGROUP"
[ -f /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog
+watchdog_probe() {
+ $exec --probe > /dev/null 2>&1
+ retval=$?
+ return $retval
+}
+
watchdog_check() {
- if [ ! -c /dev/watchdog ]; then
+ watchdog_probe
+ retval=$?
+
+ if [ $retval -ne 0 ]; then
echo -n $"Loading the softdog kernel module: "
modprobe softdog && udevadm settle
- [ -c /dev/watchdog ] && success || failure
- echo
+
+ watchdog_probe
+ retval=$?
+ if [ $retval -ne 0 ]; then
+ failure; echo
+ return 1
+ fi
+ success; echo
fi
}
diff --git a/wdmd/main.c b/wdmd/main.c
index 529b563..8a09632 100644
--- a/wdmd/main.c
+++ b/wdmd/main.c
@@ -1085,6 +1085,120 @@ static int setup_watchdog(void)
}
+static int probe_dev(const char *path)
+{
+ struct stat buf;
+ int fd, err, rv, timeout;
+
+ rv = stat(path, &buf);
+ if (rv < 0) {
+ fprintf(stderr, "error %d stat %s\n", errno, path);
+ return -1;
+ }
+
+ fd = open(path, O_WRONLY | O_CLOEXEC);
+ if (fd < 0) {
+ fprintf(stderr, "error %d open %s\n", errno, path);
+ return fd;
+ }
+
+ timeout = 0;
+
+ rv = ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
+ if (rv < 0) {
+ fprintf(stderr, "error %d ioctl gettimeout %s\n", errno, path);
+ rv = -1;
+ goto out;
+ }
+
+ if (timeout == fire_timeout) {
+ printf("%s\n", path);
+ rv = 0;
+ goto out;
+ }
+
+ timeout = fire_timeout;
+
+ rv = ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
+ if (rv < 0) {
+ fprintf(stderr, "error %d ioctl settimeout %s\n", errno, path);
+ rv = -1;
+ goto out;
+ }
+
+ if (timeout != fire_timeout) {
+ fprintf(stderr, "error %d invalid timeout %s\n", errno, path);
+ rv = -1;
+ goto out;
+ }
+
+ printf("%s\n", path);
+ rv = 0;
+
+ out:
+ err = write(fd, "V", 1);
+ if (err < 0) {
+ fprintf(stderr, "probe failed to disarm %s error %d %d\n", path, err, errno);
+ openlog("wdmd", LOG_CONS | LOG_PID, LOG_DAEMON);
+ syslog(LOG_ERR, "probe failed to disarm %s error %d %d\n", path, err, errno);
+ }
+
+ close(fd);
+ return rv;
+}
+
+static int probe_watchdog(void)
+{
+ int rv;
+
+ if (!saved_path[0])
+ goto opt;
+
+ rv = probe_dev(saved_path);
+ if (!rv)
+ return 0;
+
+ opt:
+ if (!option_path[0] || !strcmp(saved_path, option_path))
+ goto zero;
+
+ rv = probe_dev(option_path);
+ if (!rv)
+ return 0;
+
+ zero:
+ if (!strcmp(saved_path, "/dev/watchdog0") ||
+ !strcmp(option_path, "/dev/watchdog0"))
+ goto one;
+
+ rv = probe_dev((char *)"/dev/watchdog0");
+ if (!rv)
+ return 0;
+
+ one:
+ if (!strcmp(saved_path, "/dev/watchdog1") ||
+ !strcmp(option_path, "/dev/watchdog1"))
+ goto old;
+
+ rv = probe_dev((char *)"/dev/watchdog1");
+ if (!rv)
+ return 0;
+
+ old:
+ if (!strcmp(saved_path, "/dev/watchdog") ||
+ !strcmp(option_path, "/dev/watchdog"))
+ goto out;
+
+ rv = probe_dev((char *)"/dev/watchdog");
+ if (!rv)
+ return 0;
+
+ out:
+ fprintf(stderr, "no watchdog device, load a watchdog driver\n");
+ return -1;
+
+}
+
static void pet_watchdog(void)
{
int rv, unused;
@@ -1397,6 +1511,7 @@ static void print_usage_and_exit(int status)
printf("--version, -V print version\n");
printf("--help, -h print usage\n");
printf("--dump, -d print debug from daemon\n");
+ printf("--probe, -p print path of functional watchdog device\n");
printf("-D debug: no fork and print all logging to stderr\n");
printf("-H 0|1 use high priority features (1 yes, 0 no, default %d)\n",
DEFAULT_HIGH_PRIORITY);
@@ -1425,6 +1540,7 @@ static void print_version_and_exit(void)
int main(int argc, char *argv[])
{
+ int do_probe = 0;
int rv;
while (1) {
@@ -1433,12 +1549,13 @@ int main(int argc, char *argv[])
static struct option long_options[] = {
{"help", no_argument, 0, 'h' },
+ {"probe", no_argument, 0, 'p' },
{"dump", no_argument, 0, 'd' },
{"version", no_argument, 0, 'V' },
{0, 0, 0, 0 }
};
- c = getopt_long(argc, argv, "hdVDH:G:S:s:k:w:",
+ c = getopt_long(argc, argv, "hpdVDH:G:S:s:k:w:",
long_options, &option_index);
if (c == -1)
break;
@@ -1447,6 +1564,9 @@ int main(int argc, char *argv[])
case 'h':
print_usage_and_exit(0);
break;
+ case 'p':
+ do_probe = 1;
+ break;
case 'd':
print_debug_and_exit();
break;
@@ -1478,6 +1598,14 @@ int main(int argc, char *argv[])
}
}
+ if (do_probe) {
+ rv = probe_watchdog();
+ if (rv < 0)
+ exit(EXIT_FAILURE);
+ else
+ exit(EXIT_SUCCESS);
+ }
+
if (!daemon_debug) {
if (daemon(0, 0) < 0) {
fprintf(stderr, "cannot fork daemon\n");
diff --git a/wdmd/wdmd.8 b/wdmd/wdmd.8
index 7e11562..cc03be7 100644
--- a/wdmd/wdmd.8
+++ b/wdmd/wdmd.8
@@ -79,6 +79,12 @@ it is considered a failure.
Print debug information from the daemon.
.TP
+.B \-\-probe, \-p
+ Print path of functional watchdog device. Exit code 0 indicates a
+ functional device was found. Exit code 1 indicates a functional device
+ was not found.
+
+.TP
.B \-D
Enable debugging to stderr and don't fork.
@@ -103,4 +109,8 @@ it is considered a failure.
.BI \-k " num"
Kill unfinished scripts after num seconds.
+.TP
+.BI \-w " path"
+ The path to the watchdog device to try first.
+
10 years, 2 months