[PATCH AUTOSEL 6.15 033/110] dlm: use SHUT_RDWR for SCTP shutdown

Sasha Levin
2025-06-01T23:26:03Z

From: Alexander Aring <aahringo@redhat.com>

[ Upstream commit 55612ddb62fc12437a7ff2f27b51a8981bc187a4 ]

Currently SCTP shutdown() call gets stuck because there is no incoming
EOF indicator on its socket. On the peer side the EOF indicator as
recvmsg() returns 0 will be triggered as mechanism to flush the socket
queue on the receive side. In SCTP recvmsg() function sctp_recvmsg() we
can see that only if sk_shutdown has the bit RCV_SHUTDOWN set SCTP will
recvmsg() will return EOF. The RCV_SHUTDOWN bit will only be set when
shutdown with SHUT_RD is called. We use now SHUT_RDWR to also get a EOF
indicator from recvmsg() call on the shutdown() initiator.

SCTP does not support half closed sockets and the semantic of SHUT_WR is
different here, it seems that calling SHUT_WR on sctp sockets keeps the
socket open to have the possibility to do some specific SCTP operations on
it that we don't do here.

There exists still a difference in the limitations of TCP vs SCTP in
case if we are required to have a half closed socket functionality. This
was tried to archieve with DLM protocol changes in the past and
hopefully we really don't require half closed socket functionality.

Signed-off-by: Alexander Aring <aahringo@redhat.com>
Tested-by: Heming zhao <heming.zhao@suse.com>
Reviewed-by: Heming zhao <heming.zhao@suse.com>
Signed-off-by: David Teigland <teigland@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

Based on my analysis, here is my assessment: **YES** This commit should
be backported to stable kernel trees. ## Analysis ### The Problem The
commit addresses a critical functional issue in DLM (Distributed Lock
Manager) when using SCTP protocol. The issue is that SCTP shutdown
operations get stuck because there's no incoming EOF indicator on the
socket, preventing proper connection cleanup. ### Root Cause Analysis
from Code Changes 1. **Current behavior (before patch)**: DLM always
uses `SHUT_WR` for both TCP and SCTP protocols in
`kernel_sock_shutdown(con->sock, SHUT_WR)` at line 813 in the
`shutdown_connection()` function. 2. **SCTP-specific problem**: Unlike
TCP, SCTP requires both read and write shutdown (`SHUT_RDWR`) to
properly trigger the EOF condition. The commit message explains that
SCTP's `recvmsg()` function (`sctp_recvmsg()`) only returns EOF when
`sk_shutdown` has the `RCV_SHUTDOWN` bit set, which only happens with
`SHUT_RD` or `SHUT_RDWR`. 3. **The fix**: The patch introduces a new
`how` field in the `dlm_proto_ops` structure and sets: - TCP: `SHUT_WR`
(maintains existing behavior) - SCTP: `SHUT_RDWR` (fixes the EOF
detection issue) ### Why This Should Be Backported 1. **Critical Bug
Fix**: This fixes a fundamental functional issue where DLM connections
using SCTP cannot properly shutdown, leading to stuck operations. 2.
**Minimal and Contained Change**: - Adds only one new field to a
protocol operations structure - Changes only the shutdown method
parameter based on protocol - No architectural changes or new features
3. **Clear Side Effects Assessment**: The change is protocol-specific
and maintains backward compatibility. TCP behavior is unchanged, and
SCTP behavior is fixed to work as intended. 4. **Follows Stable Tree
Rules**: - Fixes an important bug affecting users of DLM with SCTP -
Small, well-contained change with minimal regression risk - No
introduction of new features 5. **Historical Context**: Looking at the
git history, there have been multiple fixes for DLM shutdown handling,
indicating this is an actively maintained and critical subsystem. This
specific fix addresses a protocol-level compatibility issue that has
likely affected users. 6. **Similar Backport Patterns**: This is similar
to "Similar Commit #1" which was marked as YES - it's a contained fix
for connection handling in DLM with clear problem scope and minimal code
changes. The fix is essential for environments using DLM with SCTP
protocol, as without it, proper connection shutdown is impossible,
leading to resource leaks and potentially affecting cluster operations.

fs/dlm/lowcomms.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 70abd4da17a63..90abcd07f8898 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -160,6 +160,7 @@ struct dlm_proto_ops {
bool try_new_addr;
const char *name;
int proto;
+ int how;

void (*sockopts)(struct socket *sock);
int (*bind)(struct socket *sock);
@@ -810,7 +811,7 @@ static void shutdown_connection(struct connection *con, bool and_other)
return;
}

- ret = kernel_sock_shutdown(con->sock, SHUT_WR);
+ ret = kernel_sock_shutdown(con->sock, dlm_proto_ops->how);
up_read(&con->sock_lock);
if (ret) {
log_print("Connection %p failed to shutdown: %d will force close",
@@ -1858,6 +1859,7 @@ static int dlm_tcp_listen_bind(struct socket *sock)
static const struct dlm_proto_ops dlm_tcp_ops = {
.name = "TCP",
.proto = IPPROTO_TCP,
+ .how = SHUT_WR,
.sockopts = dlm_tcp_sockopts,
.bind = dlm_tcp_bind,
.listen_validate = dlm_tcp_listen_validate,
@@ -1896,6 +1898,7 @@ static void dlm_sctp_sockopts(struct socket *sock)
static const struct dlm_proto_ops dlm_sctp_ops = {
.name = "SCTP",
.proto = IPPROTO_SCTP,
+ .how = SHUT_RDWR,
.try_new_addr = true,
.sockopts = dlm_sctp_sockopts,
.bind = dlm_sctp_bind,
--
2.39.5