From 7984c54f07f6dd5f8e09a98147396734f902dded Mon Sep 17 00:00:00 2001 From: AlmaLinux RelEng Bot Date: Wed, 4 Mar 2026 04:48:10 -0500 Subject: [PATCH] import CS git dlm-4.1.0-3.el8_10 --- ...dlm_controld-better-uevent-filtering.patch | 232 ++++++++++++++++++ ...d-plock-operations-without-resource-.patch | 75 ++++++ ...dlm_controld-terminate-uevent-buffer.patch | 26 ++ ...old-handle-RELEASE_RECOVER-event-env.patch | 232 ++++++++++++++++++ SPECS/dlm.spec | 18 +- 5 files changed, 582 insertions(+), 1 deletion(-) create mode 100644 SOURCES/0001-dlm_controld-better-uevent-filtering.patch create mode 100644 SOURCES/0001-dlm_controld-send-plock-operations-without-resource-.patch create mode 100644 SOURCES/0002-dlm_controld-terminate-uevent-buffer.patch create mode 100644 SOURCES/0003-dlm_controld-handle-RELEASE_RECOVER-event-env.patch diff --git a/SOURCES/0001-dlm_controld-better-uevent-filtering.patch b/SOURCES/0001-dlm_controld-better-uevent-filtering.patch new file mode 100644 index 0000000..f1b8948 --- /dev/null +++ b/SOURCES/0001-dlm_controld-better-uevent-filtering.patch @@ -0,0 +1,232 @@ +From 7b6c22b254181a2b1921a4c31228fc8920b5547e Mon Sep 17 00:00:00 2001 +From: Alexander Aring +Date: Fri, 13 Jan 2023 17:33:31 -0500 +Subject: [PATCH 1/3] dlm_controld: better uevent filtering + +When I did test with dlm_locktorture module I got several log messages +about: + +uevent message has 3 args: add@/module/dlm_locktorture +uevent message has 3 args: remove@/module/dlm_locktorture + +which are not expected and not able to parse by dlm_controld +process_uevent() function, because mismatch of argument counts. +Debugging it more, I figured out that those uevents are for +loading/unloading the dlm_locktorture module and there are uevents for +loading and unloading modules which have nothing todo with dlm lockspace +uevent handling. + +The current filter works as: + +if (!strstr(buf, "dlm")) + +for matching the dlm joining/leaving uevent string which looks like: + +offline@/kernel/dlm/locktorture + +to avoid matching with other uevent which has somehow the string "dlm" +in it, we switch to the match the uevent env variables for action, +devpath (just to check if it's set) and subsystem. Additional the dlm +subsystem sets the LOCKSPACE variable which can be used to get the +lockspace name instead of extracting it previously from the devpath. + +The code to decode the uevent envs were taken from the gfs2_controld +utility [0]. + +[0] https://github.com/andyprice/gfs2-utils/blob/91c3e9a69ed70d3d522f5b47015da5e5868722ec/group/gfs_controld/main.c +--- + dlm_controld/main.c | 126 +++++++++++++++++++++++++------------------- + 1 file changed, 71 insertions(+), 55 deletions(-) + +diff --git a/dlm_controld/main.c b/dlm_controld/main.c +index c35756d4..74a5e61b 100644 +--- a/dlm_controld/main.c ++++ b/dlm_controld/main.c +@@ -46,6 +46,50 @@ struct client { + struct lockspace *ls; + }; + ++enum { ++ Env_ACTION = 0, ++ Env_DEVPATH, ++ Env_SUBSYSTEM, ++ Env_LOCKSPACE, ++ Env_Last, /* Flag for end of vars */ ++}; ++ ++static const char *uevent_vars[] = { ++ [Env_ACTION] = "ACTION=", ++ [Env_DEVPATH] = "DEVPATH=", ++ [Env_SUBSYSTEM] = "SUBSYSTEM=", ++ [Env_LOCKSPACE] = "LOCKSPACE=", ++}; ++ ++static void decode_uevent(const char *buf, unsigned len, const char *vars[], ++ unsigned nvars, const char *vals[]) ++{ ++ const char *ptr; ++ unsigned int i; ++ int slen, vlen; ++ ++ memset(vals, 0, sizeof(const char *) * nvars); ++ ++ while (len > 0) { ++ ptr = buf; ++ slen = strlen(ptr); ++ buf += slen; ++ len -= slen; ++ buf++; ++ len--; ++ ++ for (i = 0; i < nvars; i++) { ++ vlen = strlen(vars[i]); ++ if (vlen > slen) ++ continue; ++ if (memcmp(vars[i], ptr, vlen) != 0) ++ continue; ++ vals[i] = ptr + vlen; ++ break; ++ } ++ } ++} ++ + int do_read(int fd, void *buf, size_t count) + { + int rv, off = 0; +@@ -627,38 +671,6 @@ static void fs_register_del(char *name) + } + } + +-#define MAXARGS 8 +- +-static char *get_args(char *buf, int *argc, char **argv, char sep, int want) +-{ +- char *p = buf, *rp = NULL; +- int i; +- +- argv[0] = p; +- +- for (i = 1; i < MAXARGS; i++) { +- p = strchr(buf, sep); +- if (!p) +- break; +- *p = '\0'; +- +- if (want == i) { +- rp = p + 1; +- break; +- } +- +- argv[i] = p + 1; +- buf = p + 1; +- } +- *argc = i; +- +- /* we ended by hitting \0, return the point following that */ +- if (!rp) +- rp = strchr(buf, '\0') + 1; +- +- return rp; +-} +- + const char *dlm_mode_str(int mode) + { + switch (mode) { +@@ -686,13 +698,12 @@ const char *dlm_mode_str(int mode) + + static void process_uevent(int ci) + { ++ const char *uevent_vals[Env_Last]; + struct lockspace *ls; + char buf[MAX_LINE_UEVENT]; +- char *argv[MAXARGS], *act, *sys; +- int rv, argc = 0; ++ int rv; + + memset(buf, 0, sizeof(buf)); +- memset(argv, 0, sizeof(char *) * MAXARGS); + + retry_recv: + rv = recv(client[ci].fd, &buf, sizeof(buf), 0); +@@ -704,35 +715,38 @@ static void process_uevent(int ci) + return; + } + +- if (!strstr(buf, "dlm")) +- return; ++ decode_uevent(buf, rv, uevent_vars, Env_Last, uevent_vals); + +- log_debug("uevent: %s", buf); +- +- get_args(buf, &argc, argv, '/', 4); +- if (argc != 4) +- log_error("uevent message has %d args", argc); +- act = argv[0]; +- sys = argv[2]; +- +- if (!act || !sys || !argv[3]) ++ if (!uevent_vals[Env_ACTION] || ++ !uevent_vals[Env_DEVPATH] || ++ !uevent_vals[Env_SUBSYSTEM] || ++ !uevent_vals[Env_LOCKSPACE]) { ++ log_debug("failed to validate uevent, action: %p, devpath: %p, subsystem: %p, lockspace: %p", ++ uevent_vals[Env_ACTION], uevent_vals[Env_DEVPATH], ++ uevent_vals[Env_SUBSYSTEM], ++ uevent_vals[Env_LOCKSPACE]); + return; ++ } + +- if (strncmp(sys, "dlm", 3)) ++ if (strcmp(uevent_vals[Env_SUBSYSTEM], "dlm")) { ++ log_debug("uevent looks like dlm but came not from dlm subsystem"); + return; ++ } + +- log_debug("kernel: %s %s", act, argv[3]); ++ log_debug("uevent action: %s, devpath: %s, devpath: %s, lockspace: %s", ++ uevent_vals[Env_ACTION], uevent_vals[Env_SUBSYSTEM], ++ uevent_vals[Env_DEVPATH], uevent_vals[Env_LOCKSPACE]); + + rv = 0; + +- if (!strcmp(act, "online@")) { +- ls = find_ls(argv[3]); ++ if (!strcmp(uevent_vals[Env_ACTION], "online")) { ++ ls = find_ls(uevent_vals[Env_LOCKSPACE]); + if (ls) { + rv = -EEXIST; + goto out; + } + +- ls = create_ls(argv[3]); ++ ls = create_ls(uevent_vals[Env_LOCKSPACE]); + if (!ls) { + rv = -ENOMEM; + goto out; +@@ -747,8 +761,8 @@ static void process_uevent(int ci) + goto out; + } + +- } else if (!strcmp(act, "offline@")) { +- ls = find_ls(argv[3]); ++ } else if (!strcmp(uevent_vals[Env_ACTION], "offline")) { ++ ls = find_ls(uevent_vals[Env_LOCKSPACE]); + if (!ls) { + rv = -ENOENT; + goto out; +@@ -758,8 +772,10 @@ static void process_uevent(int ci) + } + out: + if (rv < 0) +- log_error("process_uevent %s error %d errno %d", +- act, rv, errno); ++ log_error("%s action: %s, devpath: %s, devpath: %s, lockspace: %s - error %d errno %d", ++ __func__, uevent_vals[Env_ACTION], ++ uevent_vals[Env_SUBSYSTEM], uevent_vals[Env_DEVPATH], ++ uevent_vals[Env_LOCKSPACE], rv, errno); + } + + static int setup_uevent(void) +-- +2.43.0 + diff --git a/SOURCES/0001-dlm_controld-send-plock-operations-without-resource-.patch b/SOURCES/0001-dlm_controld-send-plock-operations-without-resource-.patch new file mode 100644 index 0000000..629f05d --- /dev/null +++ b/SOURCES/0001-dlm_controld-send-plock-operations-without-resource-.patch @@ -0,0 +1,75 @@ +From b6f52406411d2421d0614244080cf7bc668c336b Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Tue, 13 Jan 2026 16:59:25 -0600 +Subject: [PATCH dlm/tool] dlm_controld: send plock operations without resource + lookup + +When plock_ownership mode is disabled, a plock operation read from +the kernel can be sent to all nodes immediately, without looking up +the local resource struct. This is faster, and it avoids a bug in +cases where multiple threads in a process submit concurrent fcntl +lock ops on a file. + +This bug occurs because create/free of the resource struct should +only be done in the context of ordered receive_plock cpg messages. +plock unlock results were being incorrectly returned based on the +non-existence of a struct resource checked in process_plocks (outside +of the ordered message context.) In this case, the existence of the +resource struct was used to imply a lock state ("no locks"), which is +invalid to conclude outside of the message context. The bug would +only appear in the unusual scenario where multiple threads in a +process are running concurrent fcntl lock operations on a file. + +This fix does not address the problem when plock_ownership is enabled, +so warnings are added for the plock_ownership setting. +--- + dlm_controld/dlm_controld.8 | 2 ++ + dlm_controld/main.c | 2 +- + dlm_controld/plock.c | 5 +++++ + 3 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/dlm_controld/dlm_controld.8 b/dlm_controld/dlm_controld.8 +index 3aab3885..3858be87 100644 +--- a/dlm_controld/dlm_controld.8 ++++ b/dlm_controld/dlm_controld.8 +@@ -50,6 +50,8 @@ For default settings, see dlm_controld -h. + .B --plock_ownership | -o + 0|1 + enable/disable plock ownership ++.br ++ (WARNING: do not enable if threads perform fcntl locking.) + + .B --drop_resources_time | -t + .I int +diff --git a/dlm_controld/main.c b/dlm_controld/main.c +index 2dc6b91b..728b7464 100644 +--- a/dlm_controld/main.c ++++ b/dlm_controld/main.c +@@ -1841,7 +1841,7 @@ static void set_opt_defaults(void) + set_opt_default(plock_ownership_ind, + "plock_ownership", 'o', req_arg_bool, + 0, NULL, 0, +- "enable/disable plock ownership"); ++ "enable/disable plock ownership (do not enable if threads do fcntl locking)"); + + set_opt_default(drop_resources_time_ind, + "drop_resources_time", 't', req_arg_int, +diff --git a/dlm_controld/plock.c b/dlm_controld/plock.c +index 992fb16f..56ea9765 100644 +--- a/dlm_controld/plock.c ++++ b/dlm_controld/plock.c +@@ -1569,6 +1569,11 @@ void process_plocks(int ci) + plock_rate_delays = 0; + } + ++ if (!opt(plock_ownership_ind)) { ++ send_plock(ls, NULL, &info); ++ return; ++ } ++ + create = (info.optype == DLM_PLOCK_OP_UNLOCK) ? 0 : 1; + + rv = find_resource(ls, info.number, create, &r); +-- +2.43.0 + diff --git a/SOURCES/0002-dlm_controld-terminate-uevent-buffer.patch b/SOURCES/0002-dlm_controld-terminate-uevent-buffer.patch new file mode 100644 index 0000000..c398e47 --- /dev/null +++ b/SOURCES/0002-dlm_controld-terminate-uevent-buffer.patch @@ -0,0 +1,26 @@ +From 615e7936d39248de09dc9c5e7570463387f7d139 Mon Sep 17 00:00:00 2001 +From: David Teigland +Date: Thu, 15 Aug 2024 11:05:54 -0500 +Subject: [PATCH 2/3] dlm_controld: terminate uevent buffer + +for checker +--- + dlm_controld/main.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/dlm_controld/main.c b/dlm_controld/main.c +index 74a5e61b..1828428c 100644 +--- a/dlm_controld/main.c ++++ b/dlm_controld/main.c +@@ -715,6 +715,8 @@ static void process_uevent(int ci) + return; + } + ++ buf[MAX_LINE_UEVENT-1] = '\0'; ++ + decode_uevent(buf, rv, uevent_vars, Env_Last, uevent_vals); + + if (!uevent_vals[Env_ACTION] || +-- +2.43.0 + diff --git a/SOURCES/0003-dlm_controld-handle-RELEASE_RECOVER-event-env.patch b/SOURCES/0003-dlm_controld-handle-RELEASE_RECOVER-event-env.patch new file mode 100644 index 0000000..d114e6d --- /dev/null +++ b/SOURCES/0003-dlm_controld-handle-RELEASE_RECOVER-event-env.patch @@ -0,0 +1,232 @@ +From d317347643ec2610bbbd390493cf5e920f4ddd79 Mon Sep 17 00:00:00 2001 +From: Alexander Aring +Date: Fri, 22 Nov 2024 12:45:36 -0500 +Subject: [PATCH 3/3] dlm_controld: handle RELEASE_RECOVER event env + +Newer kernels might sending an additional attribute for the leaving lockspace +event "RELEASE_RECOVER" to tell other nodes from the release lockspace +initator to call the recover_slot() callback in their recovery handling +as a membership update triggers in-kernel recovery. +--- + dlm_controld/action.c | 33 ++++++++++++++++++ + dlm_controld/cpg.c | 72 ++++++++++++++++++++++++++++++++++++++- + dlm_controld/dlm_daemon.h | 6 +++- + dlm_controld/main.c | 4 ++- + 4 files changed, 112 insertions(+), 3 deletions(-) + +diff --git a/dlm_controld/action.c b/dlm_controld/action.c +index 0eff2799..6d23a330 100644 +--- a/dlm_controld/action.c ++++ b/dlm_controld/action.c +@@ -240,6 +240,39 @@ int path_exists(const char *path) + return 1; + } + ++int set_configfs_member_release_recover(struct lockspace *ls, int id, ++ uint32_t release_recover) ++{ ++ char path[PATH_MAX]; ++ char buf[32]; ++ int fd, rv; ++ ++ memset(path, 0, PATH_MAX); ++ snprintf(path, PATH_MAX, "%s/%s/nodes/%d/release_recover", ++ SPACES_DIR, ls->name, id); ++ ++ rv = fd = open(path, O_WRONLY); ++ if (rv < 0) { ++ log_error("%s: open failed: %d", path, errno); ++ goto out; ++ } ++ ++ memset(buf, 0, 32); ++ snprintf(buf, 32, "%u", release_recover); ++ ++ rv = do_write(fd, buf, strlen(buf)); ++ if (rv < 0) { ++ log_error("%s: write failed: %d, %s", path, errno, buf); ++ close(fd); ++ goto out; ++ } ++ close(fd); ++ rv = 0; ++ ++out: ++ return rv; ++} ++ + /* The "renew" nodes are those that have left and rejoined since the last + call to set_members(). We rmdir/mkdir for these nodes so dlm-kernel + can notice they've left and rejoined. */ +diff --git a/dlm_controld/cpg.c b/dlm_controld/cpg.c +index f3365ee4..10139664 100644 +--- a/dlm_controld/cpg.c ++++ b/dlm_controld/cpg.c +@@ -1057,6 +1057,23 @@ static void receive_start(struct lockspace *ls, struct dlm_header *hd, int len) + memb->start = 1; + } + ++static void receive_release_recover(struct lockspace *ls, ++ struct dlm_header *hd, int len) ++{ ++ uint32_t release_recover = hd->msgdata; ++ ++ log_dlock(ls, "%s %d: len %d release_recover %u", __func__, ++ hd->nodeid, len, release_recover); ++ ++ if (hd->nodeid == our_nodeid) ++ return; ++ ++ /* try to set members release recover setting before removing to ++ * tell other nodes the release recover option from the initiator. ++ */ ++ set_configfs_member_release_recover(ls, hd->nodeid, release_recover); ++} ++ + static void receive_plocks_done(struct lockspace *ls, struct dlm_header *hd, + int len) + { +@@ -1170,6 +1187,43 @@ static void send_info(struct lockspace *ls, struct change *cg, int type, + free(buf); + } + ++static void send_release_recover_msg(struct lockspace *ls, int type, ++ unsigned long release_recover) ++{ ++ struct dlm_header *hd; ++ char *buf; ++ int len; ++ ++ len = sizeof(struct dlm_header); ++ ++ buf = malloc(len); ++ if (!buf) { ++ log_error("send_info len %d no mem", len); ++ return; ++ } ++ memset(buf, 0, len); ++ ++ hd = (struct dlm_header *)buf; ++ ++ /* fill in header (dlm_send_message handles part of header) */ ++ ++ hd->type = type; ++ hd->msgdata = release_recover; ++ ++ dlm_send_message(ls, buf, len); ++ ++ free(buf); ++} ++ ++static void send_release_recover(struct lockspace *ls, ++ unsigned long release_recover) ++{ ++ log_group(ls, "%s %d: counts %u release_recover: %ld", __func__, ++ our_nodeid, ls->started_count, release_recover); ++ ++ send_release_recover_msg(ls, DLM_MSG_RELEASE_RECOVER, release_recover); ++} ++ + /* fenced used the DUPLICATE_CG flag instead of sending nacks like we + do here. I think the nacks didn't work for fenced for some reason, + but I don't remember why (possibly because the node blocked doing +@@ -1642,6 +1696,10 @@ static void deliver_cb(cpg_handle_t handle, + hd->type, nodeid, enable_plock); + break; + ++ case DLM_MSG_RELEASE_RECOVER: ++ receive_release_recover(ls, hd, len); ++ break; ++ + #if 0 + case DLM_MSG_DEADLK_CYCLE_START: + if (opt(enable_deadlk)) +@@ -1809,12 +1867,24 @@ int dlm_join_lockspace(struct lockspace *ls) + + /* received an "offline" uevent from dlm-kernel */ + +-int dlm_leave_lockspace(struct lockspace *ls) ++int dlm_leave_lockspace(struct lockspace *ls, const char *release_recover_str) + { + cs_error_t error; + struct cpg_name name; ++ unsigned long release_recover; + int i = 0; + ++ if (release_recover_str) { ++ release_recover = strtoul(release_recover_str, NULL, 0); ++ if (release_recover == ULONG_MAX) { ++ log_error("failed to parse release recover: %s", ++ release_recover_str); ++ return errno; ++ } ++ ++ send_release_recover(ls, release_recover); ++ } ++ + ls->leaving = 1; + + memset(&name, 0, sizeof(name)); +diff --git a/dlm_controld/dlm_daemon.h b/dlm_controld/dlm_daemon.h +index 45b295ea..119eb543 100644 +--- a/dlm_controld/dlm_daemon.h ++++ b/dlm_controld/dlm_daemon.h +@@ -236,6 +236,7 @@ enum { + DLM_MSG_RUN_REQUEST, + DLM_MSG_RUN_REPLY, + DLM_MSG_RUN_CANCEL, ++ DLM_MSG_RELEASE_RECOVER, + }; + + /* dlm_header flags */ +@@ -367,6 +368,8 @@ int set_sysfs_control(char *name, int val); + int set_sysfs_event_done(char *name, int val); + int set_sysfs_id(char *name, uint32_t id); + int set_sysfs_nodir(char *name, int val); ++int set_configfs_member_release_recover(struct lockspace *ls, int id, ++ uint32_t release_recover); + int set_configfs_members(struct lockspace *ls, char *name, + int new_count, int *new_members, + int renew_count, int *renew_members); +@@ -389,7 +392,8 @@ void setup_lockspace_config(struct lockspace *ls); + void process_lockspace_changes(void); + void process_fencing_changes(void); + int dlm_join_lockspace(struct lockspace *ls); +-int dlm_leave_lockspace(struct lockspace *ls); ++int dlm_leave_lockspace(struct lockspace *ls, ++ const char *release_recover_str); + void update_flow_control_status(void); + int set_node_info(struct lockspace *ls, int nodeid, struct dlmc_node *node); + int set_lockspace_info(struct lockspace *ls, struct dlmc_lockspace *lockspace); +diff --git a/dlm_controld/main.c b/dlm_controld/main.c +index 1828428c..2dc6b91b 100644 +--- a/dlm_controld/main.c ++++ b/dlm_controld/main.c +@@ -51,6 +51,7 @@ enum { + Env_DEVPATH, + Env_SUBSYSTEM, + Env_LOCKSPACE, ++ Env_RELEASE_RECOVER, + Env_Last, /* Flag for end of vars */ + }; + +@@ -59,6 +60,7 @@ static const char *uevent_vars[] = { + [Env_DEVPATH] = "DEVPATH=", + [Env_SUBSYSTEM] = "SUBSYSTEM=", + [Env_LOCKSPACE] = "LOCKSPACE=", ++ [Env_RELEASE_RECOVER] = "RELEASE_RECOVER=", + }; + + static void decode_uevent(const char *buf, unsigned len, const char *vars[], +@@ -770,7 +772,7 @@ static void process_uevent(int ci) + goto out; + } + +- dlm_leave_lockspace(ls); ++ dlm_leave_lockspace(ls, uevent_vals[Env_RELEASE_RECOVER]); + } + out: + if (rv < 0) +-- +2.43.0 + diff --git a/SPECS/dlm.spec b/SPECS/dlm.spec index 2766763..b83f018 100644 --- a/SPECS/dlm.spec +++ b/SPECS/dlm.spec @@ -1,6 +1,6 @@ Name: dlm Version: 4.1.0 -Release: 1%{?dist} +Release: 3%{?dist} License: GPLv2 and GPLv2+ and LGPLv2+ # For a breakdown of the licensing, see README.license Group: System Environment/Kernel @@ -15,6 +15,10 @@ BuildRequires: systemd-devel Source0: https://releases.pagure.org/dlm/%{name}-%{version}.tar.gz # Patch0: 0001-foo.patch +Patch0: 0001-dlm_controld-better-uevent-filtering.patch +Patch1: 0002-dlm_controld-terminate-uevent-buffer.patch +Patch2: 0003-dlm_controld-handle-RELEASE_RECOVER-event-env.patch +Patch3: 0001-dlm_controld-send-plock-operations-without-resource-.patch %if 0%{?rhel} && 0%{?rhel} <= 7 ExclusiveArch: i686 x86_64 @@ -34,6 +38,10 @@ The kernel dlm requires a user daemon to control membership. %prep %setup -q # %patch0 -p1 -b .0001-foo.patch +%patch0 -p1 -b .backup0 +%patch1 -p1 -b .backup1 +%patch2 -p1 -b .backup2 +%patch3 -p1 -b .backup3 %build # upstream does not require configure @@ -105,6 +113,14 @@ developing applications that use %{name}. %{_libdir}/pkgconfig/*.pc %changelog +* Tue Jan 20 2026 Alexander Aring - 4.1.0-3 +- Rebuild for posix lock issue fix + Related: RHEL-140243 + +* Tue Dec 16 2025 Alexander Aring - 4.1.0-2 +- Rebuild for recover flag functionality + Related: RHEL-136235 + * Wed Jan 13 2021 David Teigland - 4.1.0-1 - update to 4.1.0