import sanlock-3.8.4-1.el8
This commit is contained in:
parent
35a5270df1
commit
5db2e65024
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1 @@
|
|||||||
SOURCES/sanlock-3.8.3.tar.gz
|
SOURCES/sanlock-3.8.4.tar.gz
|
||||||
|
@ -1 +1 @@
|
|||||||
b860d082a129a6d80e6e79353fd9da1d60269bfa SOURCES/sanlock-3.8.3.tar.gz
|
494d5efc260b643ed9a3ee6bbdb0d31ecb14c201 SOURCES/sanlock-3.8.4.tar.gz
|
||||||
|
@ -1,342 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
@ -1,452 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
Name: sanlock
|
Name: sanlock
|
||||||
Version: 3.8.3
|
Version: 3.8.4
|
||||||
Release: 3%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: A shared storage lock manager
|
Summary: A shared storage lock manager
|
||||||
|
|
||||||
Group: System Environment/Base
|
Group: System Environment/Base
|
||||||
@ -23,9 +23,6 @@ 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
|
||||||
@ -34,9 +31,6 @@ 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
|
||||||
# upstream does not support _smp_mflags
|
# upstream does not support _smp_mflags
|
||||||
@ -189,7 +183,10 @@ common sanlock lockspace.
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Thu May 27 2021 David Teigland <teigland@redhat.com> 3.8.3-3
|
* Tue Jun 01 2021 David Teigland <teigland@redhat.com> 3.8.4-1
|
||||||
|
- Update to sanlock-3.8.4
|
||||||
|
|
||||||
|
* Thu May 20 2021 David Teigland <teigland@redhat.com> 3.8.3-2
|
||||||
- Fix connection close and add python inquire api
|
- 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
|
||||||
|
Loading…
Reference in New Issue
Block a user