xref: /linux/fs/smb/smbdirect/listen.c (revision 8ab992f815d6736b5c7a6f5fd7bfe7bc106bb3dc)
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