import sanlock-3.8.3-2.el8

This commit is contained in:
CentOS Sources 2021-05-24 04:10:45 +00:00 committed by Andrew Lukoshko
parent 82ed521242
commit e124ddde4c
3 changed files with 804 additions and 1 deletions

View File

@ -0,0 +1,342 @@
From 2d3e2fceb615a5bd12d26b09fe95668152fb0743 Mon Sep 17 00:00:00 2001
From: Nir Soffer <nsoffer@redhat.com>
Date: Wed, 28 Apr 2021 02:20:28 +0300
Subject: [PATCH] python: Add inquire()
Use sanlock_inquire() to query the resource held by the current process
(using the slkfd= argument) or held by another program (using the pid=
argument).
When using the slkfd= argument, we communicate with sanlock daemon using
slkfd, ensuring that the current process is connected to sanlock. If the
current process is not connected, sanlock assumes that the process is
dead, and release all the leases acquired by the process.
When using the pid= argument, the function opens a new socket to sanlock
daemon and query the status of resources owned by specified pid.
In both cases the information comes from sanlock daemon, without
accessing storage. To verify storage content, the caller should use
read_resource() and read_resource_owners().
The call returns list of resources dicts that can be used for verifying
that sanlock state matches the program state.
sanlock_inquire() reports the SANLOCK_RES_LVER or sanlock.RES_SHARED
flags in the resource flags field. Add the field to the returned dict
and add sanlock constants for the flag.
The resource flags are needed if you want to restore a lease after it
was released, ensuring that nobody else acquired the lease after it was
released. This flow is used by libvirt using libsanlock. With this
change we can implement the same flow using the python binding.
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
---
python/sanlock.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++
tests/python_test.py | 84 +++++++++++++++++++++++++
2 files changed, 257 insertions(+)
diff --git a/python/sanlock.c b/python/sanlock.c
index 67d34fc23a20..c4814640c874 100644
--- a/python/sanlock.c
+++ b/python/sanlock.c
@@ -323,6 +323,88 @@ exit_fail:
return NULL;
}
+/* Convert disks array to list of tuples. */
+static PyObject *
+disks_to_list(struct sanlk_disk *disks, uint32_t disks_count)
+{
+ PyObject *result = NULL;
+ PyObject *disk = NULL;
+
+ result = PyList_New(disks_count);
+ if (result == NULL)
+ return NULL;
+
+ for (uint32_t i = 0; i < disks_count; i++) {
+ disk = Py_BuildValue(
+ "(s,K)",
+ disks[i].path,
+ disks[i].offset);
+ if (disk == NULL)
+ goto exit_fail;
+
+ /* Steals reference to disk. */
+ if (PyList_SetItem(result, i, disk) != 0)
+ goto exit_fail;
+
+ disk = NULL;
+ }
+
+ return result;
+
+exit_fail:
+ Py_XDECREF(result);
+ Py_XDECREF(disk);
+
+ return NULL;
+}
+
+/* Convert resources array returned from sanlock_inquire() to list of resource
+ * dicts. */
+static PyObject *
+resources_to_list(struct sanlk_resource **res, int res_count)
+{
+ PyObject *result = NULL;
+ PyObject *info = NULL;
+ PyObject *disks = NULL;
+
+ if ((result = PyList_New(res_count)) == NULL)
+ return NULL;
+
+ for (int i = 0; i < res_count; i++) {
+ disks = disks_to_list(res[i]->disks, res[i]->num_disks);
+ if (disks == NULL)
+ goto exit_fail;
+
+ /* Steals reference to disks. */
+ info = Py_BuildValue(
+ "{s:y,s:y,s:k,s:K,s:N}",
+ "lockspace", res[i]->lockspace_name,
+ "resource", res[i]->name,
+ "flags", res[i]->flags,
+ "version", res[i]->lver,
+ "disks", disks);
+ if (info == NULL)
+ goto exit_fail;
+
+ disks = NULL;
+
+ /* Steals reference to info. */
+ if (PyList_SetItem(result, i, info) != 0)
+ goto exit_fail;
+
+ info = NULL;
+ }
+
+ return result;
+
+exit_fail:
+ Py_XDECREF(result);
+ Py_XDECREF(info);
+ Py_XDECREF(disks);
+
+ return NULL;
+}
+
/* register */
PyDoc_STRVAR(pydoc_register, "\
register() -> int\n\
@@ -1062,6 +1144,89 @@ finally:
Py_RETURN_NONE;
}
+/* inquire */
+PyDoc_STRVAR(pydoc_inquire, "\
+inquire(slkfd=-1, pid=-1)\n\
+Return list of resources held by current process (using the slkfd \n\
+argument to specify the sanlock file descriptor) or for another \n\
+process (using the pid argument).\n\
+\n\
+Does not access storage. To learn about resource state on storage,\n\
+use sanlock.read_resource() and sanlock.read_resource_owners().\n\
+\n\
+Arguments\n\
+ slkfd (int): The file descriptor returned from sanlock.register().\n\
+ pid (int): The program pid to query.\n\
+\n\
+Returns\n\
+ List of resource dicts with the following keys:\n\
+ lockspace (bytes): lockspace name\n\
+ resource (bytes): resource name\n\
+ flags (int): resource flags (sanlock.RES_*)\n\
+ version (int): resource version\n\
+ disks (list): list of disk tuples (path, offset)\n\
+");
+
+static PyObject *
+py_inquire(PyObject *self __unused, PyObject *args, PyObject *keywds)
+{
+ int sanlockfd = -1;
+ int pid = -1;
+ char *kwlist[] = {"slkfd", "pid", NULL};
+ int rv = -1;
+
+ /* sanlock_inquire() return values. */
+ int res_count = 0;
+ char *res_state = NULL;
+
+ /* Array of resoruces parsed from res_state. */
+ struct sanlk_resource **res_arr = NULL;
+
+ /* List of resource dicts. */
+ PyObject *result = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, keywds, "|ii", kwlist, &sanlockfd, &pid)) {
+ return NULL;
+ }
+
+ /* Check if any of the slkfd or pid parameters was given. */
+ if (sanlockfd == -1 && pid == -1) {
+ set_sanlock_error(-EINVAL, "Invalid slkfd and pid values");
+ return NULL;
+ }
+
+ /* Inquire sanlock (gil disabled) */
+ Py_BEGIN_ALLOW_THREADS
+ rv = sanlock_inquire(sanlockfd, pid, 0, &res_count, &res_state);
+ Py_END_ALLOW_THREADS
+
+ if (rv != 0) {
+ set_sanlock_error(rv, "Inquire error");
+ return NULL;
+ }
+
+ if (res_count > 0) {
+ rv = sanlock_state_to_args(res_state, &res_count, &res_arr);
+ if (rv != 0) {
+ /* TODO: Include res_state in the error. */
+ set_sanlock_error(rv, "Error parsing inquire state string");
+ goto finally;
+ }
+ }
+
+ result = resources_to_list(res_arr, res_count);
+
+finally:
+ free(res_state);
+
+ for (int i = 0; i < res_count; i++)
+ free(res_arr[i]);
+ free(res_arr);
+
+ return result;
+}
+
/* release */
PyDoc_STRVAR(pydoc_release, "\
release(lockspace, resource, disks [, slkfd=fd, pid=owner])\n\
@@ -1752,6 +1917,8 @@ sanlock_methods[] = {
METH_VARARGS|METH_KEYWORDS, pydoc_read_resource_owners},
{"acquire", (PyCFunction) py_acquire,
METH_VARARGS|METH_KEYWORDS, pydoc_acquire},
+ {"inquire", (PyCFunction) py_inquire,
+ METH_VARARGS|METH_KEYWORDS, pydoc_inquire},
{"release", (PyCFunction) py_release,
METH_VARARGS|METH_KEYWORDS, pydoc_release},
{"request", (PyCFunction) py_request,
@@ -1850,6 +2017,12 @@ module_init(PyObject* m)
if (PyModule_AddIntConstant(m, "SETEV_ALL_HOSTS", SANLK_SETEV_ALL_HOSTS))
return -1;
+ /* sanlock_inquire() result resource flags */
+ if (PyModule_AddIntConstant(m, "RES_LVER", SANLK_RES_LVER))
+ return -1;
+ if (PyModule_AddIntConstant(m, "RES_SHARED", SANLK_RES_SHARED))
+ return -1;
+
/* Tuples with supported sector size and alignment values */
PyObject *sector = Py_BuildValue("ii", SECTOR_SIZE_512, SECTOR_SIZE_4K);
diff --git a/tests/python_test.py b/tests/python_test.py
index 58a22c71995c..caf2f3e7594a 100644
--- a/tests/python_test.py
+++ b/tests/python_test.py
@@ -479,6 +479,90 @@ def test_acquire_release_resource(tmpdir, sanlock_daemon, size, offset):
assert owners == []
+@pytest.mark.parametrize("res_name", [
+ "ascii",
+ "\u05d0", # Hebrew Alef
+])
+def test_inquire(tmpdir, sanlock_daemon, res_name):
+ ls_path = str(tmpdir.join("ls_name"))
+ util.create_file(ls_path, MiB)
+
+ res_path = str(tmpdir.join(res_name))
+ util.create_file(res_path, 10 * MiB)
+
+ fd = sanlock.register()
+
+ # No lockspace yet.
+ assert sanlock.inquire(slkfd=fd) == []
+
+ sanlock.write_lockspace(b"ls_name", ls_path, offset=0, iotimeout=1)
+ sanlock.add_lockspace(b"ls_name", 1, ls_path, offset=0, iotimeout=1)
+
+ # No resources created yet.
+ assert sanlock.inquire(slkfd=fd) == []
+
+ resources = [
+ # name, offset, acquire
+ (b"res-0", 0 * MiB, True),
+ (b"res-1", 1 * MiB, False),
+ (b"res-2", 2 * MiB, True),
+ (b"res-8", 8 * MiB, False),
+ (b"res-9", 9 * MiB, True),
+ ]
+
+ for res_name, res_offset, acquire in resources:
+ sanlock.write_resource(b"ls_name", res_name, [(res_path, res_offset)])
+
+ # No resource acquired yet.
+ assert sanlock.inquire(slkfd=fd) == []
+
+ # Acquire resources.
+ for res_name, res_offset, acquire in resources:
+ if acquire:
+ sanlock.acquire(
+ b"ls_name", res_name, [(res_path, res_offset)], slkfd=fd)
+
+ time.sleep(1)
+
+ expected = [
+ {
+ "lockspace": b"ls_name",
+ "resource": b"res-0",
+ "flags": sanlock.RES_LVER,
+ "version": 1,
+ "disks": [(res_path, 0 * MiB)],
+ },
+ {
+ "lockspace": b"ls_name",
+ "resource": b"res-2",
+ "flags": sanlock.RES_LVER,
+ "version": 1,
+ "disks": [(res_path, 2 * MiB)],
+ },
+ {
+ "lockspace": b"ls_name",
+ "resource": b"res-9",
+ "flags": sanlock.RES_LVER,
+ "version": 1,
+ "disks": [(res_path, 9 * MiB)],
+ },
+ ]
+
+ # Check acquired resources using snlkfd.
+ assert sanlock.inquire(slkfd=fd) == expected
+
+ # Check acquired resources using pid.
+ assert sanlock.inquire(pid=os.getpid()) == expected
+
+ for res_name, res_offset, acquire in resources:
+ if acquire:
+ sanlock.release(
+ b"ls_name", res_name, [(res_path, res_offset)], slkfd=fd)
+
+ # All resource released.
+ assert sanlock.inquire(slkfd=fd) == []
+
+
@pytest.mark.parametrize("align, sector", [
# Invalid alignment
(KiB, sanlock.SECTOR_SIZE[0]),
--
2.7.5

View File

@ -0,0 +1,452 @@
From bb70c220b51720a46a1bdc6b824936fc7269d5d8 Mon Sep 17 00:00:00 2001
From: David Teigland <teigland@redhat.com>
Date: Mon, 3 May 2021 12:52:17 -0500
Subject: [PATCH] sanlock: do not close connection in error handling
When processing a client connection, a problem with the message
or with the client handling would cause the sanlock daemon to
close the client connection (the socket fd) and release any
leases if the connection was "registered". If this happened,
the client may be unaware of it, and may continue running,
using the leases that have been dropped. This could lead to
different clients on different hosts believing that they hold
the same lease concurrently.
A known cause of this is when a sanlock client program makes
libsanlock calls on a registered connection concurrently
from multiple threads without serialization. These calls are:
sanlock_acquire, sanlock_release, sanlock_inquire,
sanlock_convert, sanlock_restrict, sanlock_killpath.
These calls involve:
- sending a header to the sanlock daemon
- sending a body to the sanlock daemon
- receving a reply from the sanlock daemon
If these steps are interleaved from multiple threads, the
sanlock daemon will read incorrect data when processing
a request, or the wrong result could be received by the caller.
A specific example that's been seen involves two concurrent
sanlock_release calls from different threads. The proper
sequence would be:
sanlock_release_1
send header_1
send body_1
recv result_1
sanlock_release_2
send header_2
send body_2
recv result_2
Without locking, data from both requests are interleaved,
causing a sequence to be received in the daemon:
header_1
header_2
body_1
The sanlock daemon expects the correct sequence of data,
so it misinterprets the mixed data and reports errors when
it finds unexpected fields in what it thinks are headers
and body structs.
The sanlock daemon recvs header_1, then recvs header_2,
and thinks header_2 is body_1. When it finds an unknown
resource name in what it thinks is body_1 (really header_2),
it logs an error to sanlock.log:
cmd_release 19,86,41799 no resource ...
Then the sanlock dameon recvs data from body_1, and thinks
it is header_2. When it finds an invalid magic number in
header_2 (really body_1), it logs an error to sanlock.log:
ci 19 recv 32 magic 0 vs 4282010
The error path after seeing a bad magic number in a message
header is to call deadfn(). For a registered connection,
this is client_pid_dead() which closes the socket fd for
the client and drops leases held by the client.
Closing the connection is the wrong way to handle a bad message
because the client is still running, and a closed connection
implies that a registered client has exited.
The fix is to simply ignore the bad data (logging an error).
By ignoring the messages, the sanlock clients will likely be
stuck waiting for replies, or possibly receive errors from
their calls. So, this fix only prevents leases from being
dropped incorrectly. Clients must still serialize access
to sockets.
Other error conditions in processing a client connection also
use this same incorrect error handling, and they are also
changed to simply ignore the issue and log an error.
---
src/main.c | 44 ++++++-----
src/sanlock_resource.h | 3 +
tests/Makefile | 9 ++-
tests/sanlk_mixmsg.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 242 insertions(+), 22 deletions(-)
create mode 100644 tests/sanlk_mixmsg.c
diff --git a/src/main.c b/src/main.c
index 622dc8e39f2a..026f7dae7d6a 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1235,33 +1235,33 @@ static void process_connection(int ci)
if (!rv)
goto dead;
- log_client(ci, client[ci].fd, "recv %d %d", rv, h.cmd);
+ log_client(ci, client[ci].fd, "recv %d %u", rv, h.cmd);
if (rv < 0) {
- log_error("ci %d fd %d pid %d recv errno %d",
- ci, client[ci].fd, client[ci].pid, errno);
- goto dead;
+ log_error("client connection %d %d %d recv msg header rv %d errno %d",
+ ci, client[ci].fd, client[ci].pid, rv, errno);
+ goto bad;
}
if (rv != sizeof(h)) {
- log_error("ci %d fd %d pid %d recv size %d",
- ci, client[ci].fd, client[ci].pid, rv);
- goto dead;
+ log_error("client connection %d %d %d recv msg header rv %d cmd %u len %u",
+ ci, client[ci].fd, client[ci].pid, rv, h.cmd, h.length);
+ goto bad;
}
if (h.magic != SM_MAGIC) {
- log_error("ci %d recv %d magic %x vs %x",
- ci, rv, h.magic, SM_MAGIC);
- goto dead;
+ log_error("client connection %d %d %d recv msg header rv %d cmd %u len %u magic %x vs %x",
+ ci, client[ci].fd, client[ci].pid, rv, h.cmd, h.length, h.magic, SM_MAGIC);
+ goto bad;
}
if (client[ci].restricted & SANLK_RESTRICT_ALL) {
- log_error("ci %d fd %d pid %d cmd %d restrict all",
- ci, client[ci].fd, client[ci].pid, h.cmd);
- goto dead;
+ log_error("client connection %d %d %d recv msg header rv %d cmd %u len %u restrict all",
+ ci, client[ci].fd, client[ci].pid, rv, h.cmd, h.length);
+ goto bad;
}
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;
+ log_error("client connection %d %d %d recv msg header rv %d cmd %u len %u version %x",
+ ci, client[ci].fd, client[ci].pid, rv, h.cmd, h.length, h.version);
+ goto bad;
}
client[ci].cmd_last = h.cmd;
@@ -1306,7 +1306,7 @@ static void process_connection(int ci)
case SM_CMD_DELETE_RESOURCE:
rv = client_suspend(ci);
if (rv < 0)
- goto dead;
+ goto bad;
process_cmd_thread_unregistered(ci, &h);
break;
case SM_CMD_ACQUIRE:
@@ -1318,16 +1318,20 @@ static void process_connection(int ci)
while the thread is working on it */
rv = client_suspend(ci);
if (rv < 0)
- goto dead;
+ goto bad;
process_cmd_thread_registered(ci, &h);
break;
default:
- log_error("process_connection ci %d fd %d cmd %d unknown", ci, client[ci].fd, h.cmd);
- goto dead;
+ log_error("client connection ci %d fd %d pid %d cmd %d unknown",
+ ci, client[ci].fd, client[ci].pid, h.cmd);
+ goto bad;
};
return;
+ bad:
+ return;
+
dead:
log_client(ci, client[ci].fd, "recv dead");
deadfn = client[ci].deadfn;
diff --git a/src/sanlock_resource.h b/src/sanlock_resource.h
index 80178d194b6b..48e448969b3c 100644
--- a/src/sanlock_resource.h
+++ b/src/sanlock_resource.h
@@ -15,6 +15,9 @@
* process creates registered connection and acquires/releases leases on
* that connection for itself
*
+ * A threaded sanlock client must serialize libsanlock calls that are
+ * made using a registered socket connection.
+ *
* sock == -1, pid is used:
* process asks daemon to acquire/release leases for another separately
* registered pid
diff --git a/tests/Makefile b/tests/Makefile
index 1e7f7f487915..80123d3dc633 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -5,6 +5,7 @@ TARGET4 = killpath
TARGET5 = sanlk_path
TARGET6 = sanlk_testr
TARGET7 = sanlk_events
+TARGET8 = sanlk_mixmsg
SOURCE1 = devcount.c
SOURCE2 = sanlk_load.c
@@ -13,6 +14,7 @@ SOURCE4 = killpath.c
SOURCE5 = sanlk_path.c
SOURCE6 = sanlk_testr.c
SOURCE7 = sanlk_events.c
+SOURCE8 = sanlk_mixmsg.c
CFLAGS += -D_GNU_SOURCE -g \
-Wall \
@@ -36,7 +38,7 @@ CFLAGS += -D_GNU_SOURCE -g \
LDFLAGS = -lrt -laio -lblkid -lsanlock
-all: $(TARGET1) $(TARGET2) $(TARGET3) $(TARGET4) $(TARGET5) $(TARGET6) $(TARGET7)
+all: $(TARGET1) $(TARGET2) $(TARGET3) $(TARGET4) $(TARGET5) $(TARGET6) $(TARGET7) $(TARGET8)
$(TARGET1): $(SOURCE1)
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -L. -I../src -L../src
@@ -59,6 +61,9 @@ $(TARGET6): $(SOURCE6)
$(TARGET7): $(SOURCE7)
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -L. -I../src -L../src
+$(TARGET8): $(SOURCE8)
+ $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ -L. -I../src -L../src
+
clean:
- rm -f *.o *.so *.so.* $(TARGET) $(TARGET2) $(TARGET3) $(TARGET4) $(TARGET5) $(TARGET6) $(TARGET7)
+ rm -f *.o *.so *.so.* $(TARGET) $(TARGET2) $(TARGET3) $(TARGET4) $(TARGET5) $(TARGET6) $(TARGET7) $(TARGET8)
diff --git a/tests/sanlk_mixmsg.c b/tests/sanlk_mixmsg.c
new file mode 100644
index 000000000000..1b9376e981b6
--- /dev/null
+++ b/tests/sanlk_mixmsg.c
@@ -0,0 +1,208 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <sys/mount.h>
+#include <sys/signalfd.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/socket.h>
+
+#include "sanlock.h"
+#include "sanlock_resource.h"
+#include "sanlock_admin.h"
+#include "sanlock_sock.h"
+
+/* gcc with -lsanlock */
+
+/*
+ * sanlock direct init -s 1271384c-24db-4c9b-bebf-61a1916b6cb1:0:/dev/test/main:0
+ * sanlock add_lockspace -s 1271384c-24db-4c9b-bebf-61a1916b6cb1:1:/dev/test/main:0
+ */
+
+/* copied from client.c */
+static int send_header(int sock, int cmd, uint32_t cmd_flags, int datalen,
+ uint32_t data, uint32_t data2)
+{
+ struct sm_header header;
+ int rv;
+
+ memset(&header, 0, sizeof(header));
+ header.magic = SM_MAGIC;
+ header.version = SM_PROTO;
+ header.cmd = cmd;
+ header.cmd_flags = cmd_flags;
+ header.length = sizeof(header) + datalen;
+ header.data = data;
+ header.data2 = data2;
+
+retry:
+ rv = send(sock, (void *) &header, sizeof(header), 0);
+ if (rv == -1 && errno == EINTR)
+ goto retry;
+
+ if (rv < 0)
+ return -errno;
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ char rd1[sizeof(struct sanlk_resource) + sizeof(struct sanlk_disk)];
+ char rd2[sizeof(struct sanlk_resource) + sizeof(struct sanlk_disk)];
+ struct sanlk_resource *res1;
+ struct sanlk_resource *res2;
+ const char *lsname;
+ const char *resname1;
+ const char *resname2;
+ char *path;
+ int fd, rv;
+
+ if (argc < 2) {
+ printf("%s <path>\n", argv[0]);
+ return -1;
+ }
+
+ path = argv[1];
+
+ lsname = "1271384c-24db-4c9b-bebf-61a1916b6cb1";
+ resname1 = "2e794e7a-5a9c-4617-8cd0-dc03c917d7a1";
+ resname2 = "2e794e7a-5a9c-4617-8cd0-dc03c917d7a2";
+
+ memset(rd1, 0, sizeof(rd1));
+ memset(rd2, 0, sizeof(rd2));
+
+ res1 = (struct sanlk_resource *)&rd1;
+ res2 = (struct sanlk_resource *)&rd2;
+
+ strcpy(res1->lockspace_name, lsname);
+ sprintf(res1->name, "%s", resname1);
+ res1->num_disks = 1;
+ strcpy(res1->disks[0].path, path);
+ res1->disks[0].offset = 1048576;
+
+ strcpy(res2->lockspace_name, lsname);
+ sprintf(res2->name, "%s", resname2);
+ res2->num_disks = 1;
+ strcpy(res2->disks[0].path, path);
+ res2->disks[0].offset = 2 * 1048576;
+
+ /*
+ struct sanlk_lockspace ls = { 0 };
+ sprintf(ls.name, lsname);
+ sprintf(ls.host_id_disk.path, path);
+
+ rv = sanlock_write_lockspace(&ls, 0, 0, 0);
+ if (rv < 0) {
+ printf("write_lockspace error %d\n", rv);
+ return -1;
+ }
+ */
+
+ rv = sanlock_write_resource(res1, 0, 0, 0);
+ if (rv < 0) {
+ printf("write_resource1 error %d\n", rv);
+ return -1;
+ }
+ rv = sanlock_write_resource(res2, 0, 0, 0);
+ if (rv < 0) {
+ printf("write_resource2 error %d\n", rv);
+ return -1;
+ }
+
+ fd = sanlock_register();
+ if (fd < 0) {
+ printf("register error %d\n", fd);
+ return -1;
+ }
+
+ printf("acquiring both leases for registered fd %d\n", fd);
+
+ rv = sanlock_acquire(fd, -1, 0, 1, &res1, NULL);
+ if (rv < 0) {
+ printf("acquire res1 error %d\n", rv);
+ return -1;
+ }
+
+ rv = sanlock_acquire(fd, -1, 0, 1, &res2, NULL);
+ if (rv < 0) {
+ printf("acquire res2 error %d\n", rv);
+ return -1;
+ }
+
+ printf("sleeping... check that both leases are held\n");
+ sleep(20);
+
+ printf("sending res1 release header only\n");
+ rv = send_header(fd, SM_CMD_RELEASE, 0, sizeof(struct sanlk_resource), 1, -1);
+ if (rv < 0)
+ printf("send bad header error %d\n", rv);
+ else
+ printf("send bad header ok\n");
+
+ printf("sending res2 release interleaved\n");
+ rv = sanlock_release(fd, -1, 0, 1, &res2);
+ if (rv < 0)
+ printf("odd release res2 error %d\n", rv);
+ else
+ printf("odd release res2 ok\n");
+
+ printf("sending res1 release body only\n");
+ rv = send(fd, res1, sizeof(struct sanlk_resource), 0);
+ if (rv < 0)
+ printf("send bad body error %d\n", rv);
+ else
+ printf("send bad body ok\n");
+
+ /*
+ * This is not simulating the recv() that each sanlock_release
+ * would do in libsanlock to get a result for each release.
+ * These would likely just cause the client block indefinitely
+ * waiting for a reply that won't come because the bad release
+ * calls were ignored.
+ */
+
+ printf("sleeping... check which leases are held\n");
+ sleep(20);
+
+ printf("releasing both leases normally\n");
+ rv = sanlock_release(fd, -1, 0, 1, &res1);
+ if (rv < 0)
+ printf("release res1 error %d\n", rv);
+ else
+ printf("release res1 ok\n");
+
+ rv = sanlock_release(fd, -1, 0, 1, &res2);
+ if (rv < 0)
+ printf("release res2 error %d\n", rv);
+ else
+ printf("release res2 ok\n");
+
+ printf("sleeping... check that both leases are released\n");
+ sleep(20);
+
+ printf("acquiring lease res1\n");
+ rv = sanlock_acquire(fd, -1, 0, 1, &res1, NULL);
+ if (rv < 0)
+ printf("acquire res1 error %d\n", rv);
+ else
+ printf("acquire res1 ok\n");
+
+ /* exit should close our registered connection and
+ automatically release res1 */
+
+ printf("exiting... check if held lease is released after exit\n");
+
+ return 0;
+}
+
--
2.7.5

View File

@ -1,6 +1,6 @@
Name: sanlock Name: sanlock
Version: 3.8.3 Version: 3.8.3
Release: 1%{?dist} Release: 2%{?dist}
Summary: A shared storage lock manager Summary: A shared storage lock manager
Group: System Environment/Base Group: System Environment/Base
@ -23,6 +23,9 @@ Requires(preun): systemd-units
Requires(postun): systemd-units Requires(postun): systemd-units
Source0: https://releases.pagure.org/sanlock/%{name}-%{version}.tar.gz Source0: https://releases.pagure.org/sanlock/%{name}-%{version}.tar.gz
Patch0: sanlock-do-not-close-connection-in-error-handling.patch
Patch1: python-Add-inquire.patch
%global python_package python3-%{name} %global python_package python3-%{name}
%description %description
@ -30,6 +33,9 @@ The sanlock daemon manages leases for applications on hosts using shared storage
%prep %prep
%setup -q %setup -q
%patch0 -p1 -b .sanlock-do-not-close-connection-in-error-handling.patch
%patch1 -p1 -b .python-Add-inquire.patch
%build %build
# upstream does not require configure # upstream does not require configure
@ -183,6 +189,9 @@ common sanlock lockspace.
%changelog %changelog
* Thu May 20 2021 David Teigland <teigland@redhat.com> 3.8.3-2
- Fix connection close and add python inquire api
* Tue Jan 19 2021 David Teigland <teigland@redhat.com> 3.8.3-1 * Tue Jan 19 2021 David Teigland <teigland@redhat.com> 3.8.3-1
- Update to sanlock-3.8.3 - Update to sanlock-3.8.3