Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

smb: client: relax WARN_ON_ONCE(SMBDIRECT_SOCKET_*) checks in recv_done() and smbd_conn_upcall()

sc->first_error might already be set and sc->status
is thus unexpected, so this should avoid the WARN[_ON]_ONCE()
if sc->first_error is already set and have a usable error path.

While there set sc->first_error as soon as possible.

This is done based on a problem seen in similar places on
the server. And there it was already very useful in order
to find the problem when we have a meaningful WARN_ONCE()
that prints details about the connection.

This is much more useful:

[ 309.560973] expected[NEGOTIATE_NEEDED] != RDMA_CONNECT_RUNNING
first_error=0 local=192.168.0.200:445 remote=192.168.0.100:60445
[ 309.561034] WARNING: CPU: 2 PID: 78 at transport_rdma.c:643
recv_done+0x2fa/0x3d0 [ksmbd]

than what we had before (only):

[ 894.140316] WARNING: CPU: 1 PID: 116 at
fs/smb/server/transport_rdma.c:642 recv_done+0x308/0x360 [ksmbd]

Fixes: 58dfba8a2d4e ("smb: client/smbdirect: replace SMBDIRECT_SOCKET_CONNECTING with more detailed states")
Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: Long Li <longli@microsoft.com>
Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: Paulo Alcantara <pc@manguebit.org>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>

authored by

Stefan Metzmacher and committed by
Steve French
dc10cf13 425c3275

+15 -13
+15 -13
fs/smb/client/smbdirect.c
··· 7 7 #include <linux/module.h> 8 8 #include <linux/highmem.h> 9 9 #include <linux/folio_queue.h> 10 + #define __SMBDIRECT_SOCKET_DISCONNECT(__sc) smbd_disconnect_rdma_connection(__sc) 10 11 #include "../common/smbdirect/smbdirect_pdu.h" 11 12 #include "smbdirect.h" 12 13 #include "cifs_debug.h" ··· 187 186 struct smbdirect_socket *sc = 188 187 container_of(work, struct smbdirect_socket, disconnect_work); 189 188 189 + if (sc->first_error == 0) 190 + sc->first_error = -ECONNABORTED; 191 + 190 192 /* 191 193 * make sure this and other work is not queued again 192 194 * but here we don't block and avoid ··· 200 196 disable_work(&sc->mr_io.recovery_work); 201 197 disable_work(&sc->idle.immediate_work); 202 198 disable_delayed_work(&sc->idle.timer_work); 203 - 204 - if (sc->first_error == 0) 205 - sc->first_error = -ECONNABORTED; 206 199 207 200 switch (sc->status) { 208 201 case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: ··· 243 242 244 243 static void smbd_disconnect_rdma_connection(struct smbdirect_socket *sc) 245 244 { 245 + if (sc->first_error == 0) 246 + sc->first_error = -ECONNABORTED; 247 + 246 248 /* 247 249 * make sure other work (than disconnect_work) is 248 250 * not queued again but here we don't block and avoid ··· 255 251 disable_work(&sc->mr_io.recovery_work); 256 252 disable_work(&sc->idle.immediate_work); 257 253 disable_delayed_work(&sc->idle.timer_work); 258 - 259 - if (sc->first_error == 0) 260 - sc->first_error = -ECONNABORTED; 261 254 262 255 switch (sc->status) { 263 256 case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED: ··· 323 322 324 323 switch (event->event) { 325 324 case RDMA_CM_EVENT_ADDR_RESOLVED: 326 - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); 325 + if (SMBDIRECT_CHECK_STATUS_DISCONNECT(sc, SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING)) 326 + break; 327 327 sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED; 328 328 wake_up(&sc->status_wait); 329 329 break; 330 330 331 331 case RDMA_CM_EVENT_ROUTE_RESOLVED: 332 - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); 332 + if (SMBDIRECT_CHECK_STATUS_DISCONNECT(sc, SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING)) 333 + break; 333 334 sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED; 334 335 wake_up(&sc->status_wait); 335 336 break; 336 337 337 338 case RDMA_CM_EVENT_ADDR_ERROR: 338 339 log_rdma_event(ERR, "connecting failed event=%s\n", event_name); 339 - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); 340 340 sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED; 341 341 smbd_disconnect_rdma_work(&sc->disconnect_work); 342 342 break; 343 343 344 344 case RDMA_CM_EVENT_ROUTE_ERROR: 345 345 log_rdma_event(ERR, "connecting failed event=%s\n", event_name); 346 - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); 347 346 sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED; 348 347 smbd_disconnect_rdma_work(&sc->disconnect_work); 349 348 break; ··· 429 428 min_t(u8, sp->responder_resources, 430 429 peer_responder_resources); 431 430 432 - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); 431 + if (SMBDIRECT_CHECK_STATUS_DISCONNECT(sc, SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING)) 432 + break; 433 433 sc->status = SMBDIRECT_SOCKET_NEGOTIATE_NEEDED; 434 434 wake_up(&sc->status_wait); 435 435 break; ··· 439 437 case RDMA_CM_EVENT_UNREACHABLE: 440 438 case RDMA_CM_EVENT_REJECTED: 441 439 log_rdma_event(ERR, "connecting failed event=%s\n", event_name); 442 - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); 443 440 sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED; 444 441 smbd_disconnect_rdma_work(&sc->disconnect_work); 445 442 break; ··· 700 699 negotiate_done = 701 700 process_negotiation_response(response, wc->byte_len); 702 701 put_receive_buffer(sc, response); 703 - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_NEGOTIATE_RUNNING); 702 + if (SMBDIRECT_CHECK_STATUS_WARN(sc, SMBDIRECT_SOCKET_NEGOTIATE_RUNNING)) 703 + negotiate_done = false; 704 704 if (!negotiate_done) { 705 705 sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; 706 706 smbd_disconnect_rdma_connection(sc);