1*1249c01aSStefan Metzmacher // SPDX-License-Identifier: GPL-2.0-or-later 2*1249c01aSStefan Metzmacher /* 3*1249c01aSStefan Metzmacher * Copyright (C) 2017, Microsoft Corporation. 4*1249c01aSStefan Metzmacher * Copyright (c) 2025, Stefan Metzmacher 5*1249c01aSStefan Metzmacher */ 6*1249c01aSStefan Metzmacher 7*1249c01aSStefan Metzmacher #include "internal.h" 8*1249c01aSStefan Metzmacher 9*1249c01aSStefan Metzmacher bool smbdirect_frwr_is_supported(const struct ib_device_attr *attrs) 10*1249c01aSStefan Metzmacher { 11*1249c01aSStefan Metzmacher /* 12*1249c01aSStefan Metzmacher * Test if FRWR (Fast Registration Work Requests) is supported on the 13*1249c01aSStefan Metzmacher * device This implementation requires FRWR on RDMA read/write return 14*1249c01aSStefan Metzmacher * value: true if it is supported 15*1249c01aSStefan Metzmacher */ 16*1249c01aSStefan Metzmacher 17*1249c01aSStefan Metzmacher if (!(attrs->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS)) 18*1249c01aSStefan Metzmacher return false; 19*1249c01aSStefan Metzmacher if (attrs->max_fast_reg_page_list_len == 0) 20*1249c01aSStefan Metzmacher return false; 21*1249c01aSStefan Metzmacher return true; 22*1249c01aSStefan Metzmacher } 23*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_frwr_is_supported); 24*1249c01aSStefan Metzmacher 25*1249c01aSStefan Metzmacher static void smbdirect_socket_cleanup_work(struct work_struct *work); 26*1249c01aSStefan Metzmacher 27*1249c01aSStefan Metzmacher static int smbdirect_socket_rdma_event_handler(struct rdma_cm_id *id, 28*1249c01aSStefan Metzmacher struct rdma_cm_event *event) 29*1249c01aSStefan Metzmacher { 30*1249c01aSStefan Metzmacher struct smbdirect_socket *sc = id->context; 31*1249c01aSStefan Metzmacher int ret = -ESTALE; 32*1249c01aSStefan Metzmacher 33*1249c01aSStefan Metzmacher /* 34*1249c01aSStefan Metzmacher * This should be replaced before any real work 35*1249c01aSStefan Metzmacher * starts! So it should never be called! 36*1249c01aSStefan Metzmacher */ 37*1249c01aSStefan Metzmacher 38*1249c01aSStefan Metzmacher if (event->event == RDMA_CM_EVENT_DEVICE_REMOVAL) 39*1249c01aSStefan Metzmacher ret = -ENETDOWN; 40*1249c01aSStefan Metzmacher if (IS_ERR(SMBDIRECT_DEBUG_ERR_PTR(event->status))) 41*1249c01aSStefan Metzmacher ret = event->status; 42*1249c01aSStefan Metzmacher pr_err("%s (first_error=%1pe, expected=%s) => event=%s status=%d => ret=%1pe\n", 43*1249c01aSStefan Metzmacher smbdirect_socket_status_string(sc->status), 44*1249c01aSStefan Metzmacher SMBDIRECT_DEBUG_ERR_PTR(sc->first_error), 45*1249c01aSStefan Metzmacher rdma_event_msg(sc->rdma.expected_event), 46*1249c01aSStefan Metzmacher rdma_event_msg(event->event), 47*1249c01aSStefan Metzmacher event->status, 48*1249c01aSStefan Metzmacher SMBDIRECT_DEBUG_ERR_PTR(ret)); 49*1249c01aSStefan Metzmacher WARN_ONCE(1, "%s should not be called!\n", __func__); 50*1249c01aSStefan Metzmacher sc->rdma.cm_id = NULL; 51*1249c01aSStefan Metzmacher return -ESTALE; 52*1249c01aSStefan Metzmacher } 53*1249c01aSStefan Metzmacher 54*1249c01aSStefan Metzmacher int smbdirect_socket_init_new(struct net *net, struct smbdirect_socket *sc) 55*1249c01aSStefan Metzmacher { 56*1249c01aSStefan Metzmacher struct rdma_cm_id *id; 57*1249c01aSStefan Metzmacher int ret; 58*1249c01aSStefan Metzmacher 59*1249c01aSStefan Metzmacher smbdirect_socket_init(sc); 60*1249c01aSStefan Metzmacher 61*1249c01aSStefan Metzmacher id = rdma_create_id(net, 62*1249c01aSStefan Metzmacher smbdirect_socket_rdma_event_handler, 63*1249c01aSStefan Metzmacher sc, 64*1249c01aSStefan Metzmacher RDMA_PS_TCP, 65*1249c01aSStefan Metzmacher IB_QPT_RC); 66*1249c01aSStefan Metzmacher if (IS_ERR(id)) { 67*1249c01aSStefan Metzmacher pr_err("%s: rdma_create_id() failed %1pe\n", __func__, id); 68*1249c01aSStefan Metzmacher return PTR_ERR(id); 69*1249c01aSStefan Metzmacher } 70*1249c01aSStefan Metzmacher 71*1249c01aSStefan Metzmacher ret = rdma_set_afonly(id, 1); 72*1249c01aSStefan Metzmacher if (ret) { 73*1249c01aSStefan Metzmacher rdma_destroy_id(id); 74*1249c01aSStefan Metzmacher pr_err("%s: rdma_set_afonly() failed %1pe\n", 75*1249c01aSStefan Metzmacher __func__, SMBDIRECT_DEBUG_ERR_PTR(ret)); 76*1249c01aSStefan Metzmacher return ret; 77*1249c01aSStefan Metzmacher } 78*1249c01aSStefan Metzmacher 79*1249c01aSStefan Metzmacher sc->rdma.cm_id = id; 80*1249c01aSStefan Metzmacher 81*1249c01aSStefan Metzmacher INIT_WORK(&sc->disconnect_work, smbdirect_socket_cleanup_work); 82*1249c01aSStefan Metzmacher 83*1249c01aSStefan Metzmacher return 0; 84*1249c01aSStefan Metzmacher } 85*1249c01aSStefan Metzmacher 86*1249c01aSStefan Metzmacher int smbdirect_socket_create_kern(struct net *net, struct smbdirect_socket **_sc) 87*1249c01aSStefan Metzmacher { 88*1249c01aSStefan Metzmacher struct smbdirect_socket *sc; 89*1249c01aSStefan Metzmacher int ret; 90*1249c01aSStefan Metzmacher 91*1249c01aSStefan Metzmacher ret = -ENOMEM; 92*1249c01aSStefan Metzmacher sc = kzalloc_obj(*sc); 93*1249c01aSStefan Metzmacher if (!sc) 94*1249c01aSStefan Metzmacher goto alloc_failed; 95*1249c01aSStefan Metzmacher 96*1249c01aSStefan Metzmacher ret = smbdirect_socket_init_new(net, sc); 97*1249c01aSStefan Metzmacher if (ret) 98*1249c01aSStefan Metzmacher goto init_failed; 99*1249c01aSStefan Metzmacher 100*1249c01aSStefan Metzmacher kref_init(&sc->refs.destroy); 101*1249c01aSStefan Metzmacher 102*1249c01aSStefan Metzmacher *_sc = sc; 103*1249c01aSStefan Metzmacher return 0; 104*1249c01aSStefan Metzmacher 105*1249c01aSStefan Metzmacher init_failed: 106*1249c01aSStefan Metzmacher kfree(sc); 107*1249c01aSStefan Metzmacher alloc_failed: 108*1249c01aSStefan Metzmacher return ret; 109*1249c01aSStefan Metzmacher } 110*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_create_kern); 111*1249c01aSStefan Metzmacher 112*1249c01aSStefan Metzmacher int smbdirect_socket_init_accepting(struct rdma_cm_id *id, struct smbdirect_socket *sc) 113*1249c01aSStefan Metzmacher { 114*1249c01aSStefan Metzmacher smbdirect_socket_init(sc); 115*1249c01aSStefan Metzmacher 116*1249c01aSStefan Metzmacher sc->rdma.cm_id = id; 117*1249c01aSStefan Metzmacher sc->rdma.cm_id->context = sc; 118*1249c01aSStefan Metzmacher sc->rdma.cm_id->event_handler = smbdirect_socket_rdma_event_handler; 119*1249c01aSStefan Metzmacher 120*1249c01aSStefan Metzmacher sc->ib.dev = sc->rdma.cm_id->device; 121*1249c01aSStefan Metzmacher 122*1249c01aSStefan Metzmacher INIT_WORK(&sc->disconnect_work, smbdirect_socket_cleanup_work); 123*1249c01aSStefan Metzmacher 124*1249c01aSStefan Metzmacher return 0; 125*1249c01aSStefan Metzmacher } 126*1249c01aSStefan Metzmacher 127*1249c01aSStefan Metzmacher int smbdirect_socket_create_accepting(struct rdma_cm_id *id, struct smbdirect_socket **_sc) 128*1249c01aSStefan Metzmacher { 129*1249c01aSStefan Metzmacher struct smbdirect_socket *sc; 130*1249c01aSStefan Metzmacher int ret; 131*1249c01aSStefan Metzmacher 132*1249c01aSStefan Metzmacher ret = -ENOMEM; 133*1249c01aSStefan Metzmacher sc = kzalloc_obj(*sc); 134*1249c01aSStefan Metzmacher if (!sc) 135*1249c01aSStefan Metzmacher goto alloc_failed; 136*1249c01aSStefan Metzmacher 137*1249c01aSStefan Metzmacher ret = smbdirect_socket_init_accepting(id, sc); 138*1249c01aSStefan Metzmacher if (ret) 139*1249c01aSStefan Metzmacher goto init_failed; 140*1249c01aSStefan Metzmacher 141*1249c01aSStefan Metzmacher kref_init(&sc->refs.destroy); 142*1249c01aSStefan Metzmacher 143*1249c01aSStefan Metzmacher *_sc = sc; 144*1249c01aSStefan Metzmacher return 0; 145*1249c01aSStefan Metzmacher 146*1249c01aSStefan Metzmacher init_failed: 147*1249c01aSStefan Metzmacher kfree(sc); 148*1249c01aSStefan Metzmacher alloc_failed: 149*1249c01aSStefan Metzmacher return ret; 150*1249c01aSStefan Metzmacher } 151*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_create_accepting); 152*1249c01aSStefan Metzmacher 153*1249c01aSStefan Metzmacher int smbdirect_socket_set_initial_parameters(struct smbdirect_socket *sc, 154*1249c01aSStefan Metzmacher const struct smbdirect_socket_parameters *sp) 155*1249c01aSStefan Metzmacher { 156*1249c01aSStefan Metzmacher /* 157*1249c01aSStefan Metzmacher * This is only allowed before connect or accept 158*1249c01aSStefan Metzmacher */ 159*1249c01aSStefan Metzmacher WARN_ONCE(sc->status != SMBDIRECT_SOCKET_CREATED, 160*1249c01aSStefan Metzmacher "status=%s first_error=%1pe", 161*1249c01aSStefan Metzmacher smbdirect_socket_status_string(sc->status), 162*1249c01aSStefan Metzmacher SMBDIRECT_DEBUG_ERR_PTR(sc->first_error)); 163*1249c01aSStefan Metzmacher if (sc->status != SMBDIRECT_SOCKET_CREATED) 164*1249c01aSStefan Metzmacher return -EINVAL; 165*1249c01aSStefan Metzmacher 166*1249c01aSStefan Metzmacher if (sp->flags & ~SMBDIRECT_FLAG_PORT_RANGE_MASK) 167*1249c01aSStefan Metzmacher return -EINVAL; 168*1249c01aSStefan Metzmacher 169*1249c01aSStefan Metzmacher if (sp->initiator_depth > U8_MAX) 170*1249c01aSStefan Metzmacher return -EINVAL; 171*1249c01aSStefan Metzmacher if (sp->responder_resources > U8_MAX) 172*1249c01aSStefan Metzmacher return -EINVAL; 173*1249c01aSStefan Metzmacher 174*1249c01aSStefan Metzmacher if (sp->flags & SMBDIRECT_FLAG_PORT_RANGE_ONLY_IB && 175*1249c01aSStefan Metzmacher sp->flags & SMBDIRECT_FLAG_PORT_RANGE_ONLY_IW) 176*1249c01aSStefan Metzmacher return -EINVAL; 177*1249c01aSStefan Metzmacher else if (sp->flags & SMBDIRECT_FLAG_PORT_RANGE_ONLY_IB) 178*1249c01aSStefan Metzmacher rdma_restrict_node_type(sc->rdma.cm_id, RDMA_NODE_IB_CA); 179*1249c01aSStefan Metzmacher else if (sp->flags & SMBDIRECT_FLAG_PORT_RANGE_ONLY_IW) 180*1249c01aSStefan Metzmacher rdma_restrict_node_type(sc->rdma.cm_id, RDMA_NODE_RNIC); 181*1249c01aSStefan Metzmacher 182*1249c01aSStefan Metzmacher /* 183*1249c01aSStefan Metzmacher * Make a copy of the callers parameters 184*1249c01aSStefan Metzmacher * from here we only work on the copy 185*1249c01aSStefan Metzmacher * 186*1249c01aSStefan Metzmacher * TODO: do we want consistency checking? 187*1249c01aSStefan Metzmacher */ 188*1249c01aSStefan Metzmacher sc->parameters = *sp; 189*1249c01aSStefan Metzmacher 190*1249c01aSStefan Metzmacher return 0; 191*1249c01aSStefan Metzmacher } 192*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_set_initial_parameters); 193*1249c01aSStefan Metzmacher 194*1249c01aSStefan Metzmacher const struct smbdirect_socket_parameters * 195*1249c01aSStefan Metzmacher smbdirect_socket_get_current_parameters(struct smbdirect_socket *sc) 196*1249c01aSStefan Metzmacher { 197*1249c01aSStefan Metzmacher return &sc->parameters; 198*1249c01aSStefan Metzmacher } 199*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_get_current_parameters); 200*1249c01aSStefan Metzmacher 201*1249c01aSStefan Metzmacher int smbdirect_socket_set_kernel_settings(struct smbdirect_socket *sc, 202*1249c01aSStefan Metzmacher enum ib_poll_context poll_ctx, 203*1249c01aSStefan Metzmacher gfp_t gfp_mask) 204*1249c01aSStefan Metzmacher { 205*1249c01aSStefan Metzmacher /* 206*1249c01aSStefan Metzmacher * This is only allowed before connect or accept 207*1249c01aSStefan Metzmacher */ 208*1249c01aSStefan Metzmacher WARN_ONCE(sc->status != SMBDIRECT_SOCKET_CREATED, 209*1249c01aSStefan Metzmacher "status=%s first_error=%1pe", 210*1249c01aSStefan Metzmacher smbdirect_socket_status_string(sc->status), 211*1249c01aSStefan Metzmacher SMBDIRECT_DEBUG_ERR_PTR(sc->first_error)); 212*1249c01aSStefan Metzmacher if (sc->status != SMBDIRECT_SOCKET_CREATED) 213*1249c01aSStefan Metzmacher return -EINVAL; 214*1249c01aSStefan Metzmacher 215*1249c01aSStefan Metzmacher sc->ib.poll_ctx = poll_ctx; 216*1249c01aSStefan Metzmacher 217*1249c01aSStefan Metzmacher sc->send_io.mem.gfp_mask = gfp_mask; 218*1249c01aSStefan Metzmacher sc->recv_io.mem.gfp_mask = gfp_mask; 219*1249c01aSStefan Metzmacher sc->rw_io.mem.gfp_mask = gfp_mask; 220*1249c01aSStefan Metzmacher 221*1249c01aSStefan Metzmacher return 0; 222*1249c01aSStefan Metzmacher } 223*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_set_kernel_settings); 224*1249c01aSStefan Metzmacher 225*1249c01aSStefan Metzmacher void smbdirect_socket_set_logging(struct smbdirect_socket *sc, 226*1249c01aSStefan Metzmacher void *private_ptr, 227*1249c01aSStefan Metzmacher bool (*needed)(struct smbdirect_socket *sc, 228*1249c01aSStefan Metzmacher void *private_ptr, 229*1249c01aSStefan Metzmacher unsigned int lvl, 230*1249c01aSStefan Metzmacher unsigned int cls), 231*1249c01aSStefan Metzmacher void (*vaprintf)(struct smbdirect_socket *sc, 232*1249c01aSStefan Metzmacher const char *func, 233*1249c01aSStefan Metzmacher unsigned int line, 234*1249c01aSStefan Metzmacher void *private_ptr, 235*1249c01aSStefan Metzmacher unsigned int lvl, 236*1249c01aSStefan Metzmacher unsigned int cls, 237*1249c01aSStefan Metzmacher struct va_format *vaf)) 238*1249c01aSStefan Metzmacher { 239*1249c01aSStefan Metzmacher sc->logging.private_ptr = private_ptr; 240*1249c01aSStefan Metzmacher sc->logging.needed = needed; 241*1249c01aSStefan Metzmacher sc->logging.vaprintf = vaprintf; 242*1249c01aSStefan Metzmacher } 243*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_set_logging); 244*1249c01aSStefan Metzmacher 245*1249c01aSStefan Metzmacher static void smbdirect_socket_wake_up_all(struct smbdirect_socket *sc) 246*1249c01aSStefan Metzmacher { 247*1249c01aSStefan Metzmacher /* 248*1249c01aSStefan Metzmacher * Wake up all waiters in all wait queues 249*1249c01aSStefan Metzmacher * in order to notice the broken connection. 250*1249c01aSStefan Metzmacher */ 251*1249c01aSStefan Metzmacher wake_up_all(&sc->status_wait); 252*1249c01aSStefan Metzmacher wake_up_all(&sc->listen.wait_queue); 253*1249c01aSStefan Metzmacher wake_up_all(&sc->send_io.bcredits.wait_queue); 254*1249c01aSStefan Metzmacher wake_up_all(&sc->send_io.lcredits.wait_queue); 255*1249c01aSStefan Metzmacher wake_up_all(&sc->send_io.credits.wait_queue); 256*1249c01aSStefan Metzmacher wake_up_all(&sc->send_io.pending.zero_wait_queue); 257*1249c01aSStefan Metzmacher wake_up_all(&sc->recv_io.reassembly.wait_queue); 258*1249c01aSStefan Metzmacher wake_up_all(&sc->rw_io.credits.wait_queue); 259*1249c01aSStefan Metzmacher wake_up_all(&sc->mr_io.ready.wait_queue); 260*1249c01aSStefan Metzmacher } 261*1249c01aSStefan Metzmacher 262*1249c01aSStefan Metzmacher void __smbdirect_socket_schedule_cleanup(struct smbdirect_socket *sc, 263*1249c01aSStefan Metzmacher const char *macro_name, 264*1249c01aSStefan Metzmacher unsigned int lvl, 265*1249c01aSStefan Metzmacher const char *func, 266*1249c01aSStefan Metzmacher unsigned int line, 267*1249c01aSStefan Metzmacher int error, 268*1249c01aSStefan Metzmacher enum smbdirect_socket_status *force_status) 269*1249c01aSStefan Metzmacher { 270*1249c01aSStefan Metzmacher struct smbdirect_socket *psc, *tsc; 271*1249c01aSStefan Metzmacher unsigned long flags; 272*1249c01aSStefan Metzmacher bool was_first = false; 273*1249c01aSStefan Metzmacher 274*1249c01aSStefan Metzmacher if (!sc->first_error) { 275*1249c01aSStefan Metzmacher ___smbdirect_log_generic(sc, func, line, 276*1249c01aSStefan Metzmacher lvl, 277*1249c01aSStefan Metzmacher SMBDIRECT_LOG_RDMA_EVENT, 278*1249c01aSStefan Metzmacher "%s(%1pe%s%s) called from %s in line=%u status=%s\n", 279*1249c01aSStefan Metzmacher macro_name, 280*1249c01aSStefan Metzmacher SMBDIRECT_DEBUG_ERR_PTR(error), 281*1249c01aSStefan Metzmacher force_status ? ", " : "", 282*1249c01aSStefan Metzmacher force_status ? smbdirect_socket_status_string(*force_status) : "", 283*1249c01aSStefan Metzmacher func, line, 284*1249c01aSStefan Metzmacher smbdirect_socket_status_string(sc->status)); 285*1249c01aSStefan Metzmacher if (error) 286*1249c01aSStefan Metzmacher sc->first_error = error; 287*1249c01aSStefan Metzmacher else 288*1249c01aSStefan Metzmacher sc->first_error = -ECONNABORTED; 289*1249c01aSStefan Metzmacher was_first = true; 290*1249c01aSStefan Metzmacher } 291*1249c01aSStefan Metzmacher 292*1249c01aSStefan Metzmacher /* 293*1249c01aSStefan Metzmacher * make sure other work (than disconnect_work) 294*1249c01aSStefan Metzmacher * is not queued again but here we don't block and avoid 295*1249c01aSStefan Metzmacher * disable[_delayed]_work_sync() 296*1249c01aSStefan Metzmacher */ 297*1249c01aSStefan Metzmacher disable_work(&sc->connect.work); 298*1249c01aSStefan Metzmacher disable_work(&sc->recv_io.posted.refill_work); 299*1249c01aSStefan Metzmacher disable_work(&sc->idle.immediate_work); 300*1249c01aSStefan Metzmacher sc->idle.keepalive = SMBDIRECT_KEEPALIVE_NONE; 301*1249c01aSStefan Metzmacher disable_delayed_work(&sc->idle.timer_work); 302*1249c01aSStefan Metzmacher 303*1249c01aSStefan Metzmacher /* 304*1249c01aSStefan Metzmacher * In case we were a listener we need to 305*1249c01aSStefan Metzmacher * disconnect all pending and ready sockets 306*1249c01aSStefan Metzmacher * 307*1249c01aSStefan Metzmacher * First we move ready sockets to pending again. 308*1249c01aSStefan Metzmacher */ 309*1249c01aSStefan Metzmacher spin_lock_irqsave(&sc->listen.lock, flags); 310*1249c01aSStefan Metzmacher list_splice_init(&sc->listen.ready, &sc->listen.pending); 311*1249c01aSStefan Metzmacher list_for_each_entry_safe(psc, tsc, &sc->listen.pending, accept.list) 312*1249c01aSStefan Metzmacher smbdirect_socket_schedule_cleanup(psc, sc->first_error); 313*1249c01aSStefan Metzmacher spin_unlock_irqrestore(&sc->listen.lock, flags); 314*1249c01aSStefan Metzmacher 315*1249c01aSStefan Metzmacher switch (sc->status) { 316*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED: 317*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED: 318*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED: 319*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_NEGOTIATE_FAILED: 320*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_ERROR: 321*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_DISCONNECTING: 322*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_DISCONNECTED: 323*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_DESTROYED: 324*1249c01aSStefan Metzmacher /* 325*1249c01aSStefan Metzmacher * Keep the current error status 326*1249c01aSStefan Metzmacher */ 327*1249c01aSStefan Metzmacher break; 328*1249c01aSStefan Metzmacher 329*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RESOLVE_ADDR_NEEDED: 330*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING: 331*1249c01aSStefan Metzmacher sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED; 332*1249c01aSStefan Metzmacher break; 333*1249c01aSStefan Metzmacher 334*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED: 335*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING: 336*1249c01aSStefan Metzmacher sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED; 337*1249c01aSStefan Metzmacher break; 338*1249c01aSStefan Metzmacher 339*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED: 340*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING: 341*1249c01aSStefan Metzmacher sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED; 342*1249c01aSStefan Metzmacher break; 343*1249c01aSStefan Metzmacher 344*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: 345*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING: 346*1249c01aSStefan Metzmacher sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; 347*1249c01aSStefan Metzmacher break; 348*1249c01aSStefan Metzmacher 349*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_CREATED: 350*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_LISTENING: 351*1249c01aSStefan Metzmacher sc->status = SMBDIRECT_SOCKET_DISCONNECTED; 352*1249c01aSStefan Metzmacher break; 353*1249c01aSStefan Metzmacher 354*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_CONNECTED: 355*1249c01aSStefan Metzmacher sc->status = SMBDIRECT_SOCKET_ERROR; 356*1249c01aSStefan Metzmacher break; 357*1249c01aSStefan Metzmacher } 358*1249c01aSStefan Metzmacher 359*1249c01aSStefan Metzmacher if (force_status && (was_first || *force_status > sc->status)) 360*1249c01aSStefan Metzmacher sc->status = *force_status; 361*1249c01aSStefan Metzmacher 362*1249c01aSStefan Metzmacher /* 363*1249c01aSStefan Metzmacher * Wake up all waiters in all wait queues 364*1249c01aSStefan Metzmacher * in order to notice the broken connection. 365*1249c01aSStefan Metzmacher */ 366*1249c01aSStefan Metzmacher smbdirect_socket_wake_up_all(sc); 367*1249c01aSStefan Metzmacher 368*1249c01aSStefan Metzmacher queue_work(sc->workqueues.cleanup, &sc->disconnect_work); 369*1249c01aSStefan Metzmacher } 370*1249c01aSStefan Metzmacher 371*1249c01aSStefan Metzmacher static void smbdirect_socket_cleanup_work(struct work_struct *work) 372*1249c01aSStefan Metzmacher { 373*1249c01aSStefan Metzmacher struct smbdirect_socket *sc = 374*1249c01aSStefan Metzmacher container_of(work, struct smbdirect_socket, disconnect_work); 375*1249c01aSStefan Metzmacher struct smbdirect_socket *psc, *tsc; 376*1249c01aSStefan Metzmacher unsigned long flags; 377*1249c01aSStefan Metzmacher 378*1249c01aSStefan Metzmacher /* 379*1249c01aSStefan Metzmacher * This should not never be called in an interrupt! 380*1249c01aSStefan Metzmacher */ 381*1249c01aSStefan Metzmacher WARN_ON_ONCE(in_interrupt()); 382*1249c01aSStefan Metzmacher 383*1249c01aSStefan Metzmacher if (!sc->first_error) { 384*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_ERR, 385*1249c01aSStefan Metzmacher "%s called with first_error==0\n", 386*1249c01aSStefan Metzmacher smbdirect_socket_status_string(sc->status)); 387*1249c01aSStefan Metzmacher 388*1249c01aSStefan Metzmacher sc->first_error = -ECONNABORTED; 389*1249c01aSStefan Metzmacher } 390*1249c01aSStefan Metzmacher 391*1249c01aSStefan Metzmacher /* 392*1249c01aSStefan Metzmacher * make sure this and other work is not queued again 393*1249c01aSStefan Metzmacher * but here we don't block and avoid 394*1249c01aSStefan Metzmacher * disable[_delayed]_work_sync() 395*1249c01aSStefan Metzmacher */ 396*1249c01aSStefan Metzmacher disable_work(&sc->disconnect_work); 397*1249c01aSStefan Metzmacher disable_work(&sc->connect.work); 398*1249c01aSStefan Metzmacher disable_work(&sc->recv_io.posted.refill_work); 399*1249c01aSStefan Metzmacher disable_work(&sc->idle.immediate_work); 400*1249c01aSStefan Metzmacher sc->idle.keepalive = SMBDIRECT_KEEPALIVE_NONE; 401*1249c01aSStefan Metzmacher disable_delayed_work(&sc->idle.timer_work); 402*1249c01aSStefan Metzmacher 403*1249c01aSStefan Metzmacher /* 404*1249c01aSStefan Metzmacher * In case we were a listener we need to 405*1249c01aSStefan Metzmacher * disconnect all pending and ready sockets 406*1249c01aSStefan Metzmacher * 407*1249c01aSStefan Metzmacher * First we move ready sockets to pending again. 408*1249c01aSStefan Metzmacher */ 409*1249c01aSStefan Metzmacher spin_lock_irqsave(&sc->listen.lock, flags); 410*1249c01aSStefan Metzmacher list_splice_init(&sc->listen.ready, &sc->listen.pending); 411*1249c01aSStefan Metzmacher list_for_each_entry_safe(psc, tsc, &sc->listen.pending, accept.list) 412*1249c01aSStefan Metzmacher smbdirect_socket_schedule_cleanup(psc, sc->first_error); 413*1249c01aSStefan Metzmacher spin_unlock_irqrestore(&sc->listen.lock, flags); 414*1249c01aSStefan Metzmacher 415*1249c01aSStefan Metzmacher switch (sc->status) { 416*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: 417*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING: 418*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_NEGOTIATE_FAILED: 419*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_CONNECTED: 420*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_ERROR: 421*1249c01aSStefan Metzmacher sc->status = SMBDIRECT_SOCKET_DISCONNECTING; 422*1249c01aSStefan Metzmacher /* 423*1249c01aSStefan Metzmacher * Make sure we hold the callback lock 424*1249c01aSStefan Metzmacher * im order to coordinate with the 425*1249c01aSStefan Metzmacher * rdma_event handlers, typically 426*1249c01aSStefan Metzmacher * smbdirect_connection_rdma_event_handler(), 427*1249c01aSStefan Metzmacher * and smbdirect_socket_destroy(). 428*1249c01aSStefan Metzmacher * 429*1249c01aSStefan Metzmacher * So that the order of ib_drain_qp() 430*1249c01aSStefan Metzmacher * and rdma_disconnect() is controlled 431*1249c01aSStefan Metzmacher * by the mutex. 432*1249c01aSStefan Metzmacher */ 433*1249c01aSStefan Metzmacher rdma_lock_handler(sc->rdma.cm_id); 434*1249c01aSStefan Metzmacher rdma_disconnect(sc->rdma.cm_id); 435*1249c01aSStefan Metzmacher rdma_unlock_handler(sc->rdma.cm_id); 436*1249c01aSStefan Metzmacher break; 437*1249c01aSStefan Metzmacher 438*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_CREATED: 439*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_LISTENING: 440*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RESOLVE_ADDR_NEEDED: 441*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING: 442*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED: 443*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED: 444*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING: 445*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED: 446*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED: 447*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING: 448*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED: 449*1249c01aSStefan Metzmacher /* 450*1249c01aSStefan Metzmacher * rdma_{accept,connect}() never reached 451*1249c01aSStefan Metzmacher * RDMA_CM_EVENT_ESTABLISHED 452*1249c01aSStefan Metzmacher */ 453*1249c01aSStefan Metzmacher sc->status = SMBDIRECT_SOCKET_DISCONNECTED; 454*1249c01aSStefan Metzmacher break; 455*1249c01aSStefan Metzmacher 456*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_DISCONNECTING: 457*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_DISCONNECTED: 458*1249c01aSStefan Metzmacher case SMBDIRECT_SOCKET_DESTROYED: 459*1249c01aSStefan Metzmacher break; 460*1249c01aSStefan Metzmacher } 461*1249c01aSStefan Metzmacher 462*1249c01aSStefan Metzmacher /* 463*1249c01aSStefan Metzmacher * Wake up all waiters in all wait queues 464*1249c01aSStefan Metzmacher * in order to notice the broken connection. 465*1249c01aSStefan Metzmacher */ 466*1249c01aSStefan Metzmacher smbdirect_socket_wake_up_all(sc); 467*1249c01aSStefan Metzmacher } 468*1249c01aSStefan Metzmacher 469*1249c01aSStefan Metzmacher static void smbdirect_socket_destroy(struct smbdirect_socket *sc) 470*1249c01aSStefan Metzmacher { 471*1249c01aSStefan Metzmacher struct smbdirect_socket *psc, *tsc; 472*1249c01aSStefan Metzmacher size_t psockets; 473*1249c01aSStefan Metzmacher struct smbdirect_recv_io *recv_io; 474*1249c01aSStefan Metzmacher struct smbdirect_recv_io *recv_tmp; 475*1249c01aSStefan Metzmacher LIST_HEAD(all_list); 476*1249c01aSStefan Metzmacher unsigned long flags; 477*1249c01aSStefan Metzmacher 478*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, 479*1249c01aSStefan Metzmacher "status=%s first_error=%1pe", 480*1249c01aSStefan Metzmacher smbdirect_socket_status_string(sc->status), 481*1249c01aSStefan Metzmacher SMBDIRECT_DEBUG_ERR_PTR(sc->first_error)); 482*1249c01aSStefan Metzmacher 483*1249c01aSStefan Metzmacher /* 484*1249c01aSStefan Metzmacher * This should not never be called in an interrupt! 485*1249c01aSStefan Metzmacher */ 486*1249c01aSStefan Metzmacher WARN_ON_ONCE(in_interrupt()); 487*1249c01aSStefan Metzmacher 488*1249c01aSStefan Metzmacher if (sc->status == SMBDIRECT_SOCKET_DESTROYED) 489*1249c01aSStefan Metzmacher return; 490*1249c01aSStefan Metzmacher 491*1249c01aSStefan Metzmacher WARN_ONCE(sc->status != SMBDIRECT_SOCKET_DISCONNECTED, 492*1249c01aSStefan Metzmacher "status=%s first_error=%1pe", 493*1249c01aSStefan Metzmacher smbdirect_socket_status_string(sc->status), 494*1249c01aSStefan Metzmacher SMBDIRECT_DEBUG_ERR_PTR(sc->first_error)); 495*1249c01aSStefan Metzmacher 496*1249c01aSStefan Metzmacher /* 497*1249c01aSStefan Metzmacher * The listener should clear this before we reach this 498*1249c01aSStefan Metzmacher */ 499*1249c01aSStefan Metzmacher WARN_ONCE(sc->accept.listener, 500*1249c01aSStefan Metzmacher "status=%s first_error=%1pe", 501*1249c01aSStefan Metzmacher smbdirect_socket_status_string(sc->status), 502*1249c01aSStefan Metzmacher SMBDIRECT_DEBUG_ERR_PTR(sc->first_error)); 503*1249c01aSStefan Metzmacher 504*1249c01aSStefan Metzmacher /* 505*1249c01aSStefan Metzmacher * Wake up all waiters in all wait queues 506*1249c01aSStefan Metzmacher * in order to notice the broken connection. 507*1249c01aSStefan Metzmacher * 508*1249c01aSStefan Metzmacher * Most likely this was already called via 509*1249c01aSStefan Metzmacher * smbdirect_socket_cleanup_work(), but call it again... 510*1249c01aSStefan Metzmacher */ 511*1249c01aSStefan Metzmacher smbdirect_socket_wake_up_all(sc); 512*1249c01aSStefan Metzmacher 513*1249c01aSStefan Metzmacher disable_work_sync(&sc->disconnect_work); 514*1249c01aSStefan Metzmacher disable_work_sync(&sc->connect.work); 515*1249c01aSStefan Metzmacher disable_work_sync(&sc->recv_io.posted.refill_work); 516*1249c01aSStefan Metzmacher disable_work_sync(&sc->idle.immediate_work); 517*1249c01aSStefan Metzmacher disable_delayed_work_sync(&sc->idle.timer_work); 518*1249c01aSStefan Metzmacher 519*1249c01aSStefan Metzmacher if (sc->rdma.cm_id) 520*1249c01aSStefan Metzmacher rdma_lock_handler(sc->rdma.cm_id); 521*1249c01aSStefan Metzmacher 522*1249c01aSStefan Metzmacher if (sc->ib.qp) { 523*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, 524*1249c01aSStefan Metzmacher "drain qp\n"); 525*1249c01aSStefan Metzmacher ib_drain_qp(sc->ib.qp); 526*1249c01aSStefan Metzmacher } 527*1249c01aSStefan Metzmacher 528*1249c01aSStefan Metzmacher /* 529*1249c01aSStefan Metzmacher * In case we were a listener we need to 530*1249c01aSStefan Metzmacher * disconnect all pending and ready sockets 531*1249c01aSStefan Metzmacher * 532*1249c01aSStefan Metzmacher * We move ready sockets to pending again. 533*1249c01aSStefan Metzmacher */ 534*1249c01aSStefan Metzmacher spin_lock_irqsave(&sc->listen.lock, flags); 535*1249c01aSStefan Metzmacher list_splice_tail_init(&sc->listen.ready, &all_list); 536*1249c01aSStefan Metzmacher list_splice_tail_init(&sc->listen.pending, &all_list); 537*1249c01aSStefan Metzmacher spin_unlock_irqrestore(&sc->listen.lock, flags); 538*1249c01aSStefan Metzmacher psockets = list_count_nodes(&all_list); 539*1249c01aSStefan Metzmacher if (sc->listen.backlog != -1) /* was a listener */ 540*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, 541*1249c01aSStefan Metzmacher "release %zu pending sockets\n", psockets); 542*1249c01aSStefan Metzmacher list_for_each_entry_safe(psc, tsc, &all_list, accept.list) { 543*1249c01aSStefan Metzmacher list_del_init(&psc->accept.list); 544*1249c01aSStefan Metzmacher psc->accept.listener = NULL; 545*1249c01aSStefan Metzmacher smbdirect_socket_release(psc); 546*1249c01aSStefan Metzmacher } 547*1249c01aSStefan Metzmacher if (sc->listen.backlog != -1) /* was a listener */ 548*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, 549*1249c01aSStefan Metzmacher "released %zu pending sockets\n", psockets); 550*1249c01aSStefan Metzmacher INIT_LIST_HEAD(&all_list); 551*1249c01aSStefan Metzmacher 552*1249c01aSStefan Metzmacher /* It's not possible for upper layer to get to reassembly */ 553*1249c01aSStefan Metzmacher if (sc->listen.backlog == -1) /* was not a listener */ 554*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, 555*1249c01aSStefan Metzmacher "drain the reassembly queue\n"); 556*1249c01aSStefan Metzmacher spin_lock_irqsave(&sc->recv_io.reassembly.lock, flags); 557*1249c01aSStefan Metzmacher list_splice_tail_init(&sc->recv_io.reassembly.list, &all_list); 558*1249c01aSStefan Metzmacher spin_unlock_irqrestore(&sc->recv_io.reassembly.lock, flags); 559*1249c01aSStefan Metzmacher list_for_each_entry_safe(recv_io, recv_tmp, &all_list, list) 560*1249c01aSStefan Metzmacher smbdirect_connection_put_recv_io(recv_io); 561*1249c01aSStefan Metzmacher sc->recv_io.reassembly.data_length = 0; 562*1249c01aSStefan Metzmacher 563*1249c01aSStefan Metzmacher if (sc->listen.backlog == -1) /* was not a listener */ 564*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, 565*1249c01aSStefan Metzmacher "freeing mr list\n"); 566*1249c01aSStefan Metzmacher smbdirect_connection_destroy_mr_list(sc); 567*1249c01aSStefan Metzmacher 568*1249c01aSStefan Metzmacher if (sc->listen.backlog == -1) /* was not a listener */ 569*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, 570*1249c01aSStefan Metzmacher "destroying qp\n"); 571*1249c01aSStefan Metzmacher smbdirect_connection_destroy_qp(sc); 572*1249c01aSStefan Metzmacher if (sc->rdma.cm_id) { 573*1249c01aSStefan Metzmacher rdma_unlock_handler(sc->rdma.cm_id); 574*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, 575*1249c01aSStefan Metzmacher "destroying cm_id\n"); 576*1249c01aSStefan Metzmacher rdma_destroy_id(sc->rdma.cm_id); 577*1249c01aSStefan Metzmacher sc->rdma.cm_id = NULL; 578*1249c01aSStefan Metzmacher } 579*1249c01aSStefan Metzmacher 580*1249c01aSStefan Metzmacher if (sc->listen.backlog == -1) /* was not a listener */ 581*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, 582*1249c01aSStefan Metzmacher "destroying mem pools\n"); 583*1249c01aSStefan Metzmacher smbdirect_connection_destroy_mem_pools(sc); 584*1249c01aSStefan Metzmacher 585*1249c01aSStefan Metzmacher sc->status = SMBDIRECT_SOCKET_DESTROYED; 586*1249c01aSStefan Metzmacher 587*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, 588*1249c01aSStefan Metzmacher "rdma session destroyed\n"); 589*1249c01aSStefan Metzmacher } 590*1249c01aSStefan Metzmacher 591*1249c01aSStefan Metzmacher void smbdirect_socket_destroy_sync(struct smbdirect_socket *sc) 592*1249c01aSStefan Metzmacher { 593*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, 594*1249c01aSStefan Metzmacher "status=%s first_error=%1pe", 595*1249c01aSStefan Metzmacher smbdirect_socket_status_string(sc->status), 596*1249c01aSStefan Metzmacher SMBDIRECT_DEBUG_ERR_PTR(sc->first_error)); 597*1249c01aSStefan Metzmacher 598*1249c01aSStefan Metzmacher /* 599*1249c01aSStefan Metzmacher * This should not never be called in an interrupt! 600*1249c01aSStefan Metzmacher */ 601*1249c01aSStefan Metzmacher WARN_ON_ONCE(in_interrupt()); 602*1249c01aSStefan Metzmacher 603*1249c01aSStefan Metzmacher /* 604*1249c01aSStefan Metzmacher * First we try to disable the work 605*1249c01aSStefan Metzmacher * without disable_work_sync() in a 606*1249c01aSStefan Metzmacher * non blocking way, if it's already 607*1249c01aSStefan Metzmacher * running it will be handles by 608*1249c01aSStefan Metzmacher * disable_work_sync() below. 609*1249c01aSStefan Metzmacher * 610*1249c01aSStefan Metzmacher * Here we just want to make sure queue_work() in 611*1249c01aSStefan Metzmacher * smbdirect_socket_schedule_cleanup_lvl() 612*1249c01aSStefan Metzmacher * is a no-op. 613*1249c01aSStefan Metzmacher */ 614*1249c01aSStefan Metzmacher disable_work(&sc->disconnect_work); 615*1249c01aSStefan Metzmacher 616*1249c01aSStefan Metzmacher if (!sc->first_error) 617*1249c01aSStefan Metzmacher /* 618*1249c01aSStefan Metzmacher * SMBDIRECT_LOG_INFO is enough here 619*1249c01aSStefan Metzmacher * as this is the typical case where 620*1249c01aSStefan Metzmacher * we terminate the connection ourself. 621*1249c01aSStefan Metzmacher */ 622*1249c01aSStefan Metzmacher smbdirect_socket_schedule_cleanup_lvl(sc, 623*1249c01aSStefan Metzmacher SMBDIRECT_LOG_INFO, 624*1249c01aSStefan Metzmacher -ESHUTDOWN); 625*1249c01aSStefan Metzmacher 626*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, 627*1249c01aSStefan Metzmacher "cancelling and disable disconnect_work\n"); 628*1249c01aSStefan Metzmacher disable_work_sync(&sc->disconnect_work); 629*1249c01aSStefan Metzmacher 630*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, 631*1249c01aSStefan Metzmacher "destroying rdma session\n"); 632*1249c01aSStefan Metzmacher if (sc->status < SMBDIRECT_SOCKET_DISCONNECTING) 633*1249c01aSStefan Metzmacher smbdirect_socket_cleanup_work(&sc->disconnect_work); 634*1249c01aSStefan Metzmacher if (sc->status < SMBDIRECT_SOCKET_DISCONNECTED) { 635*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, 636*1249c01aSStefan Metzmacher "wait for transport being disconnected\n"); 637*1249c01aSStefan Metzmacher wait_event(sc->status_wait, sc->status == SMBDIRECT_SOCKET_DISCONNECTED); 638*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, 639*1249c01aSStefan Metzmacher "waited for transport being disconnected\n"); 640*1249c01aSStefan Metzmacher } 641*1249c01aSStefan Metzmacher 642*1249c01aSStefan Metzmacher /* 643*1249c01aSStefan Metzmacher * Once we reached SMBDIRECT_SOCKET_DISCONNECTED, 644*1249c01aSStefan Metzmacher * we should call smbdirect_socket_destroy() 645*1249c01aSStefan Metzmacher */ 646*1249c01aSStefan Metzmacher smbdirect_socket_destroy(sc); 647*1249c01aSStefan Metzmacher smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, 648*1249c01aSStefan Metzmacher "status=%s first_error=%1pe", 649*1249c01aSStefan Metzmacher smbdirect_socket_status_string(sc->status), 650*1249c01aSStefan Metzmacher SMBDIRECT_DEBUG_ERR_PTR(sc->first_error)); 651*1249c01aSStefan Metzmacher } 652*1249c01aSStefan Metzmacher 653*1249c01aSStefan Metzmacher int smbdirect_socket_bind(struct smbdirect_socket *sc, struct sockaddr *addr) 654*1249c01aSStefan Metzmacher { 655*1249c01aSStefan Metzmacher int ret; 656*1249c01aSStefan Metzmacher 657*1249c01aSStefan Metzmacher if (sc->status != SMBDIRECT_SOCKET_CREATED) 658*1249c01aSStefan Metzmacher return -EINVAL; 659*1249c01aSStefan Metzmacher 660*1249c01aSStefan Metzmacher ret = rdma_bind_addr(sc->rdma.cm_id, addr); 661*1249c01aSStefan Metzmacher if (ret) 662*1249c01aSStefan Metzmacher return ret; 663*1249c01aSStefan Metzmacher 664*1249c01aSStefan Metzmacher return 0; 665*1249c01aSStefan Metzmacher } 666*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_bind); 667*1249c01aSStefan Metzmacher 668*1249c01aSStefan Metzmacher void smbdirect_socket_shutdown(struct smbdirect_socket *sc) 669*1249c01aSStefan Metzmacher { 670*1249c01aSStefan Metzmacher smbdirect_socket_schedule_cleanup_lvl(sc, SMBDIRECT_LOG_INFO, -ESHUTDOWN); 671*1249c01aSStefan Metzmacher } 672*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_shutdown); 673*1249c01aSStefan Metzmacher 674*1249c01aSStefan Metzmacher static void smbdirect_socket_release_disconnect(struct kref *kref) 675*1249c01aSStefan Metzmacher { 676*1249c01aSStefan Metzmacher struct smbdirect_socket *sc = 677*1249c01aSStefan Metzmacher container_of(kref, struct smbdirect_socket, refs.disconnect); 678*1249c01aSStefan Metzmacher 679*1249c01aSStefan Metzmacher /* 680*1249c01aSStefan Metzmacher * For now do a sync disconnect/destroy 681*1249c01aSStefan Metzmacher */ 682*1249c01aSStefan Metzmacher smbdirect_socket_destroy_sync(sc); 683*1249c01aSStefan Metzmacher } 684*1249c01aSStefan Metzmacher 685*1249c01aSStefan Metzmacher static void smbdirect_socket_release_destroy(struct kref *kref) 686*1249c01aSStefan Metzmacher { 687*1249c01aSStefan Metzmacher struct smbdirect_socket *sc = 688*1249c01aSStefan Metzmacher container_of(kref, struct smbdirect_socket, refs.destroy); 689*1249c01aSStefan Metzmacher 690*1249c01aSStefan Metzmacher /* 691*1249c01aSStefan Metzmacher * Do a sync disconnect/destroy... 692*1249c01aSStefan Metzmacher * hopefully a no-op, as it should be already 693*1249c01aSStefan Metzmacher * in DESTROYED state, before we free the memory. 694*1249c01aSStefan Metzmacher */ 695*1249c01aSStefan Metzmacher smbdirect_socket_destroy_sync(sc); 696*1249c01aSStefan Metzmacher kfree(sc); 697*1249c01aSStefan Metzmacher } 698*1249c01aSStefan Metzmacher 699*1249c01aSStefan Metzmacher void smbdirect_socket_release(struct smbdirect_socket *sc) 700*1249c01aSStefan Metzmacher { 701*1249c01aSStefan Metzmacher /* 702*1249c01aSStefan Metzmacher * We expect only 1 disconnect reference 703*1249c01aSStefan Metzmacher * and if it is already 0, it's a use after free! 704*1249c01aSStefan Metzmacher */ 705*1249c01aSStefan Metzmacher WARN_ON_ONCE(kref_read(&sc->refs.disconnect) != 1); 706*1249c01aSStefan Metzmacher WARN_ON(!kref_put(&sc->refs.disconnect, smbdirect_socket_release_disconnect)); 707*1249c01aSStefan Metzmacher 708*1249c01aSStefan Metzmacher /* 709*1249c01aSStefan Metzmacher * This may not trigger smbdirect_socket_release_destroy(), 710*1249c01aSStefan Metzmacher * if struct smbdirect_socket is embedded in another structure 711*1249c01aSStefan Metzmacher * indicated by REFCOUNT_MAX. 712*1249c01aSStefan Metzmacher */ 713*1249c01aSStefan Metzmacher kref_put(&sc->refs.destroy, smbdirect_socket_release_destroy); 714*1249c01aSStefan Metzmacher } 715*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_socket_release); 716*1249c01aSStefan Metzmacher 717*1249c01aSStefan Metzmacher int smbdirect_socket_wait_for_credits(struct smbdirect_socket *sc, 718*1249c01aSStefan Metzmacher enum smbdirect_socket_status expected_status, 719*1249c01aSStefan Metzmacher int unexpected_errno, 720*1249c01aSStefan Metzmacher wait_queue_head_t *waitq, 721*1249c01aSStefan Metzmacher atomic_t *total_credits, 722*1249c01aSStefan Metzmacher int needed) 723*1249c01aSStefan Metzmacher { 724*1249c01aSStefan Metzmacher int ret; 725*1249c01aSStefan Metzmacher 726*1249c01aSStefan Metzmacher if (WARN_ON_ONCE(needed < 0)) 727*1249c01aSStefan Metzmacher return -EINVAL; 728*1249c01aSStefan Metzmacher 729*1249c01aSStefan Metzmacher do { 730*1249c01aSStefan Metzmacher if (atomic_sub_return(needed, total_credits) >= 0) 731*1249c01aSStefan Metzmacher return 0; 732*1249c01aSStefan Metzmacher 733*1249c01aSStefan Metzmacher atomic_add(needed, total_credits); 734*1249c01aSStefan Metzmacher ret = wait_event_interruptible(*waitq, 735*1249c01aSStefan Metzmacher atomic_read(total_credits) >= needed || 736*1249c01aSStefan Metzmacher sc->status != expected_status); 737*1249c01aSStefan Metzmacher 738*1249c01aSStefan Metzmacher if (sc->status != expected_status) 739*1249c01aSStefan Metzmacher return unexpected_errno; 740*1249c01aSStefan Metzmacher else if (ret < 0) 741*1249c01aSStefan Metzmacher return ret; 742*1249c01aSStefan Metzmacher } while (true); 743*1249c01aSStefan Metzmacher } 744