On Fri, Dec 4, 2020 at 12:45 PM Benny Zlotnik <bzlotnik(a)redhat.com> wrote:
Add a binding to the set_lvb function to allow writing data to LVB.
Signed-off-by: Benny Zlotnik <bzlotnik(a)redhat.com>
---
Changes in v2:
- Fix paramter list
- Fix resource initialization
- Fix indentation
python/sanlock.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+)
diff --git a/python/sanlock.c b/python/sanlock.c
index 4592f7e..9647c03 100644
--- a/python/sanlock.c
+++ b/python/sanlock.c
@@ -1594,6 +1594,61 @@ finally:
Py_RETURN_NONE;
}
+/* set_lvb */
+PyDoc_STRVAR(pydoc_set_lvb, "\
+set_lvb(lockspace, resource, disks, data)\n\
+Set Lock Value Block for a given resource\n\
Need to explain when the lvb is written and visible to others (see
comments later).
+\n\
+Arguments\n\
+ lockspace lockspace name (str)\n\
+ resource resource name (int)\n\
+ disks path and offset (tuple)\n\
+ data data to write (bytes)\n\
+\n\
+Notes\n\
+\n\
+The resource must be acquired with the SANLK_ACQUIRE_LVB flag\n");
This is correct from sanlock point of view, but the caller of this
function knows only
about the lvb= flag, so this should be:
... with lvb=True
+static PyObject *
+py_set_lvb(PyObject *self __unused, PyObject *args, PyObject *keywds)
+{
+ uint32_t flags = 0;
+ int rv = -1;
+ struct sanlk_resource *res = NULL;
+ PyObject *lockspace = NULL, *resource = NULL, *data = NULL;
+ PyObject *disks;
+
+ static char *kwlist[] = {"lockspace", "resource",
"disks", "data", NULL};
+ if (!PyArg_ParseTupleAndKeywords(args, keywds, "O&O&O!O&",
kwlist,
+ convert_to_pybytes, &lockspace, convert_to_pybytes, &resource,
+ &PyList_Type, &disks, convert_to_pybytes, &data)) {
+ goto finally;
+ }
+
+ if (parse_disks(disks, &res) < 0) {
+ goto finally;
+ }
+
+ strncpy(res->lockspace_name, PyBytes_AsString(lockspace), SANLK_NAME_LEN);
+ strncpy(res->name, PyBytes_AsString(resource), SANLK_NAME_LEN);
+
+ Py_BEGIN_ALLOW_THREADS
+ rv = sanlock_set_lvb(flags, res, PyBytes_AS_STRING(data), PyBytes_GET_SIZE(data));
Looking in the source
1125 /* 4096 is the max sector size we handle, it is compared
1126 against the actual 512/4K sector size in res_set_lvb. */
1127
1128 if (lvblen > 4096) {
1129 log_error("cmd_set_lvb %d,%d lvblen %d too big",
ca->ci_in, fd, lvblen);
1130 result = -E2BIG;
1131 goto reply;
1132 }
I think we should document that lvm size is limited to the sector size
of the resource.
Looking in src/resource.h:
702 int res_set_lvb(struct sanlk_resource *res, char *lvb, int lvblen)
703 {
704 struct resource *r;
705 int rv = -ENOENT;
706
707 pthread_mutex_lock(&resource_mutex);
708 list_for_each_entry(r, &resources_held, list) {
709 if (strncmp(r->r.lockspace_name,
res->lockspace_name, NAME_ID_SIZE))
710 continue;
711 if (strncmp(r->r.name, res->name, NAME_ID_SIZE))
712 continue;
713
714 if (!r->lvb) {
715 rv = -EINVAL;
716 break;
717 }
718
719 if (lvblen > r->leader.sector_size) {
720 rv = -E2BIG;
721 break;
722 }
723
724 memcpy(r->lvb, lvb, lvblen);
725 r->flags |= R_LVB_WRITE_RELEASE;
726 rv = 0;
727 break;
728 }
729 pthread_mutex_unlock(&resource_mutex);
730
731 return rv;
732 }
set_lvb does not write anything to storage, only copy the data into
the resource.
It looks like the lvb is written to storage in _release_token():
1085 if (r_flags & R_LVB_WRITE_RELEASE) {
1086 rv = write_lvb_block(task, r, token);
1087 if (!rv)
1088 r->flags &= ~R_LVB_WRITE_RELEASE;
1089 else
1090 log_errot(token, "release_token
write_lvb error %d", rv);
1091 /* do we want to give more effort to
writing lvb? */
1092 }
So we the lvb can be updated only after we acquire and release the
resource. This
may surprise users of this API.
+ Py_END_ALLOW_THREADS
+
+ if (rv < 0) {
+ set_sanlock_error(rv, "Unable to set lvb");
+ goto finally;
+ }
+
+finally:
+ Py_XDECREF(lockspace);
+ Py_XDECREF(resource);
+ free(res);
+ if (rv < 0)
+ return NULL;
+ Py_RETURN_NONE;
+}
+
static PyMethodDef
sanlock_methods[] = {
{"register", py_register, METH_NOARGS, pydoc_register},
@@ -1631,6 +1686,9 @@ sanlock_methods[] = {
{"end_event", (PyCFunction) py_end_event, METH_VARARGS, pydoc_end_event},
{"set_event", (PyCFunction) py_set_event,
METH_VARARGS|METH_KEYWORDS, pydoc_set_event},
+ {"set_lvb", (PyCFunction) py_set_lvb,
+ METH_VARARGS|METH_KEYWORDS, pydoc_set_lvb},
+
{NULL, NULL, 0, NULL}
};
--
2.28.0