1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2017, Microsoft Corporation.
4 * Copyright (C) 2018, LG Electronics.
5 * Copyright (c) 2025, Stefan Metzmacher
6 */
7
8 #include "internal.h"
9
10 static int smbdirect_listen_rdma_event_handler(struct rdma_cm_id *id,
11 struct rdma_cm_event *event);
12
smbdirect_socket_listen(struct smbdirect_socket * sc,int backlog)13 int smbdirect_socket_listen(struct smbdirect_socket *sc, int backlog)
14 {
15 int ret;
16
17 if (backlog < 0)
18 return -EINVAL;
19 if (!backlog)
20 backlog = 1; /* use 1 as default for now */
21
22 if (sc->first_error)
23 return -EINVAL;
24
25 if (sc->status != SMBDIRECT_SOCKET_CREATED)
26 return -EINVAL;
27
28 if (WARN_ON_ONCE(!sc->rdma.cm_id))
29 return -EINVAL;
30
31 if (sc->rdma.cm_id->device)
32 smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
33 "try to listen on addr: %pISpsfc dev: %.*s\n",
34 &sc->rdma.cm_id->route.addr.src_addr,
35 IB_DEVICE_NAME_MAX,
36 sc->rdma.cm_id->device->name);
37 else
38 smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
39 "try to listen on addr: %pISpsfc\n",
40 &sc->rdma.cm_id->route.addr.src_addr);
41
42 /* already checked above */
43 WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_CREATED);
44 sc->status = SMBDIRECT_SOCKET_LISTENING;
45 sc->rdma.expected_event = RDMA_CM_EVENT_CONNECT_REQUEST;
46 rdma_lock_handler(sc->rdma.cm_id);
47 sc->rdma.cm_id->event_handler = smbdirect_listen_rdma_event_handler;
48 rdma_unlock_handler(sc->rdma.cm_id);
49
50 ret = rdma_listen(sc->rdma.cm_id, backlog);
51 if (ret) {
52 sc->first_error = ret;
53 sc->status = SMBDIRECT_SOCKET_DISCONNECTED;
54 if (sc->rdma.cm_id->device)
55 smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
56 "listening failed %1pe on addr: %pISpsfc dev: %.*s\n",
57 SMBDIRECT_DEBUG_ERR_PTR(ret),
58 &sc->rdma.cm_id->route.addr.src_addr,
59 IB_DEVICE_NAME_MAX,
60 sc->rdma.cm_id->device->name);
61 else
62 smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
63 "listening failed %1pe on addr: %pISpsfc\n",
64 SMBDIRECT_DEBUG_ERR_PTR(ret),
65 &sc->rdma.cm_id->route.addr.src_addr);
66 return ret;
67 }
68
69 /*
70 * This is a value > 0, checked above,
71 * so we are able to use sc->listen.backlog == -1,
72 * as indication that the socket was never
73 * a listener.
74 */
75 sc->listen.backlog = backlog;
76
77 if (sc->rdma.cm_id->device)
78 smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
79 "listening on addr: %pISpsfc dev: %.*s\n",
80 &sc->rdma.cm_id->route.addr.src_addr,
81 IB_DEVICE_NAME_MAX,
82 sc->rdma.cm_id->device->name);
83 else
84 smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO,
85 "listening on addr: %pISpsfc\n",
86 &sc->rdma.cm_id->route.addr.src_addr);
87
88 /*
89 * The rest happens async via smbdirect_listen_rdma_event_handler()
90 */
91 return 0;
92 }
93 EXPORT_SYMBOL_GPL(smbdirect_socket_listen);
94
smbdirect_new_rdma_event_handler(struct rdma_cm_id * new_id,struct rdma_cm_event * event)95 static int smbdirect_new_rdma_event_handler(struct rdma_cm_id *new_id,
96 struct rdma_cm_event *event)
97 {
98 int ret = -ESTALE;
99
100 /*
101 * This should be replaced before any real work
102 * starts! So it should never be called!
103 */
104
105 if (event->event == RDMA_CM_EVENT_DEVICE_REMOVAL)
106 ret = -ENETDOWN;
107 if (IS_ERR(SMBDIRECT_DEBUG_ERR_PTR(event->status)))
108 ret = event->status;
109 WARN_ONCE(1,
110 "%s should not be called! event=%s status=%d => ret=%1pe\n",
111 __func__,
112 rdma_event_msg(event->event),
113 event->status,
114 SMBDIRECT_DEBUG_ERR_PTR(ret));
115 return -ESTALE;
116 }
117
118 static int smbdirect_listen_connect_request(struct smbdirect_socket *lsc,
119 struct rdma_cm_id *new_id,
120 const struct rdma_cm_event *event);
121
smbdirect_listen_rdma_event_handler(struct rdma_cm_id * new_id,struct rdma_cm_event * event)122 static int smbdirect_listen_rdma_event_handler(struct rdma_cm_id *new_id,
123 struct rdma_cm_event *event)
124 {
125 struct smbdirect_socket *lsc = new_id->context;
126 int ret;
127
128 if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST) {
129 new_id->context = NULL;
130 new_id->event_handler = smbdirect_new_rdma_event_handler;
131 } else
132 new_id = NULL;
133
134 /*
135 * cma_cm_event_handler() has
136 * lockdep_assert_held(&id_priv->handler_mutex);
137 *
138 * Mutexes are not allowed in interrupts,
139 * and we rely on not being in an interrupt here,
140 * as we might sleep.
141 */
142 WARN_ON_ONCE(in_interrupt());
143
144 if (event->status || event->event != lsc->rdma.expected_event) {
145 ret = -ECONNABORTED;
146
147 if (event->event == RDMA_CM_EVENT_DEVICE_REMOVAL)
148 ret = -ENETDOWN;
149 if (IS_ERR(SMBDIRECT_DEBUG_ERR_PTR(event->status)))
150 ret = event->status;
151
152 smbdirect_log_rdma_event(lsc, SMBDIRECT_LOG_ERR,
153 "%s (first_error=%1pe, expected=%s) => event=%s status=%d => ret=%1pe\n",
154 smbdirect_socket_status_string(lsc->status),
155 SMBDIRECT_DEBUG_ERR_PTR(lsc->first_error),
156 rdma_event_msg(lsc->rdma.expected_event),
157 rdma_event_msg(event->event),
158 event->status,
159 SMBDIRECT_DEBUG_ERR_PTR(ret));
160
161 /*
162 * In case of error return it and let the caller
163 * destroy new_id
164 */
165 smbdirect_socket_schedule_cleanup(lsc, ret);
166 return new_id ? ret : 0;
167 }
168
169 smbdirect_log_rdma_event(lsc, SMBDIRECT_LOG_INFO,
170 "%s (first_error=%1pe) event=%s\n",
171 smbdirect_socket_status_string(lsc->status),
172 SMBDIRECT_DEBUG_ERR_PTR(lsc->first_error),
173 rdma_event_msg(event->event));
174
175 /*
176 * In case of error return it and let the caller
177 * destroy new_id
178 */
179 if (lsc->first_error)
180 return new_id ? lsc->first_error : 0;
181
182 switch (event->event) {
183 case RDMA_CM_EVENT_CONNECT_REQUEST:
184 WARN_ON_ONCE(lsc->status != SMBDIRECT_SOCKET_LISTENING);
185
186 /*
187 * In case of error return it and let the caller
188 * destroy new_id
189 */
190 ret = smbdirect_listen_connect_request(lsc, new_id, event);
191 if (ret)
192 return ret;
193 return 0;
194
195 default:
196 break;
197 }
198
199 /*
200 * This is an internal error
201 */
202 WARN_ON_ONCE(lsc->rdma.expected_event != RDMA_CM_EVENT_CONNECT_REQUEST);
203 smbdirect_socket_schedule_cleanup(lsc, -EINVAL);
204 return 0;
205 }
206
smbdirect_listen_connect_request(struct smbdirect_socket * lsc,struct rdma_cm_id * new_id,const struct rdma_cm_event * event)207 static int smbdirect_listen_connect_request(struct smbdirect_socket *lsc,
208 struct rdma_cm_id *new_id,
209 const struct rdma_cm_event *event)
210 {
211 const struct smbdirect_socket_parameters *lsp = &lsc->parameters;
212 struct smbdirect_socket *nsc;
213 unsigned long flags;
214 size_t backlog = max_t(size_t, 1, lsc->listen.backlog);
215 size_t psockets;
216 size_t rsockets;
217 int ret;
218
219 if (!smbdirect_frwr_is_supported(&new_id->device->attrs)) {
220 smbdirect_log_rdma_event(lsc, SMBDIRECT_LOG_ERR,
221 "Fast Registration Work Requests (FRWR) is not supported device %.*s\n",
222 IB_DEVICE_NAME_MAX,
223 new_id->device->name);
224 smbdirect_log_rdma_event(lsc, SMBDIRECT_LOG_ERR,
225 "Device capability flags = %llx max_fast_reg_page_list_len = %u\n",
226 new_id->device->attrs.device_cap_flags,
227 new_id->device->attrs.max_fast_reg_page_list_len);
228 return -EPROTONOSUPPORT;
229 }
230
231 if (lsp->flags & SMBDIRECT_FLAG_PORT_RANGE_ONLY_IB &&
232 !rdma_ib_or_roce(new_id->device, new_id->port_num)) {
233 smbdirect_log_rdma_event(lsc, SMBDIRECT_LOG_ERR,
234 "Not IB: device: %.*s IW:%u local: %pISpsfc remote: %pISpsfc\n",
235 IB_DEVICE_NAME_MAX,
236 new_id->device->name,
237 rdma_protocol_iwarp(new_id->device, new_id->port_num),
238 &new_id->route.addr.src_addr,
239 &new_id->route.addr.dst_addr);
240 return -EPROTONOSUPPORT;
241 }
242 if (lsp->flags & SMBDIRECT_FLAG_PORT_RANGE_ONLY_IW &&
243 !rdma_protocol_iwarp(new_id->device, new_id->port_num)) {
244 smbdirect_log_rdma_event(lsc, SMBDIRECT_LOG_ERR,
245 "Not IW: device: %.*s IB:%u local: %pISpsfc remote: %pISpsfc\n",
246 IB_DEVICE_NAME_MAX,
247 new_id->device->name,
248 rdma_ib_or_roce(new_id->device, new_id->port_num),
249 &new_id->route.addr.src_addr,
250 &new_id->route.addr.dst_addr);
251 return -EPROTONOSUPPORT;
252 }
253
254 spin_lock_irqsave(&lsc->listen.lock, flags);
255 psockets = list_count_nodes(&lsc->listen.pending);
256 rsockets = list_count_nodes(&lsc->listen.ready);
257 spin_unlock_irqrestore(&lsc->listen.lock, flags);
258
259 if (psockets > backlog ||
260 rsockets > backlog ||
261 (psockets + rsockets) > backlog) {
262 smbdirect_log_rdma_event(lsc, SMBDIRECT_LOG_ERR,
263 "Backlog[%d][%zu] full pending[%zu] ready[%zu]\n",
264 lsc->listen.backlog, backlog, psockets, rsockets);
265 return -EBUSY;
266 }
267
268 ret = smbdirect_socket_create_accepting(new_id, &nsc);
269 if (ret)
270 goto socket_init_failed;
271
272 nsc->logging = lsc->logging;
273 ret = smbdirect_socket_set_initial_parameters(nsc, &lsc->parameters);
274 if (ret)
275 goto set_params_failed;
276 ret = smbdirect_socket_set_kernel_settings(nsc,
277 lsc->ib.poll_ctx,
278 lsc->send_io.mem.gfp_mask);
279 if (ret)
280 goto set_settings_failed;
281
282 spin_lock_irqsave(&lsc->listen.lock, flags);
283 list_add_tail(&nsc->accept.list, &lsc->listen.pending);
284 nsc->accept.listener = lsc;
285 spin_unlock_irqrestore(&lsc->listen.lock, flags);
286
287 ret = smbdirect_accept_connect_request(nsc, &event->param.conn);
288 if (ret)
289 goto accept_connect_failed;
290
291 return 0;
292
293 accept_connect_failed:
294 spin_lock_irqsave(&lsc->listen.lock, flags);
295 list_del_init(&nsc->accept.list);
296 nsc->accept.listener = NULL;
297 spin_unlock_irqrestore(&lsc->listen.lock, flags);
298 set_settings_failed:
299 set_params_failed:
300 /*
301 * The caller will destroy new_id
302 */
303 nsc->ib.dev = NULL;
304 nsc->rdma.cm_id = NULL;
305 smbdirect_socket_release(nsc);
306 socket_init_failed:
307 return ret;
308 }
309