From 1b0bb73f72d1b91c872e5c068ee5b46d943accad Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 8 Jan 2018 11:00:40 -0800 Subject: IB/srpt: Remove an unused structure member Fixes: commit a42d985bd5b2 ("ib_srpt: Initial SRP Target merge for v3.3-rc1") Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index bfa576aa9f03..81e8085bc5bb 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1123,7 +1123,6 @@ static struct srpt_send_ioctx *srpt_get_send_ioctx(struct srpt_rdma_ch *ch) ioctx->state = SRPT_STATE_NEW; ioctx->n_rdma = 0; ioctx->n_rw_ctx = 0; - init_completion(&ioctx->tx_done); ioctx->queue_status_only = false; /* * transport_init_se_cmd() does not initialize all fields, so do it -- cgit v1.2.3 From 10eac19bb272415cad6f28ebe8c055b648f334b1 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 8 Jan 2018 11:00:41 -0800 Subject: IB/srpt: Fix kernel-doc warnings in ib_srpt.c Avoid that warnings about missing parameter descriptions are reported when building with W=1. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 205 ++++++++++++++++++++++++---------- 1 file changed, 145 insertions(+), 60 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 81e8085bc5bb..1bcf8b3b6095 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -120,7 +120,9 @@ static bool srpt_set_ch_state(struct srpt_rdma_ch *ch, enum rdma_ch_state new) } /** - * srpt_event_handler() - Asynchronous IB event callback function. + * srpt_event_handler - asynchronous IB event callback function + * @handler: IB event handler registered by ib_register_event_handler(). + * @event: Description of the event that occurred. * * Callback function called by the InfiniBand core when an asynchronous IB * event occurs. This callback may occur in interrupt context. See also @@ -169,7 +171,9 @@ static void srpt_event_handler(struct ib_event_handler *handler, } /** - * srpt_srq_event() - SRQ event callback function. + * srpt_srq_event - SRQ event callback function + * @event: Description of the event that occurred. + * @ctx: Context pointer specified at SRQ creation time. */ static void srpt_srq_event(struct ib_event *event, void *ctx) { @@ -194,7 +198,9 @@ static const char *get_ch_state_name(enum rdma_ch_state s) } /** - * srpt_qp_event() - QP event callback function. + * srpt_qp_event - QP event callback function + * @event: Description of the event that occurred. + * @ch: SRPT RDMA channel. */ static void srpt_qp_event(struct ib_event *event, struct srpt_rdma_ch *ch) { @@ -217,8 +223,8 @@ static void srpt_qp_event(struct ib_event *event, struct srpt_rdma_ch *ch) } /** - * srpt_set_ioc() - Helper function for initializing an IOUnitInfo structure. - * + * srpt_set_ioc - initialize a IOUnitInfo structure + * @c_list: controller list. * @slot: one-based slot number. * @value: four-bit value. * @@ -241,7 +247,8 @@ static void srpt_set_ioc(u8 *c_list, u32 slot, u8 value) } /** - * srpt_get_class_port_info() - Copy ClassPortInfo to a management datagram. + * srpt_get_class_port_info - copy ClassPortInfo to a management datagram + * @mad: Datagram that will be sent as response to DM_ATTR_CLASS_PORT_INFO. * * See also section 16.3.3.1 ClassPortInfo in the InfiniBand Architecture * Specification. @@ -260,7 +267,8 @@ static void srpt_get_class_port_info(struct ib_dm_mad *mad) } /** - * srpt_get_iou() - Write IOUnitInfo to a management datagram. + * srpt_get_iou - write IOUnitInfo to a management datagram + * @mad: Datagram that will be sent as response to DM_ATTR_IOU_INFO. * * See also section 16.3.3.3 IOUnitInfo in the InfiniBand Architecture * Specification. See also section B.7, table B.6 in the SRP r16a document. @@ -284,7 +292,10 @@ static void srpt_get_iou(struct ib_dm_mad *mad) } /** - * srpt_get_ioc() - Write IOControllerprofile to a management datagram. + * srpt_get_ioc - write IOControllerprofile to a management datagram + * @sport: HCA port through which the MAD has been received. + * @slot: Slot number specified in DM_ATTR_IOC_PROFILE query. + * @mad: Datagram that will be sent as response to DM_ATTR_IOC_PROFILE. * * See also section 16.3.3.4 IOControllerProfile in the InfiniBand * Architecture Specification. See also section B.7, table B.7 in the SRP @@ -342,7 +353,12 @@ static void srpt_get_ioc(struct srpt_port *sport, u32 slot, } /** - * srpt_get_svc_entries() - Write ServiceEntries to a management datagram. + * srpt_get_svc_entries - write ServiceEntries to a management datagram + * @ioc_guid: I/O controller GUID to use in reply. + * @slot: I/O controller number. + * @hi: End of the range of service entries to be specified in the reply. + * @lo: Start of the range of service entries to be specified in the reply.. + * @mad: Datagram that will be sent as response to DM_ATTR_SVC_ENTRIES. * * See also section 16.3.3.5 ServiceEntries in the InfiniBand Architecture * Specification. See also section B.7, table B.8 in the SRP r16a document. @@ -379,8 +395,8 @@ static void srpt_get_svc_entries(u64 ioc_guid, } /** - * srpt_mgmt_method_get() - Process a received management datagram. - * @sp: source port through which the MAD has been received. + * srpt_mgmt_method_get - process a received management datagram + * @sp: HCA port through which the MAD has been received. * @rq_mad: received MAD. * @rsp_mad: response MAD. */ @@ -419,7 +435,9 @@ static void srpt_mgmt_method_get(struct srpt_port *sp, struct ib_mad *rq_mad, } /** - * srpt_mad_send_handler() - Post MAD-send callback function. + * srpt_mad_send_handler - MAD send completion callback + * @mad_agent: Return value of ib_register_mad_agent(). + * @mad_wc: Work completion reporting that the MAD has been sent. */ static void srpt_mad_send_handler(struct ib_mad_agent *mad_agent, struct ib_mad_send_wc *mad_wc) @@ -429,7 +447,10 @@ static void srpt_mad_send_handler(struct ib_mad_agent *mad_agent, } /** - * srpt_mad_recv_handler() - MAD reception callback function. + * srpt_mad_recv_handler - MAD reception callback function + * @mad_agent: Return value of ib_register_mad_agent(). + * @send_buf: Not used. + * @mad_wc: Work completion reporting that a MAD has been received. */ static void srpt_mad_recv_handler(struct ib_mad_agent *mad_agent, struct ib_mad_send_buf *send_buf, @@ -494,7 +515,8 @@ err: } /** - * srpt_refresh_port() - Configure a HCA port. + * srpt_refresh_port - configure a HCA port + * @sport: SRPT HCA port. * * Enable InfiniBand management datagram processing, update the cached sm_lid, * lid and gid values, and register a callback function for processing MADs @@ -577,7 +599,8 @@ err_mod_port: } /** - * srpt_unregister_mad_agent() - Unregister MAD callback functions. + * srpt_unregister_mad_agent - unregister MAD callback functions + * @sdev: SRPT HCA pointer. * * Note: It is safe to call this function more than once for the same device. */ @@ -602,7 +625,11 @@ static void srpt_unregister_mad_agent(struct srpt_device *sdev) } /** - * srpt_alloc_ioctx() - Allocate an SRPT I/O context structure. + * srpt_alloc_ioctx - allocate a SRPT I/O context structure + * @sdev: SRPT HCA pointer. + * @ioctx_size: I/O context size. + * @dma_size: Size of I/O context DMA buffer. + * @dir: DMA data direction. */ static struct srpt_ioctx *srpt_alloc_ioctx(struct srpt_device *sdev, int ioctx_size, int dma_size, @@ -633,7 +660,11 @@ err: } /** - * srpt_free_ioctx() - Free an SRPT I/O context structure. + * srpt_free_ioctx - free a SRPT I/O context structure + * @sdev: SRPT HCA pointer. + * @ioctx: I/O context pointer. + * @dma_size: Size of I/O context DMA buffer. + * @dir: DMA data direction. */ static void srpt_free_ioctx(struct srpt_device *sdev, struct srpt_ioctx *ioctx, int dma_size, enum dma_data_direction dir) @@ -647,7 +678,7 @@ static void srpt_free_ioctx(struct srpt_device *sdev, struct srpt_ioctx *ioctx, } /** - * srpt_alloc_ioctx_ring() - Allocate a ring of SRPT I/O context structures. + * srpt_alloc_ioctx_ring - allocate a ring of SRPT I/O context structures * @sdev: Device to allocate the I/O context ring for. * @ring_size: Number of elements in the I/O context ring. * @ioctx_size: I/O context size. @@ -685,7 +716,12 @@ out: } /** - * srpt_free_ioctx_ring() - Free the ring of SRPT I/O context structures. + * srpt_free_ioctx_ring - free the ring of SRPT I/O context structures + * @ioctx_ring: I/O context ring to be freed. + * @sdev: SRPT HCA pointer. + * @ring_size: Number of ring elements. + * @dma_size: Size of I/O context DMA buffer. + * @dir: DMA data direction. */ static void srpt_free_ioctx_ring(struct srpt_ioctx **ioctx_ring, struct srpt_device *sdev, int ring_size, @@ -702,7 +738,8 @@ static void srpt_free_ioctx_ring(struct srpt_ioctx **ioctx_ring, } /** - * srpt_get_cmd_state() - Get the state of a SCSI command. + * srpt_get_cmd_state - get the state of a SCSI command + * @ioctx: Send I/O context. */ static enum srpt_command_state srpt_get_cmd_state(struct srpt_send_ioctx *ioctx) { @@ -718,7 +755,9 @@ static enum srpt_command_state srpt_get_cmd_state(struct srpt_send_ioctx *ioctx) } /** - * srpt_set_cmd_state() - Set the state of a SCSI command. + * srpt_set_cmd_state - set the state of a SCSI command + * @ioctx: Send I/O context. + * @new: New I/O context state. * * Does not modify the state of aborted commands. Returns the previous command * state. @@ -741,7 +780,10 @@ static enum srpt_command_state srpt_set_cmd_state(struct srpt_send_ioctx *ioctx, } /** - * srpt_test_and_set_cmd_state() - Test and set the state of a command. + * srpt_test_and_set_cmd_state - test and set the state of a command + * @ioctx: Send I/O context. + * @old: Current I/O context state. + * @new: New I/O context state. * * Returns true if and only if the previous command state was equal to 'old'. */ @@ -765,7 +807,10 @@ static bool srpt_test_and_set_cmd_state(struct srpt_send_ioctx *ioctx, } /** - * srpt_post_recv() - Post an IB receive request. + * srpt_post_recv - post an IB receive request + * @sdev: SRPT HCA pointer. + * @ch: SRPT RDMA channel. + * @ioctx: Receive I/O context pointer. */ static int srpt_post_recv(struct srpt_device *sdev, struct srpt_rdma_ch *ch, struct srpt_recv_ioctx *ioctx) @@ -791,7 +836,8 @@ static int srpt_post_recv(struct srpt_device *sdev, struct srpt_rdma_ch *ch, } /** - * srpt_zerolength_write() - Perform a zero-length RDMA write. + * srpt_zerolength_write - perform a zero-length RDMA write + * @ch: SRPT RDMA channel. * * A quote from the InfiniBand specification: C9-88: For an HCA responder * using Reliable Connection service, for each zero-length RDMA READ or WRITE @@ -928,11 +974,13 @@ static inline void *srpt_get_desc_buf(struct srp_cmd *srp_cmd) } /** - * srpt_get_desc_tbl() - Parse the data descriptors of an SRP_CMD request. + * srpt_get_desc_tbl - parse the data descriptors of a SRP_CMD request * @ioctx: Pointer to the I/O context associated with the request. * @srp_cmd: Pointer to the SRP_CMD request data. * @dir: Pointer to the variable to which the transfer direction will be * written. + * @sg: [out] scatterlist allocated for the parsed SRP_CMD. + * @sg_cnt: [out] length of @sg. * @data_len: Pointer to the variable to which the total data length of all * descriptors in the SRP_CMD request will be written. * @@ -998,7 +1046,9 @@ static int srpt_get_desc_tbl(struct srpt_send_ioctx *ioctx, } /** - * srpt_init_ch_qp() - Initialize queue pair attributes. + * srpt_init_ch_qp - initialize queue pair attributes + * @ch: SRPT RDMA channel. + * @qp: Queue pair pointer. * * Initialized the attributes of queue pair 'qp' by allowing local write, * remote read and remote write. Also transitions 'qp' to state IB_QPS_INIT. @@ -1026,7 +1076,7 @@ static int srpt_init_ch_qp(struct srpt_rdma_ch *ch, struct ib_qp *qp) } /** - * srpt_ch_qp_rtr() - Change the state of a channel to 'ready to receive' (RTR). + * srpt_ch_qp_rtr - change the state of a channel to 'ready to receive' (RTR) * @ch: channel of the queue pair. * @qp: queue pair to change the state of. * @@ -1056,7 +1106,7 @@ out: } /** - * srpt_ch_qp_rts() - Change the state of a channel to 'ready to send' (RTS). + * srpt_ch_qp_rts - change the state of a channel to 'ready to send' (RTS) * @ch: channel of the queue pair. * @qp: queue pair to change the state of. * @@ -1086,7 +1136,8 @@ out: } /** - * srpt_ch_qp_err() - Set the channel queue pair state to 'error'. + * srpt_ch_qp_err - set the channel queue pair state to 'error' + * @ch: SRPT RDMA channel. */ static int srpt_ch_qp_err(struct srpt_rdma_ch *ch) { @@ -1097,7 +1148,8 @@ static int srpt_ch_qp_err(struct srpt_rdma_ch *ch) } /** - * srpt_get_send_ioctx() - Obtain an I/O context for sending to the initiator. + * srpt_get_send_ioctx - obtain an I/O context for sending to the initiator + * @ch: SRPT RDMA channel. */ static struct srpt_send_ioctx *srpt_get_send_ioctx(struct srpt_rdma_ch *ch) { @@ -1135,9 +1187,8 @@ static struct srpt_send_ioctx *srpt_get_send_ioctx(struct srpt_rdma_ch *ch) } /** - * srpt_abort_cmd() - Abort a SCSI command. + * srpt_abort_cmd - abort a SCSI command * @ioctx: I/O context associated with the SCSI command. - * @context: Preferred execution context. */ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx) { @@ -1205,6 +1256,10 @@ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx) } /** + * srpt_rdma_read_done - RDMA read completion callback + * @cq: Completion queue. + * @wc: Work completion. + * * XXX: what is now target_execute_cmd used to be asynchronous, and unmapping * the data that has been transferred via IB RDMA had to be postponed until the * check_stop_free() callback. None of this is necessary anymore and needs to @@ -1236,7 +1291,7 @@ static void srpt_rdma_read_done(struct ib_cq *cq, struct ib_wc *wc) } /** - * srpt_build_cmd_rsp() - Build an SRP_RSP response. + * srpt_build_cmd_rsp - build a SRP_RSP response * @ch: RDMA channel through which the request has been received. * @ioctx: I/O context associated with the SRP_CMD request. The response will * be built in the buffer ioctx->buf points at and hence this function will @@ -1296,7 +1351,7 @@ static int srpt_build_cmd_rsp(struct srpt_rdma_ch *ch, } /** - * srpt_build_tskmgmt_rsp() - Build a task management response. + * srpt_build_tskmgmt_rsp - build a task management response * @ch: RDMA channel through which the request has been received. * @ioctx: I/O context in which the SRP_RSP response will be built. * @rsp_code: RSP_CODE that will be stored in the response. @@ -1344,7 +1399,10 @@ static int srpt_check_stop_free(struct se_cmd *cmd) } /** - * srpt_handle_cmd() - Process SRP_CMD. + * srpt_handle_cmd - process a SRP_CMD information unit + * @ch: SRPT RDMA channel. + * @recv_ioctx: Receive I/O context. + * @send_ioctx: Send I/O context. */ static void srpt_handle_cmd(struct srpt_rdma_ch *ch, struct srpt_recv_ioctx *recv_ioctx, @@ -1426,7 +1484,10 @@ static int srp_tmr_to_tcm(int fn) } /** - * srpt_handle_tsk_mgmt() - Process an SRP_TSK_MGMT information unit. + * srpt_handle_tsk_mgmt - process a SRP_TSK_MGMT information unit + * @ch: SRPT RDMA channel. + * @recv_ioctx: Receive I/O context. + * @send_ioctx: Send I/O context. * * Returns 0 if and only if the request will be processed by the target core. * @@ -1469,9 +1530,10 @@ fail: } /** - * srpt_handle_new_iu() - Process a newly received information unit. + * srpt_handle_new_iu - process a newly received information unit * @ch: RDMA channel through which the information unit has been received. - * @ioctx: SRPT I/O context associated with the information unit. + * @recv_ioctx: Receive I/O context associated with the information unit. + * @send_ioctx: Send I/O context. */ static void srpt_handle_new_iu(struct srpt_rdma_ch *ch, struct srpt_recv_ioctx *recv_ioctx, @@ -1577,6 +1639,10 @@ static void srpt_process_wait_list(struct srpt_rdma_ch *ch) } /** + * srpt_send_done - send completion callback + * @cq: Completion queue. + * @wc: Work completion. + * * Note: Although this has not yet been observed during tests, at least in * theory it is possible that the srpt_get_send_ioctx() call invoked by * srpt_handle_new_iu() fails. This is possible because the req_lim_delta @@ -1618,7 +1684,8 @@ static void srpt_send_done(struct ib_cq *cq, struct ib_wc *wc) } /** - * srpt_create_ch_ib() - Create receive and send completion queues. + * srpt_create_ch_ib - create receive and send completion queues + * @ch: SRPT RDMA channel. */ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch) { @@ -1717,7 +1784,8 @@ static void srpt_destroy_ch_ib(struct srpt_rdma_ch *ch) } /** - * srpt_close_ch() - Close an RDMA channel. + * srpt_close_ch - close a RDMA channel + * @ch: SRPT RDMA channel. * * Make sure all resources associated with the channel will be deallocated at * an appropriate time. @@ -1900,7 +1968,10 @@ static void srpt_release_channel_work(struct work_struct *w) } /** - * srpt_cm_req_recv() - Process the event IB_CM_REQ_RECEIVED. + * srpt_cm_req_recv - process the event IB_CM_REQ_RECEIVED + * @cm_id: IB/CM connection identifier. + * @param: IB/CM REQ parameters. + * @private_data: IB/CM REQ private data. * * Ownership of the cm_id is transferred to the target session if this * functions returns zero. Otherwise the caller remains the owner of cm_id. @@ -2205,7 +2276,8 @@ static void srpt_cm_rej_recv(struct srpt_rdma_ch *ch, } /** - * srpt_cm_rtu_recv() - Process an IB_CM_RTU_RECEIVED or USER_ESTABLISHED event. + * srpt_cm_rtu_recv - process an IB_CM_RTU_RECEIVED or USER_ESTABLISHED event + * @ch: SRPT RDMA channel. * * An IB_CM_RTU_RECEIVED message indicates that the connection is established * and that the recipient may begin transmitting (RTU = ready to use). @@ -2228,7 +2300,9 @@ static void srpt_cm_rtu_recv(struct srpt_rdma_ch *ch) } /** - * srpt_cm_handler() - IB connection manager callback function. + * srpt_cm_handler - IB connection manager callback function + * @cm_id: IB/CM connection identifier. + * @event: IB/CM event. * * A non-zero return value will cause the caller destroy the CM ID. * @@ -2297,7 +2371,7 @@ static int srpt_write_pending_status(struct se_cmd *se_cmd) } /* - * srpt_write_pending() - Start data transfer from initiator to target (write). + * srpt_write_pending - Start data transfer from initiator to target (write). */ static int srpt_write_pending(struct se_cmd *se_cmd) { @@ -2354,7 +2428,8 @@ static u8 tcm_to_srp_tsk_mgmt_status(const int tcm_mgmt_status) } /** - * srpt_queue_response() - Transmits the response to a SCSI command. + * srpt_queue_response - transmit the response to a SCSI command + * @cmd: SCSI target command. * * Callback function called by the TCM core. Must not block since it can be * invoked on the context of the IB completion handler. @@ -2494,7 +2569,8 @@ static void srpt_refresh_port_work(struct work_struct *work) } /** - * srpt_release_sdev() - Free the channel resources associated with a target. + * srpt_release_sdev - disable login and wait for associated channels + * @sdev: SRPT HCA pointer. */ static int srpt_release_sdev(struct srpt_device *sdev) { @@ -2622,7 +2698,8 @@ static int srpt_use_srq(struct srpt_device *sdev, bool use_srq) } /** - * srpt_add_one() - Infiniband device addition callback function. + * srpt_add_one - InfiniBand device addition callback function + * @device: Describes a HCA. */ static void srpt_add_one(struct ib_device *device) { @@ -2720,7 +2797,9 @@ err: } /** - * srpt_remove_one() - InfiniBand device removal callback function. + * srpt_remove_one - InfiniBand device removal callback function + * @device: Describes a HCA. + * @client_data: The value passed as the third argument to ib_set_client_data(). */ static void srpt_remove_one(struct ib_device *device, void *client_data) { @@ -2826,7 +2905,8 @@ static void srpt_release_cmd(struct se_cmd *se_cmd) } /** - * srpt_close_session() - Forcibly close a session. + * srpt_close_session - forcibly close a session + * @se_sess: SCSI target session. * * Callback function invoked by the TCM core to clean up sessions associated * with a node ACL when the user invokes @@ -2843,7 +2923,8 @@ static void srpt_close_session(struct se_session *se_sess) } /** - * srpt_sess_get_index() - Return the value of scsiAttIntrPortIndex (SCSI-MIB). + * srpt_sess_get_index - return the value of scsiAttIntrPortIndex (SCSI-MIB) + * @se_sess: SCSI target session. * * A quote from RFC 4455 (SCSI-MIB) about this MIB object: * This object represents an arbitrary integer used to uniquely identify a @@ -2882,7 +2963,7 @@ out: } /** - * srpt_parse_i_port_id() - Parse an initiator port ID. + * srpt_parse_i_port_id - parse an initiator port ID * @name: ASCII representation of a 128-bit initiator port ID. * @i_port_id: Binary 128-bit port ID. */ @@ -3133,8 +3214,10 @@ static struct configfs_attribute *srpt_tpg_attrs[] = { }; /** - * configfs callback invoked for - * mkdir /sys/kernel/config/target/$driver/$port/$tpg + * srpt_make_tpg - configfs callback invoked for mkdir /sys/kernel/config/target/$driver/$port/$tpg + * @wwn: Corresponds to $driver/$port. + * @group: Not used. + * @name: $tpg. */ static struct se_portal_group *srpt_make_tpg(struct se_wwn *wwn, struct config_group *group, @@ -3156,8 +3239,8 @@ static struct se_portal_group *srpt_make_tpg(struct se_wwn *wwn, } /** - * configfs callback invoked for - * rmdir /sys/kernel/config/target/$driver/$port/$tpg + * srpt_drop_tpg - configfs callback invoked for rmdir /sys/kernel/config/target/$driver/$port/$tpg + * @tpg: Target portal group to deregister. */ static void srpt_drop_tpg(struct se_portal_group *tpg) { @@ -3168,8 +3251,10 @@ static void srpt_drop_tpg(struct se_portal_group *tpg) } /** - * configfs callback invoked for - * mkdir /sys/kernel/config/target/$driver/$port + * srpt_make_tport - configfs callback invoked for mkdir /sys/kernel/config/target/$driver/$port + * @tf: Not used. + * @group: Not used. + * @name: $port. */ static struct se_wwn *srpt_make_tport(struct target_fabric_configfs *tf, struct config_group *group, @@ -3179,8 +3264,8 @@ static struct se_wwn *srpt_make_tport(struct target_fabric_configfs *tf, } /** - * configfs callback invoked for - * rmdir /sys/kernel/config/target/$driver/$port + * srpt_drop_tport - configfs callback invoked for rmdir /sys/kernel/config/target/$driver/$port + * @wwn: $port. */ static void srpt_drop_tport(struct se_wwn *wwn) { @@ -3238,7 +3323,7 @@ static const struct target_core_fabric_ops srpt_template = { }; /** - * srpt_init_module() - Kernel module initialization. + * srpt_init_module - kernel module initialization * * Note: Since ib_register_client() registers callback functions, and since at * least one of these callback functions (srpt_add_one()) calls target core -- cgit v1.2.3 From ed262287e2b46927905a41e86100a63dc2327dac Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 8 Jan 2018 11:00:43 -0800 Subject: IB/srpt: Rename a local variable, a member variable and a constant Rename rsp_size into max_rsp_size and SRPT_RQ_SIZE into MAX_SRPT_RQ_SIZE. The new names better reflect the role of this member variable and constant. Since the prefix "srp_" is superfluous in the context of the function that creates an RDMA channel, rename srp_sq_size into sq_size. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 26 +++++++++++++------------- drivers/infiniband/ulp/srpt/ib_srpt.h | 6 +++--- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 1bcf8b3b6095..4fb884c070af 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -325,7 +325,7 @@ static void srpt_get_ioc(struct srpt_port *sport, u32 slot, if (sdev->use_srq) send_queue_depth = sdev->srq_size; else - send_queue_depth = min(SRPT_RQ_SIZE, + send_queue_depth = min(MAX_SRPT_RQ_SIZE, sdev->device->attrs.max_qp_wr); memset(iocp, 0, sizeof(*iocp)); @@ -1693,7 +1693,7 @@ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch) struct srpt_port *sport = ch->sport; struct srpt_device *sdev = sport->sdev; const struct ib_device_attr *attrs = &sdev->device->attrs; - u32 srp_sq_size = sport->port_attrib.srp_sq_size; + int sq_size = sport->port_attrib.srp_sq_size; int i, ret; WARN_ON(ch->rq_size < 1); @@ -1704,12 +1704,12 @@ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch) goto out; retry: - ch->cq = ib_alloc_cq(sdev->device, ch, ch->rq_size + srp_sq_size, + ch->cq = ib_alloc_cq(sdev->device, ch, ch->rq_size + sq_size, 0 /* XXX: spread CQs */, IB_POLL_WORKQUEUE); if (IS_ERR(ch->cq)) { ret = PTR_ERR(ch->cq); pr_err("failed to create CQ cqe= %d ret= %d\n", - ch->rq_size + srp_sq_size, ret); + ch->rq_size + sq_size, ret); goto out; } @@ -1727,8 +1727,8 @@ retry: * both both, as RDMA contexts will also post completions for the * RDMA READ case. */ - qp_init->cap.max_send_wr = min(srp_sq_size / 2, attrs->max_qp_wr + 0U); - qp_init->cap.max_rdma_ctxs = srp_sq_size / 2; + qp_init->cap.max_send_wr = min(sq_size / 2, attrs->max_qp_wr); + qp_init->cap.max_rdma_ctxs = sq_size / 2; qp_init->cap.max_send_sge = min(attrs->max_sge, SRPT_MAX_SG_PER_WQE); qp_init->port_num = ch->sport->port; if (sdev->use_srq) { @@ -1742,8 +1742,8 @@ retry: if (IS_ERR(ch->qp)) { ret = PTR_ERR(ch->qp); if (ret == -ENOMEM) { - srp_sq_size /= 2; - if (srp_sq_size >= MIN_SRPT_SQ_SIZE) { + sq_size /= 2; + if (sq_size >= MIN_SRPT_SQ_SIZE) { ib_destroy_cq(ch->cq); goto retry; } @@ -1950,7 +1950,7 @@ static void srpt_release_channel_work(struct work_struct *w) srpt_free_ioctx_ring((struct srpt_ioctx **)ch->ioctx_ring, ch->sport->sdev, ch->rq_size, - ch->rsp_size, DMA_TO_DEVICE); + ch->max_rsp_size, DMA_TO_DEVICE); srpt_free_ioctx_ring((struct srpt_ioctx **)ch->ioctx_recv_ring, sdev, ch->rq_size, @@ -2098,16 +2098,16 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, * depth to avoid that the initiator driver has to report QUEUE_FULL * to the SCSI mid-layer. */ - ch->rq_size = min(SRPT_RQ_SIZE, sdev->device->attrs.max_qp_wr); + ch->rq_size = min(MAX_SRPT_RQ_SIZE, sdev->device->attrs.max_qp_wr); spin_lock_init(&ch->spinlock); ch->state = CH_CONNECTING; INIT_LIST_HEAD(&ch->cmd_wait_list); - ch->rsp_size = ch->sport->port_attrib.srp_max_rsp_size; + ch->max_rsp_size = ch->sport->port_attrib.srp_max_rsp_size; ch->ioctx_ring = (struct srpt_send_ioctx **) srpt_alloc_ioctx_ring(ch->sport->sdev, ch->rq_size, sizeof(*ch->ioctx_ring[0]), - ch->rsp_size, DMA_TO_DEVICE); + ch->max_rsp_size, DMA_TO_DEVICE); if (!ch->ioctx_ring) goto free_ch; @@ -2235,7 +2235,7 @@ free_recv_ring: free_ring: srpt_free_ioctx_ring((struct srpt_ioctx **)ch->ioctx_ring, ch->sport->sdev, ch->rq_size, - ch->rsp_size, DMA_TO_DEVICE); + ch->max_rsp_size, DMA_TO_DEVICE); free_ch: kfree(ch); diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 0c94cd6a7e9d..8f90a7ca98e6 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -114,7 +114,7 @@ enum { MIN_SRPT_SQ_SIZE = 16, DEF_SRPT_SQ_SIZE = 4096, - SRPT_RQ_SIZE = 128, + MAX_SRPT_RQ_SIZE = 128, MIN_SRPT_SRQ_SIZE = 4, DEFAULT_SRPT_SRQ_SIZE = 4095, MAX_SRPT_SRQ_SIZE = 65535, @@ -248,7 +248,7 @@ enum rdma_ch_state { * @zw_cqe: Zero-length write CQE. * @kref: kref for this channel. * @rq_size: IB receive queue size. - * @rsp_size: IB response message size in bytes. + * @max_rsp_size: Maximum size of an RSP response message in bytes. * @sq_wr_avail: number of work requests available in the send queue. * @sport: pointer to the information of the HCA port used by this * channel. @@ -280,7 +280,7 @@ struct srpt_rdma_ch { struct ib_cqe zw_cqe; struct kref kref; int rq_size; - u32 rsp_size; + u32 max_rsp_size; atomic_t sq_wr_avail; struct srpt_port *sport; u8 i_port_id[16]; -- cgit v1.2.3 From d9f45ae69ff14e672c9b1d8cb42383d4cc2a6878 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 8 Jan 2018 11:00:44 -0800 Subject: IB/srpt: Reduce the severity level of a log message Since the SRQ event message is only useful for debugging purposes, reduce its severity from "informational" to "debug". Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 4fb884c070af..a71664fe939b 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -177,7 +177,7 @@ static void srpt_event_handler(struct ib_event_handler *handler, */ static void srpt_srq_event(struct ib_event *event, void *ctx) { - pr_info("SRQ event %d\n", event->event); + pr_debug("SRQ event %d\n", event->event); } static const char *get_ch_state_name(enum rdma_ch_state s) -- cgit v1.2.3 From 5f1141b165cc0c7dc1be9143461127dd856615da Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 8 Jan 2018 11:00:45 -0800 Subject: IB/srpt: Verify port numbers in srpt_event_handler() Verify whether port numbers are in the expected range before using these as an array index. Complain if a port number is out of range. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index a71664fe939b..c5efe0afa2c8 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -134,6 +134,7 @@ static void srpt_event_handler(struct ib_event_handler *handler, { struct srpt_device *sdev; struct srpt_port *sport; + u8 port_num; sdev = ib_get_client_data(event->device, &srpt_client); if (!sdev || sdev->device != event->device) @@ -144,10 +145,15 @@ static void srpt_event_handler(struct ib_event_handler *handler, switch (event->event) { case IB_EVENT_PORT_ERR: - if (event->element.port_num <= sdev->device->phys_port_cnt) { - sport = &sdev->port[event->element.port_num - 1]; + port_num = event->element.port_num - 1; + if (port_num < sdev->device->phys_port_cnt) { + sport = &sdev->port[port_num]; sport->lid = 0; sport->sm_lid = 0; + } else { + WARN(true, "event %d: port_num %d out of range 1..%d\n", + event->event, port_num + 1, + sdev->device->phys_port_cnt); } break; case IB_EVENT_PORT_ACTIVE: @@ -157,15 +163,19 @@ static void srpt_event_handler(struct ib_event_handler *handler, case IB_EVENT_CLIENT_REREGISTER: case IB_EVENT_GID_CHANGE: /* Refresh port data asynchronously. */ - if (event->element.port_num <= sdev->device->phys_port_cnt) { - sport = &sdev->port[event->element.port_num - 1]; + port_num = event->element.port_num - 1; + if (port_num < sdev->device->phys_port_cnt) { + sport = &sdev->port[port_num]; if (!sport->lid && !sport->sm_lid) schedule_work(&sport->work); + } else { + WARN(true, "event %d: port_num %d out of range 1..%d\n", + event->event, port_num + 1, + sdev->device->phys_port_cnt); } break; default: - pr_err("received unrecognized IB event %d\n", - event->event); + pr_err("received unrecognized IB event %d\n", event->event); break; } } -- cgit v1.2.3 From b185d3f895632f1091513405ce80a9455cb5bf30 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 8 Jan 2018 11:00:46 -0800 Subject: IB/srpt: Use the IPv6 format for GIDs in log messages Make the ib_srpt driver use the IPv6 format for GIDs in log messages to improve consistency of this driver with other RDMA kernel drivers. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index c5efe0afa2c8..25c5e188c740 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -2010,17 +2010,9 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, it_iu_len = be32_to_cpu(req->req_it_iu_len); - pr_info("Received SRP_LOGIN_REQ with i_port_id 0x%llx:0x%llx," - " t_port_id 0x%llx:0x%llx and it_iu_len %d on port %d" - " (guid=0x%llx:0x%llx)\n", - be64_to_cpu(*(__be64 *)&req->initiator_port_id[0]), - be64_to_cpu(*(__be64 *)&req->initiator_port_id[8]), - be64_to_cpu(*(__be64 *)&req->target_port_id[0]), - be64_to_cpu(*(__be64 *)&req->target_port_id[8]), - it_iu_len, - param->port, - be64_to_cpu(*(__be64 *)&sdev->port[param->port - 1].gid.raw[0]), - be64_to_cpu(*(__be64 *)&sdev->port[param->port - 1].gid.raw[8])); + pr_info("Received SRP_LOGIN_REQ with i_port_id %pI6, t_port_id %pI6 and it_iu_len %d on port %d (guid=%pI6)\n", + req->initiator_port_id, req->target_port_id, it_iu_len, + param->port, &sport->gid); rsp = kzalloc(sizeof(*rsp), GFP_KERNEL); rej = kzalloc(sizeof(*rej), GFP_KERNEL); -- cgit v1.2.3 From ea51d2e12aac9205291b0ec88ffb7d33da7eafb5 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 8 Jan 2018 11:00:47 -0800 Subject: IB/srpt: Convert a warning into a debug message At least when running the ib_srpt driver on top of the rdma_rxe driver it is easy to trigger a zero-length write completion in the CH_DISCONNECTED state. Hence make the message that reports this less noisy. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 25c5e188c740..31b6f108dffb 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -875,7 +875,8 @@ static void srpt_zerolength_write_done(struct ib_cq *cq, struct ib_wc *wc) if (srpt_set_ch_state(ch, CH_DISCONNECTED)) schedule_work(&ch->release_work); else - WARN_ONCE(1, "%s-%d\n", ch->sess_name, ch->qp->qp_num); + pr_debug("%s-%d: already disconnected.\n", + ch->sess_name, ch->qp->qp_num); } } -- cgit v1.2.3 From 3fa7f0e99446f1179cbb2742e5bc4db097ad78b5 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 8 Jan 2018 11:00:48 -0800 Subject: IB/srpt: Reduce frequency of receive failure messages Disabling an SRP target port causes the state of all QPs associated with a port to be changed into IB_QPS_ERR. Avoid that this causes one error message per I/O context to be reported. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 31b6f108dffb..6f5a4d66eacc 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1622,8 +1622,8 @@ static void srpt_recv_done(struct ib_cq *cq, struct ib_wc *wc) pr_err("req_lim = %d < 0\n", req_lim); srpt_handle_new_iu(ch, ioctx, NULL); } else { - pr_info("receiving failed for ioctx %p with status %d\n", - ioctx, wc->status); + pr_info_ratelimited("receiving failed for ioctx %p with status %d\n", + ioctx, wc->status); } } -- cgit v1.2.3 From b14cb74479a2606b0052cc909727938953a939ac Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 8 Jan 2018 11:00:49 -0800 Subject: IB/srpt: Introduce srpt_format_guid() Introduce a function for converting a GUID into an ASCII string. This patch does not change any functionality. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 6f5a4d66eacc..e4c1446699a9 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -524,6 +524,15 @@ err: ib_free_recv_mad(mad_wc); } +static int srpt_format_guid(char *buf, unsigned int size, const __be64 *guid) +{ + const __be16 *g = (const __be16 *)guid; + + return snprintf(buf, size, "%04x:%04x:%04x:%04x", + be16_to_cpu(g[0]), be16_to_cpu(g[1]), + be16_to_cpu(g[2]), be16_to_cpu(g[3])); +} + /** * srpt_refresh_port - configure a HCA port * @sport: SRPT HCA port. @@ -539,7 +548,6 @@ static int srpt_refresh_port(struct srpt_port *sport) struct ib_mad_reg_req reg_req; struct ib_port_modify port_modify; struct ib_port_attr port_attr; - __be16 *guid; int ret; memset(&port_modify, 0, sizeof(port_modify)); @@ -563,11 +571,8 @@ static int srpt_refresh_port(struct srpt_port *sport) goto err_query_port; sport->port_guid_wwn.priv = sport; - guid = (__be16 *)&sport->gid.global.interface_id; - snprintf(sport->port_guid, sizeof(sport->port_guid), - "%04x:%04x:%04x:%04x", - be16_to_cpu(guid[0]), be16_to_cpu(guid[1]), - be16_to_cpu(guid[2]), be16_to_cpu(guid[3])); + srpt_format_guid(sport->port_guid, sizeof(sport->port_guid), + &sport->gid.global.interface_id); sport->port_gid_wwn.priv = sport; snprintf(sport->port_gid, sizeof(sport->port_gid), "0x%016llx%016llx", @@ -1998,7 +2003,6 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, struct srp_login_rej *rej; struct ib_cm_rep_param *rep_param; struct srpt_rdma_ch *ch, *tmp_ch; - __be16 *guid; u32 it_iu_len; int i, ret = 0; @@ -2150,10 +2154,8 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, goto destroy_ib; } - guid = (__be16 *)¶m->primary_path->dgid.global.interface_id; - snprintf(ch->ini_guid, sizeof(ch->ini_guid), "%04x:%04x:%04x:%04x", - be16_to_cpu(guid[0]), be16_to_cpu(guid[1]), - be16_to_cpu(guid[2]), be16_to_cpu(guid[3])); + srpt_format_guid(ch->ini_guid, sizeof(ch->ini_guid), + ¶m->primary_path->dgid.global.interface_id); snprintf(ch->sess_name, sizeof(ch->sess_name), "0x%016llx%016llx", be64_to_cpu(*(__be64 *)ch->i_port_id), be64_to_cpu(*(__be64 *)(ch->i_port_id + 8))); -- cgit v1.2.3 From dd3bec8655d6f760540afd2261ca7ae9b6888cb0 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 8 Jan 2018 11:00:50 -0800 Subject: IB/srpt: Inline srpt_get_cmd_state() It is not necessary to obtain ioctx->spinlock when reading the ioctx state. Since after removal of this locking only a single line remains, inline the srpt_get_cmd_state() function. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index e4c1446699a9..d2835b0c15e8 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -752,23 +752,6 @@ static void srpt_free_ioctx_ring(struct srpt_ioctx **ioctx_ring, kfree(ioctx_ring); } -/** - * srpt_get_cmd_state - get the state of a SCSI command - * @ioctx: Send I/O context. - */ -static enum srpt_command_state srpt_get_cmd_state(struct srpt_send_ioctx *ioctx) -{ - enum srpt_command_state state; - unsigned long flags; - - BUG_ON(!ioctx); - - spin_lock_irqsave(&ioctx->spinlock, flags); - state = ioctx->state; - spin_unlock_irqrestore(&ioctx->spinlock, flags); - return state; -} - /** * srpt_set_cmd_state - set the state of a SCSI command * @ioctx: Send I/O context. @@ -1303,7 +1286,7 @@ static void srpt_rdma_read_done(struct ib_cq *cq, struct ib_wc *wc) target_execute_cmd(&ioctx->cmd); else pr_err("%s[%d]: wrong state = %d\n", __func__, - __LINE__, srpt_get_cmd_state(ioctx)); + __LINE__, ioctx->state); } /** @@ -2372,7 +2355,7 @@ static int srpt_write_pending_status(struct se_cmd *se_cmd) struct srpt_send_ioctx *ioctx; ioctx = container_of(se_cmd, struct srpt_send_ioctx, cmd); - return srpt_get_cmd_state(ioctx) == SRPT_STATE_NEED_DATA; + return ioctx->state == SRPT_STATE_NEED_DATA; } /* @@ -2951,7 +2934,7 @@ static int srpt_get_tcm_cmd_state(struct se_cmd *se_cmd) struct srpt_send_ioctx *ioctx; ioctx = container_of(se_cmd, struct srpt_send_ioctx, cmd); - return srpt_get_cmd_state(ioctx); + return ioctx->state; } static int srpt_parse_guid(u64 *guid, const char *name) -- cgit v1.2.3 From 2d67017cc78f1607bac5347ce0c5258734796faf Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 8 Jan 2018 11:00:51 -0800 Subject: IB/srpt: Micro-optimize I/O context state manipulation Since all I/O context state changes are already serialized, it is not necessary to protect I/O context state changes with the I/O context spinlock. Hence remove that spinlock. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 16 +--------------- drivers/infiniband/ulp/srpt/ib_srpt.h | 2 -- 2 files changed, 1 insertion(+), 17 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index d2835b0c15e8..d78f60dcc2ba 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -764,15 +764,10 @@ static enum srpt_command_state srpt_set_cmd_state(struct srpt_send_ioctx *ioctx, enum srpt_command_state new) { enum srpt_command_state previous; - unsigned long flags; - - BUG_ON(!ioctx); - spin_lock_irqsave(&ioctx->spinlock, flags); previous = ioctx->state; if (previous != SRPT_STATE_DONE) ioctx->state = new; - spin_unlock_irqrestore(&ioctx->spinlock, flags); return previous; } @@ -790,17 +785,15 @@ static bool srpt_test_and_set_cmd_state(struct srpt_send_ioctx *ioctx, enum srpt_command_state new) { enum srpt_command_state previous; - unsigned long flags; WARN_ON(!ioctx); WARN_ON(old == SRPT_STATE_DONE); WARN_ON(new == SRPT_STATE_NEW); - spin_lock_irqsave(&ioctx->spinlock, flags); previous = ioctx->state; if (previous == old) ioctx->state = new; - spin_unlock_irqrestore(&ioctx->spinlock, flags); + return previous == old; } @@ -1170,7 +1163,6 @@ static struct srpt_send_ioctx *srpt_get_send_ioctx(struct srpt_rdma_ch *ch) return ioctx; BUG_ON(ioctx->ch != ch); - spin_lock_init(&ioctx->spinlock); ioctx->state = SRPT_STATE_NEW; ioctx->n_rdma = 0; ioctx->n_rw_ctx = 0; @@ -1192,7 +1184,6 @@ static struct srpt_send_ioctx *srpt_get_send_ioctx(struct srpt_rdma_ch *ch) static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx) { enum srpt_command_state state; - unsigned long flags; BUG_ON(!ioctx); @@ -1201,7 +1192,6 @@ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx) * the ib_srpt driver, change the state to the next state. */ - spin_lock_irqsave(&ioctx->spinlock, flags); state = ioctx->state; switch (state) { case SRPT_STATE_NEED_DATA: @@ -1216,7 +1206,6 @@ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx) __func__, state); break; } - spin_unlock_irqrestore(&ioctx->spinlock, flags); pr_debug("Aborting cmd with state %d -> %d and tag %lld\n", state, ioctx->state, ioctx->cmd.tag); @@ -2431,13 +2420,11 @@ static void srpt_queue_response(struct se_cmd *cmd) struct ib_send_wr send_wr, *first_wr = &send_wr, *bad_wr; struct ib_sge sge; enum srpt_command_state state; - unsigned long flags; int resp_len, ret, i; u8 srp_tm_status; BUG_ON(!ch); - spin_lock_irqsave(&ioctx->spinlock, flags); state = ioctx->state; switch (state) { case SRPT_STATE_NEW: @@ -2452,7 +2439,6 @@ static void srpt_queue_response(struct se_cmd *cmd) ch, ioctx->ioctx.index, ioctx->state); break; } - spin_unlock_irqrestore(&ioctx->spinlock, flags); if (unlikely(WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))) return; diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 8f90a7ca98e6..11ce8c94a051 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -195,7 +195,6 @@ struct srpt_rw_ctx { * @rw_ctxs: RDMA read/write contexts. * @rdma_cqe: RDMA completion queue element. * @free_list: Node in srpt_rdma_ch.free_list. - * @spinlock: Protects 'state'. * @state: I/O context state. * @cmd: Target core command data structure. * @sense_data: SCSI sense data. @@ -213,7 +212,6 @@ struct srpt_send_ioctx { struct ib_cqe rdma_cqe; struct list_head free_list; - spinlock_t spinlock; enum srpt_command_state state; struct se_cmd cmd; u8 n_rdma; -- cgit v1.2.3 From 795bc112cd5a40e7612313f54ee527198b1e734f Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 16 Jan 2018 16:14:05 -0800 Subject: IB/srpt: Make it safe to use RCU for srpt_device.rch_list The next patch will iterate over rch_list from a context from which it is not allowed to block. Hence make rch_list RCU-safe. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 13 ++++++++++--- drivers/infiniband/ulp/srpt/ib_srpt.h | 2 ++ 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index d78f60dcc2ba..4dd15378bc7c 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1906,7 +1906,7 @@ static void srpt_free_ch(struct kref *kref) { struct srpt_rdma_ch *ch = container_of(kref, struct srpt_rdma_ch, kref); - kfree(ch); + kfree_rcu(ch, rcu); } static void srpt_release_channel_work(struct work_struct *w) @@ -1945,11 +1945,17 @@ static void srpt_release_channel_work(struct work_struct *w) srp_max_req_size, DMA_FROM_DEVICE); mutex_lock(&sdev->mutex); - list_del_init(&ch->list); + list_del_rcu(&ch->list); if (ch->release_done) complete(ch->release_done); mutex_unlock(&sdev->mutex); + synchronize_rcu(); + + mutex_lock(&sdev->mutex); + INIT_LIST_HEAD(&ch->list); + mutex_unlock(&sdev->mutex); + wake_up(&sdev->ch_releaseQ); kref_put(&ch->kref, srpt_free_ch); @@ -2064,6 +2070,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, goto reject; } + init_rcu_head(&ch->rcu); kref_init(&ch->kref); ch->zw_cqe.done = srpt_zerolength_write_done; INIT_WORK(&ch->release_work, srpt_release_channel_work); @@ -2190,7 +2197,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, } mutex_lock(&sdev->mutex); - list_add_tail(&ch->list, &sdev->rch_list); + list_add_tail_rcu(&ch->list, &sdev->rch_list); mutex_unlock(&sdev->mutex); goto out; diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 11ce8c94a051..0ab59c60f2ef 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -244,6 +244,7 @@ enum rdma_ch_state { * @qp: IB queue pair used for communicating over this channel. * @cq: IB completion queue for this channel. * @zw_cqe: Zero-length write CQE. + * @rcu: RCU head. * @kref: kref for this channel. * @rq_size: IB receive queue size. * @max_rsp_size: Maximum size of an RSP response message in bytes. @@ -276,6 +277,7 @@ struct srpt_rdma_ch { struct ib_qp *qp; struct ib_cq *cq; struct ib_cqe zw_cqe; + struct rcu_head rcu; struct kref kref; int rq_size; u32 max_rsp_size; -- cgit v1.2.3 From 4413834452a65dd322aeeb8da3b4da58b3daa73b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 16 Jan 2018 16:14:06 -0800 Subject: IB/srpt: Rework srpt_disconnect_ch_sync() This patch fixes a use-after-free issue for ch->release_done when running the SRP protocol on top of the rdma_rxe driver. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 45 ++++++++++++++++++----------------- drivers/infiniband/ulp/srpt/ib_srpt.h | 2 -- 2 files changed, 23 insertions(+), 24 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 4dd15378bc7c..5386b993daf9 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1841,6 +1841,23 @@ static int srpt_disconnect_ch(struct srpt_rdma_ch *ch) return ret; } +static bool srpt_ch_closed(struct srpt_device *sdev, struct srpt_rdma_ch *ch) +{ + struct srpt_rdma_ch *ch2; + bool res = true; + + rcu_read_lock(); + list_for_each_entry(ch2, &sdev->rch_list, list) { + if (ch2 == ch) { + res = false; + break; + } + } + rcu_read_unlock(); + + return res; +} + /* * Send DREQ and wait for DREP. Return true if and only if this function * changed the state of @ch. @@ -1848,31 +1865,24 @@ static int srpt_disconnect_ch(struct srpt_rdma_ch *ch) static bool srpt_disconnect_ch_sync(struct srpt_rdma_ch *ch) __must_hold(&sdev->mutex) { - DECLARE_COMPLETION_ONSTACK(release_done); struct srpt_device *sdev = ch->sport->sdev; - bool wait; + int ret; lockdep_assert_held(&sdev->mutex); pr_debug("ch %s-%d state %d\n", ch->sess_name, ch->qp->qp_num, ch->state); - WARN_ON(ch->release_done); - ch->release_done = &release_done; - wait = !list_empty(&ch->list); - srpt_disconnect_ch(ch); + ret = srpt_disconnect_ch(ch); mutex_unlock(&sdev->mutex); - if (!wait) - goto out; - - while (wait_for_completion_timeout(&release_done, 180 * HZ) == 0) + while (wait_event_timeout(sdev->ch_releaseQ, srpt_ch_closed(sdev, ch), + 5 * HZ) == 0) pr_info("%s(%s-%d state %d): still waiting ...\n", __func__, ch->sess_name, ch->qp->qp_num, ch->state); -out: mutex_lock(&sdev->mutex); - return wait; + return ret == 0; } static void srpt_set_enabled(struct srpt_port *sport, bool enabled) @@ -1916,8 +1926,7 @@ static void srpt_release_channel_work(struct work_struct *w) struct se_session *se_sess; ch = container_of(w, struct srpt_rdma_ch, release_work); - pr_debug("%s: %s-%d; release_done = %p\n", __func__, ch->sess_name, - ch->qp->qp_num, ch->release_done); + pr_debug("%s-%d\n", ch->sess_name, ch->qp->qp_num); sdev = ch->sport->sdev; BUG_ON(!sdev); @@ -1946,14 +1955,6 @@ static void srpt_release_channel_work(struct work_struct *w) mutex_lock(&sdev->mutex); list_del_rcu(&ch->list); - if (ch->release_done) - complete(ch->release_done); - mutex_unlock(&sdev->mutex); - - synchronize_rcu(); - - mutex_lock(&sdev->mutex); - INIT_LIST_HEAD(&ch->list); mutex_unlock(&sdev->mutex); wake_up(&sdev->ch_releaseQ); diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 0ab59c60f2ef..67248338b4c9 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -270,7 +270,6 @@ enum rdma_ch_state { * @sess_name: Session name. * @ini_guid: Initiator port GUID. * @release_work: Allows scheduling of srpt_release_channel(). - * @release_done: Enables waiting for srpt_release_channel() completion. */ struct srpt_rdma_ch { struct ib_cm_id *cm_id; @@ -299,7 +298,6 @@ struct srpt_rdma_ch { u8 sess_name[36]; u8 ini_guid[24]; struct work_struct release_work; - struct completion *release_done; }; /** -- cgit v1.2.3 From c5efb62148a4bf2865d76c43c012a3329f5b5b8c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 16 Jan 2018 16:14:07 -0800 Subject: IB/srpt: Add P_Key support Process connection requests that use another P_Key than the default correctly. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 14 +++++++++++--- drivers/infiniband/ulp/srpt/ib_srpt.h | 2 ++ 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 5386b993daf9..cafa73083ee8 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -1057,7 +1058,12 @@ static int srpt_init_ch_qp(struct srpt_rdma_ch *ch, struct ib_qp *qp) attr->qp_state = IB_QPS_INIT; attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE; attr->port_num = ch->sport->port; - attr->pkey_index = 0; + + ret = ib_find_cached_pkey(ch->sport->sdev->device, ch->sport->port, + ch->pkey, &attr->pkey_index); + if (ret < 0) + pr_err("Translating pkey %#x failed (%d) - using index 0\n", + ch->pkey, ret); ret = ib_modify_qp(qp, attr, IB_QP_STATE | IB_QP_ACCESS_FLAGS | IB_QP_PORT | @@ -1994,9 +2000,10 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, it_iu_len = be32_to_cpu(req->req_it_iu_len); - pr_info("Received SRP_LOGIN_REQ with i_port_id %pI6, t_port_id %pI6 and it_iu_len %d on port %d (guid=%pI6)\n", + pr_info("Received SRP_LOGIN_REQ with i_port_id %pI6, t_port_id %pI6 and it_iu_len %d on port %d (guid=%pI6); pkey %#04x\n", req->initiator_port_id, req->target_port_id, it_iu_len, - param->port, &sport->gid); + param->port, &sport->gid, + be16_to_cpu(param->primary_path->pkey)); rsp = kzalloc(sizeof(*rsp), GFP_KERNEL); rej = kzalloc(sizeof(*rej), GFP_KERNEL); @@ -2073,6 +2080,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, init_rcu_head(&ch->rcu); kref_init(&ch->kref); + ch->pkey = be16_to_cpu(param->primary_path->pkey); ch->zw_cqe.done = srpt_zerolength_write_done; INIT_WORK(&ch->release_work, srpt_release_channel_work); memcpy(ch->i_port_id, req->initiator_port_id, 16); diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 67248338b4c9..f830968e7fd4 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -266,6 +266,7 @@ enum rdma_ch_state { * @cmd_wait_list: List of SCSI commands that arrived before the RTU event. This * list contains struct srpt_ioctx elements and is protected * against concurrent modification by the cm_id spinlock. + * @pkey: P_Key of the IB partition for this SRP channel. * @sess: Session information associated with this SRP channel. * @sess_name: Session name. * @ini_guid: Initiator port GUID. @@ -294,6 +295,7 @@ struct srpt_rdma_ch { struct srpt_recv_ioctx **ioctx_recv_ring; struct list_head list; struct list_head cmd_wait_list; + uint16_t pkey; struct se_session *sess; u8 sess_name[36]; u8 ini_guid[24]; -- cgit v1.2.3 From ba60c84f82f6facfe66688073458f233e4e5ba51 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 16 Jan 2018 16:14:08 -0800 Subject: IB/srpt: One target per port In multipathing setups where a target system is equipped with dual-port HCAs it is useful to have one connection per target port instead of one connection per target HCA. Hence move the connection list (rch_list) from struct srpt_device into struct srpt_port. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 98 +++++++++++++++++++---------------- drivers/infiniband/ulp/srpt/ib_srpt.h | 16 +++--- 2 files changed, 61 insertions(+), 53 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index cafa73083ee8..7893fc420794 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1847,13 +1847,13 @@ static int srpt_disconnect_ch(struct srpt_rdma_ch *ch) return ret; } -static bool srpt_ch_closed(struct srpt_device *sdev, struct srpt_rdma_ch *ch) +static bool srpt_ch_closed(struct srpt_port *sport, struct srpt_rdma_ch *ch) { struct srpt_rdma_ch *ch2; bool res = true; rcu_read_lock(); - list_for_each_entry(ch2, &sdev->rch_list, list) { + list_for_each_entry(ch2, &sport->rch_list, list) { if (ch2 == ch) { res = false; break; @@ -1871,33 +1871,32 @@ static bool srpt_ch_closed(struct srpt_device *sdev, struct srpt_rdma_ch *ch) static bool srpt_disconnect_ch_sync(struct srpt_rdma_ch *ch) __must_hold(&sdev->mutex) { - struct srpt_device *sdev = ch->sport->sdev; + struct srpt_port *sport = ch->sport; int ret; - lockdep_assert_held(&sdev->mutex); + lockdep_assert_held(&sport->mutex); pr_debug("ch %s-%d state %d\n", ch->sess_name, ch->qp->qp_num, ch->state); ret = srpt_disconnect_ch(ch); - mutex_unlock(&sdev->mutex); + mutex_unlock(&sport->mutex); - while (wait_event_timeout(sdev->ch_releaseQ, srpt_ch_closed(sdev, ch), + while (wait_event_timeout(sport->ch_releaseQ, srpt_ch_closed(sport, ch), 5 * HZ) == 0) pr_info("%s(%s-%d state %d): still waiting ...\n", __func__, ch->sess_name, ch->qp->qp_num, ch->state); - mutex_lock(&sdev->mutex); + mutex_lock(&sport->mutex); return ret == 0; } static void srpt_set_enabled(struct srpt_port *sport, bool enabled) - __must_hold(&sdev->mutex) + __must_hold(&sport->mutex) { - struct srpt_device *sdev = sport->sdev; struct srpt_rdma_ch *ch; - lockdep_assert_held(&sdev->mutex); + lockdep_assert_held(&sport->mutex); if (sport->enabled == enabled) return; @@ -1906,10 +1905,10 @@ static void srpt_set_enabled(struct srpt_port *sport, bool enabled) return; again: - list_for_each_entry(ch, &sdev->rch_list, list) { + list_for_each_entry(ch, &sport->rch_list, list) { if (ch->sport == sport) { pr_info("%s: closing channel %s-%d\n", - sdev->device->name, ch->sess_name, + sport->sdev->device->name, ch->sess_name, ch->qp->qp_num); if (srpt_disconnect_ch_sync(ch)) goto again; @@ -1929,6 +1928,7 @@ static void srpt_release_channel_work(struct work_struct *w) { struct srpt_rdma_ch *ch; struct srpt_device *sdev; + struct srpt_port *sport; struct se_session *se_sess; ch = container_of(w, struct srpt_rdma_ch, release_work); @@ -1959,11 +1959,12 @@ static void srpt_release_channel_work(struct work_struct *w) sdev, ch->rq_size, srp_max_req_size, DMA_FROM_DEVICE); - mutex_lock(&sdev->mutex); + sport = ch->sport; + mutex_lock(&sport->mutex); list_del_rcu(&ch->list); - mutex_unlock(&sdev->mutex); + mutex_unlock(&sport->mutex); - wake_up(&sdev->ch_releaseQ); + wake_up(&sport->ch_releaseQ); kref_put(&ch->kref, srpt_free_ch); } @@ -2036,9 +2037,9 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, if ((req->req_flags & SRP_MTCH_ACTION) == SRP_MULTICHAN_SINGLE) { rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_NO_CHAN; - mutex_lock(&sdev->mutex); + mutex_lock(&sport->mutex); - list_for_each_entry_safe(ch, tmp_ch, &sdev->rch_list, list) { + list_for_each_entry_safe(ch, tmp_ch, &sport->rch_list, list) { if (!memcmp(ch->i_port_id, req->initiator_port_id, 16) && !memcmp(ch->t_port_id, req->target_port_id, 16) && param->port == ch->sport->port @@ -2053,7 +2054,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, } } - mutex_unlock(&sdev->mutex); + mutex_unlock(&sport->mutex); } else rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_MAINTAINED; @@ -2205,9 +2206,9 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, goto release_channel; } - mutex_lock(&sdev->mutex); - list_add_tail_rcu(&ch->list, &sdev->rch_list); - mutex_unlock(&sdev->mutex); + mutex_lock(&sport->mutex); + list_add_tail_rcu(&ch->list, &sport->rch_list); + mutex_unlock(&sport->mutex); goto out; @@ -2559,24 +2560,21 @@ static void srpt_refresh_port_work(struct work_struct *work) } /** - * srpt_release_sdev - disable login and wait for associated channels - * @sdev: SRPT HCA pointer. + * srpt_release_sport - disable login and wait for associated channels + * @sport: SRPT HCA port. */ -static int srpt_release_sdev(struct srpt_device *sdev) +static int srpt_release_sport(struct srpt_port *sport) { - int i, res; + int res; WARN_ON_ONCE(irqs_disabled()); - BUG_ON(!sdev); - - mutex_lock(&sdev->mutex); - for (i = 0; i < ARRAY_SIZE(sdev->port); i++) - srpt_set_enabled(&sdev->port[i], false); - mutex_unlock(&sdev->mutex); + mutex_lock(&sport->mutex); + srpt_set_enabled(sport, false); + mutex_unlock(&sport->mutex); - res = wait_event_interruptible(sdev->ch_releaseQ, - list_empty_careful(&sdev->rch_list)); + res = wait_event_interruptible(sport->ch_releaseQ, + list_empty_careful(&sport->rch_list)); if (res) pr_err("%s: interrupted.\n", __func__); @@ -2704,9 +2702,7 @@ static void srpt_add_one(struct ib_device *device) goto err; sdev->device = device; - INIT_LIST_HEAD(&sdev->rch_list); - init_waitqueue_head(&sdev->ch_releaseQ); - mutex_init(&sdev->mutex); + mutex_init(&sdev->sdev_mutex); sdev->pd = ib_alloc_pd(device, 0); if (IS_ERR(sdev->pd)) @@ -2747,6 +2743,9 @@ static void srpt_add_one(struct ib_device *device) for (i = 1; i <= sdev->device->phys_port_cnt; i++) { sport = &sdev->port[i - 1]; + INIT_LIST_HEAD(&sport->rch_list); + init_waitqueue_head(&sport->ch_releaseQ); + mutex_init(&sport->mutex); sport->sdev = sdev; sport->port = i; sport->port_attrib.srp_max_rdma_size = DEFAULT_MAX_RDMA_SIZE; @@ -2819,7 +2818,9 @@ static void srpt_remove_one(struct ib_device *device, void *client_data) spin_lock(&srpt_dev_lock); list_del(&sdev->list); spin_unlock(&srpt_dev_lock); - srpt_release_sdev(sdev); + + for (i = 0; i < sdev->device->phys_port_cnt; i++) + srpt_release_sport(&sdev->port[i]); srpt_free_srq(sdev); @@ -2905,11 +2906,11 @@ static void srpt_release_cmd(struct se_cmd *se_cmd) static void srpt_close_session(struct se_session *se_sess) { struct srpt_rdma_ch *ch = se_sess->fabric_sess_ptr; - struct srpt_device *sdev = ch->sport->sdev; + struct srpt_port *sport = ch->sport; - mutex_lock(&sdev->mutex); + mutex_lock(&sport->mutex); srpt_disconnect_ch_sync(ch); - mutex_unlock(&sdev->mutex); + mutex_unlock(&sport->mutex); } /** @@ -3134,18 +3135,24 @@ static ssize_t srpt_tpg_attrib_use_srq_store(struct config_item *item, if (val != !!val) return -EINVAL; - ret = mutex_lock_interruptible(&sdev->mutex); + ret = mutex_lock_interruptible(&sdev->sdev_mutex); if (ret < 0) return ret; + ret = mutex_lock_interruptible(&sport->mutex); + if (ret < 0) + goto unlock_sdev; enabled = sport->enabled; /* Log out all initiator systems before changing 'use_srq'. */ srpt_set_enabled(sport, false); sport->port_attrib.use_srq = val; srpt_use_srq(sdev, sport->port_attrib.use_srq); srpt_set_enabled(sport, enabled); - mutex_unlock(&sdev->mutex); + ret = count; + mutex_unlock(&sport->mutex); +unlock_sdev: + mutex_unlock(&sdev->sdev_mutex); - return count; + return ret; } CONFIGFS_ATTR(srpt_tpg_attrib_, srp_max_rdma_size); @@ -3174,7 +3181,6 @@ static ssize_t srpt_tpg_enable_store(struct config_item *item, { struct se_portal_group *se_tpg = to_tpg(item); struct srpt_port *sport = srpt_tpg_to_sport(se_tpg); - struct srpt_device *sdev = sport->sdev; unsigned long tmp; int ret; @@ -3189,9 +3195,9 @@ static ssize_t srpt_tpg_enable_store(struct config_item *item, return -EINVAL; } - mutex_lock(&sdev->mutex); + mutex_lock(&sport->mutex); srpt_set_enabled(sport, tmp); - mutex_unlock(&sdev->mutex); + mutex_unlock(&sport->mutex); return count; } diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index f830968e7fd4..1434f0cd45f7 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -262,7 +262,7 @@ enum rdma_ch_state { * @state: channel state. See also enum rdma_ch_state. * @ioctx_ring: Send ring. * @ioctx_recv_ring: Receive I/O context ring. - * @list: Node for insertion in the srpt_device.rch_list list. + * @list: Node in srpt_port.rch_list. * @cmd_wait_list: List of SCSI commands that arrived before the RTU event. This * list contains struct srpt_ioctx elements and is protected * against concurrent modification by the cm_id spinlock. @@ -334,6 +334,9 @@ struct srpt_port_attrib { * @port_gid_tpg: TPG associated with target port GID. * @port_gid_wwn: WWN associated with target port GID. * @port_attrib: Port attributes that can be accessed through configfs. + * @ch_releaseQ: Enables waiting for removal from rch_list. + * @mutex: Protects rch_list. + * @rch_list: Channel list. See also srpt_rdma_ch.list. */ struct srpt_port { struct srpt_device *sdev; @@ -351,6 +354,9 @@ struct srpt_port { struct se_portal_group port_gid_tpg; struct se_wwn port_gid_wwn; struct srpt_port_attrib port_attrib; + wait_queue_head_t ch_releaseQ; + struct mutex mutex; + struct list_head rch_list; }; /** @@ -361,11 +367,9 @@ struct srpt_port { * @srq: Per-HCA SRQ (shared receive queue). * @cm_id: Connection identifier. * @srq_size: SRQ size. + * @sdev_mutex: Serializes use_srq changes. * @use_srq: Whether or not to use SRQ. * @ioctx_ring: Per-HCA SRQ. - * @rch_list: Per-device channel list -- see also srpt_rdma_ch.list. - * @ch_releaseQ: Enables waiting for removal from rch_list. - * @mutex: Protects rch_list. * @port: Information about the ports owned by this HCA. * @event_handler: Per-HCA asynchronous IB event handler. * @list: Node in srpt_dev_list. @@ -377,11 +381,9 @@ struct srpt_device { struct ib_srq *srq; struct ib_cm_id *cm_id; int srq_size; + struct mutex sdev_mutex; bool use_srq; struct srpt_recv_ioctx **ioctx_ring; - struct list_head rch_list; - wait_queue_head_t ch_releaseQ; - struct mutex mutex; struct srpt_port port[2]; struct ib_event_handler event_handler; struct list_head list; -- cgit v1.2.3 From 2dc98f09f9e68fea37ca67b5b4a406f5906c6d8b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 16 Jan 2018 16:14:09 -0800 Subject: IB/srpt: Use the source GID as session name Use the source GID as session name instead of the initiator port ID from the SRP login request. The only functional change in this patch is that it changes the session name shown in debug messages. Note: the fifth argument that is passed to target_alloc_session() is what the SCSI target core uses as key for lookups in the ACL (access control list) information. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 11 ++++++----- drivers/infiniband/ulp/srpt/ib_srpt.h | 4 +--- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 7893fc420794..597fc0bc0734 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1989,6 +1989,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, struct srp_login_rej *rej; struct ib_cm_rep_param *rep_param; struct srpt_rdma_ch *ch, *tmp_ch; + char i_port_id[36]; u32 it_iu_len; int i, ret = 0; @@ -2143,9 +2144,9 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, goto destroy_ib; } - srpt_format_guid(ch->ini_guid, sizeof(ch->ini_guid), + srpt_format_guid(ch->sess_name, sizeof(ch->sess_name), ¶m->primary_path->dgid.global.interface_id); - snprintf(ch->sess_name, sizeof(ch->sess_name), "0x%016llx%016llx", + snprintf(i_port_id, sizeof(i_port_id), "0x%016llx%016llx", be64_to_cpu(*(__be64 *)ch->i_port_id), be64_to_cpu(*(__be64 *)(ch->i_port_id + 8))); @@ -2154,16 +2155,16 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, if (sport->port_guid_tpg.se_tpg_wwn) ch->sess = target_alloc_session(&sport->port_guid_tpg, 0, 0, TARGET_PROT_NORMAL, - ch->ini_guid, ch, NULL); + ch->sess_name, ch, NULL); if (sport->port_gid_tpg.se_tpg_wwn && IS_ERR_OR_NULL(ch->sess)) ch->sess = target_alloc_session(&sport->port_gid_tpg, 0, 0, - TARGET_PROT_NORMAL, ch->sess_name, ch, + TARGET_PROT_NORMAL, i_port_id, ch, NULL); /* Retry without leading "0x" */ if (sport->port_gid_tpg.se_tpg_wwn && IS_ERR_OR_NULL(ch->sess)) ch->sess = target_alloc_session(&sport->port_gid_tpg, 0, 0, TARGET_PROT_NORMAL, - ch->sess_name + 2, ch, NULL); + i_port_id + 2, ch, NULL); if (IS_ERR_OR_NULL(ch->sess)) { pr_info("Rejected login because no ACL has been configured yet for initiator %s.\n", ch->sess_name); diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 1434f0cd45f7..6c5a14ac7742 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -269,7 +269,6 @@ enum rdma_ch_state { * @pkey: P_Key of the IB partition for this SRP channel. * @sess: Session information associated with this SRP channel. * @sess_name: Session name. - * @ini_guid: Initiator port GUID. * @release_work: Allows scheduling of srpt_release_channel(). */ struct srpt_rdma_ch { @@ -297,8 +296,7 @@ struct srpt_rdma_ch { struct list_head cmd_wait_list; uint16_t pkey; struct se_session *sess; - u8 sess_name[36]; - u8 ini_guid[24]; + u8 sess_name[24]; struct work_struct release_work; }; -- cgit v1.2.3 From a11253142e6d317c25215ddb3029f9c754baefef Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 16 Jan 2018 16:14:10 -0800 Subject: IB/srpt: Rework multi-channel support Store initiator and target port ID's once per nexus instead of in each channel data structure. This change simplifies the duplicate connection check in srpt_cm_req_recv(). Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 186 ++++++++++++++++++++++++---------- drivers/infiniband/ulp/srpt/ib_srpt.h | 34 +++++-- 2 files changed, 160 insertions(+), 60 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 597fc0bc0734..de3e77df146e 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1849,16 +1849,20 @@ static int srpt_disconnect_ch(struct srpt_rdma_ch *ch) static bool srpt_ch_closed(struct srpt_port *sport, struct srpt_rdma_ch *ch) { + struct srpt_nexus *nexus; struct srpt_rdma_ch *ch2; bool res = true; rcu_read_lock(); - list_for_each_entry(ch2, &sport->rch_list, list) { - if (ch2 == ch) { - res = false; - break; + list_for_each_entry(nexus, &sport->nexus_list, entry) { + list_for_each_entry(ch2, &nexus->ch_list, list) { + if (ch2 == ch) { + res = false; + goto done; + } } } +done: rcu_read_unlock(); return res; @@ -1891,30 +1895,78 @@ static bool srpt_disconnect_ch_sync(struct srpt_rdma_ch *ch) return ret == 0; } -static void srpt_set_enabled(struct srpt_port *sport, bool enabled) - __must_hold(&sport->mutex) +static void __srpt_close_all_ch(struct srpt_port *sport) { + struct srpt_nexus *nexus; struct srpt_rdma_ch *ch; lockdep_assert_held(&sport->mutex); - if (sport->enabled == enabled) - return; - sport->enabled = enabled; - if (sport->enabled) - return; + list_for_each_entry(nexus, &sport->nexus_list, entry) { + list_for_each_entry(ch, &nexus->ch_list, list) { + if (srpt_disconnect_ch(ch) >= 0) + pr_info("Closing channel %s-%d because target %s_%d has been disabled\n", + ch->sess_name, ch->qp->qp_num, + sport->sdev->device->name, sport->port); + srpt_close_ch(ch); + } + } +} + +/* + * Look up (i_port_id, t_port_id) in sport->nexus_list. Create an entry if + * it does not yet exist. + */ +static struct srpt_nexus *srpt_get_nexus(struct srpt_port *sport, + const u8 i_port_id[16], + const u8 t_port_id[16]) +{ + struct srpt_nexus *nexus = NULL, *tmp_nexus = NULL, *n; -again: - list_for_each_entry(ch, &sport->rch_list, list) { - if (ch->sport == sport) { - pr_info("%s: closing channel %s-%d\n", - sport->sdev->device->name, ch->sess_name, - ch->qp->qp_num); - if (srpt_disconnect_ch_sync(ch)) - goto again; + for (;;) { + mutex_lock(&sport->mutex); + list_for_each_entry(n, &sport->nexus_list, entry) { + if (memcmp(n->i_port_id, i_port_id, 16) == 0 && + memcmp(n->t_port_id, t_port_id, 16) == 0) { + nexus = n; + break; + } + } + if (!nexus && tmp_nexus) { + list_add_tail_rcu(&tmp_nexus->entry, + &sport->nexus_list); + swap(nexus, tmp_nexus); } + mutex_unlock(&sport->mutex); + + if (nexus) + break; + tmp_nexus = kzalloc(sizeof(*nexus), GFP_KERNEL); + if (!tmp_nexus) { + nexus = ERR_PTR(-ENOMEM); + break; + } + init_rcu_head(&tmp_nexus->rcu); + INIT_LIST_HEAD(&tmp_nexus->ch_list); + memcpy(tmp_nexus->i_port_id, i_port_id, 16); + memcpy(tmp_nexus->t_port_id, t_port_id, 16); } + kfree(tmp_nexus); + + return nexus; +} + +static void srpt_set_enabled(struct srpt_port *sport, bool enabled) + __must_hold(&sport->mutex) +{ + lockdep_assert_held(&sport->mutex); + + if (sport->enabled == enabled) + return; + sport->enabled = enabled; + if (!enabled) + __srpt_close_all_ch(sport); } static void srpt_free_ch(struct kref *kref) @@ -1984,11 +2036,12 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, { struct srpt_device *sdev = cm_id->context; struct srpt_port *sport = &sdev->port[param->port - 1]; + struct srpt_nexus *nexus; struct srp_login_req *req; - struct srp_login_rsp *rsp; - struct srp_login_rej *rej; - struct ib_cm_rep_param *rep_param; - struct srpt_rdma_ch *ch, *tmp_ch; + struct srp_login_rsp *rsp = NULL; + struct srp_login_rej *rej = NULL; + struct ib_cm_rep_param *rep_param = NULL; + struct srpt_rdma_ch *ch; char i_port_id[36]; u32 it_iu_len; int i, ret = 0; @@ -2007,6 +2060,13 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, param->port, &sport->gid, be16_to_cpu(param->primary_path->pkey)); + nexus = srpt_get_nexus(sport, req->initiator_port_id, + req->target_port_id); + if (IS_ERR(nexus)) { + ret = PTR_ERR(nexus); + goto out; + } + rsp = kzalloc(sizeof(*rsp), GFP_KERNEL); rej = kzalloc(sizeof(*rej), GFP_KERNEL); rep_param = kzalloc(sizeof(*rep_param), GFP_KERNEL); @@ -2036,29 +2096,22 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, } if ((req->req_flags & SRP_MTCH_ACTION) == SRP_MULTICHAN_SINGLE) { + struct srpt_rdma_ch *ch2; + rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_NO_CHAN; mutex_lock(&sport->mutex); - - list_for_each_entry_safe(ch, tmp_ch, &sport->rch_list, list) { - if (!memcmp(ch->i_port_id, req->initiator_port_id, 16) - && !memcmp(ch->t_port_id, req->target_port_id, 16) - && param->port == ch->sport->port - && param->listen_id == ch->sport->sdev->cm_id - && ch->cm_id) { - if (srpt_disconnect_ch(ch) < 0) - continue; - pr_info("Relogin - closed existing channel %s\n", - ch->sess_name); - rsp->rsp_flags = - SRP_LOGIN_RSP_MULTICHAN_TERMINATED; - } + list_for_each_entry(ch2, &nexus->ch_list, list) { + if (srpt_disconnect_ch(ch2) < 0) + continue; + pr_info("Relogin - closed existing channel %s\n", + ch2->sess_name); + rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_TERMINATED; } - mutex_unlock(&sport->mutex); - - } else + } else { rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_MAINTAINED; + } if (*(__be64 *)req->target_port_id != cpu_to_be64(srpt_service_guid) || *(__be64 *)(req->target_port_id + 8) != @@ -2083,10 +2136,9 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, init_rcu_head(&ch->rcu); kref_init(&ch->kref); ch->pkey = be16_to_cpu(param->primary_path->pkey); + ch->nexus = nexus; ch->zw_cqe.done = srpt_zerolength_write_done; INIT_WORK(&ch->release_work, srpt_release_channel_work); - memcpy(ch->i_port_id, req->initiator_port_id, 16); - memcpy(ch->t_port_id, req->target_port_id, 16); ch->sport = &sdev->port[param->port - 1]; ch->cm_id = cm_id; cm_id->context = ch; @@ -2147,8 +2199,8 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, srpt_format_guid(ch->sess_name, sizeof(ch->sess_name), ¶m->primary_path->dgid.global.interface_id); snprintf(i_port_id, sizeof(i_port_id), "0x%016llx%016llx", - be64_to_cpu(*(__be64 *)ch->i_port_id), - be64_to_cpu(*(__be64 *)(ch->i_port_id + 8))); + be64_to_cpu(*(__be64 *)nexus->i_port_id), + be64_to_cpu(*(__be64 *)(nexus->i_port_id + 8))); pr_debug("registering session %s\n", ch->sess_name); @@ -2208,7 +2260,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, } mutex_lock(&sport->mutex); - list_add_tail_rcu(&ch->list, &sport->rch_list); + list_add_tail_rcu(&ch->list, &nexus->ch_list); mutex_unlock(&sport->mutex); goto out; @@ -2560,13 +2612,28 @@ static void srpt_refresh_port_work(struct work_struct *work) srpt_refresh_port(sport); } +static bool srpt_ch_list_empty(struct srpt_port *sport) +{ + struct srpt_nexus *nexus; + bool res = true; + + rcu_read_lock(); + list_for_each_entry(nexus, &sport->nexus_list, entry) + if (!list_empty(&nexus->ch_list)) + res = false; + rcu_read_unlock(); + + return res; +} + /** * srpt_release_sport - disable login and wait for associated channels * @sport: SRPT HCA port. */ static int srpt_release_sport(struct srpt_port *sport) { - int res; + struct srpt_nexus *nexus, *next_n; + struct srpt_rdma_ch *ch; WARN_ON_ONCE(irqs_disabled()); @@ -2574,10 +2641,27 @@ static int srpt_release_sport(struct srpt_port *sport) srpt_set_enabled(sport, false); mutex_unlock(&sport->mutex); - res = wait_event_interruptible(sport->ch_releaseQ, - list_empty_careful(&sport->rch_list)); - if (res) - pr_err("%s: interrupted.\n", __func__); + while (wait_event_timeout(sport->ch_releaseQ, + srpt_ch_list_empty(sport), 5 * HZ) <= 0) { + pr_info("%s_%d: waiting for session unregistration ...\n", + sport->sdev->device->name, sport->port); + rcu_read_lock(); + list_for_each_entry(nexus, &sport->nexus_list, entry) { + list_for_each_entry(ch, &nexus->ch_list, list) { + pr_info("%s-%d: state %s\n", + ch->sess_name, ch->qp->qp_num, + get_ch_state_name(ch->state)); + } + } + rcu_read_unlock(); + } + + mutex_lock(&sport->mutex); + list_for_each_entry_safe(nexus, next_n, &sport->nexus_list, entry) { + list_del(&nexus->entry); + kfree_rcu(nexus, rcu); + } + mutex_unlock(&sport->mutex); return 0; } @@ -2744,7 +2828,7 @@ static void srpt_add_one(struct ib_device *device) for (i = 1; i <= sdev->device->phys_port_cnt; i++) { sport = &sdev->port[i - 1]; - INIT_LIST_HEAD(&sport->rch_list); + INIT_LIST_HEAD(&sport->nexus_list); init_waitqueue_head(&sport->ch_releaseQ); mutex_init(&sport->mutex); sport->sdev = sdev; diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 6c5a14ac7742..59261d5de292 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -54,6 +54,8 @@ */ #define SRP_SERVICE_NAME_PREFIX "SRP.T10:" +struct srpt_nexus; + enum { /* * SRP IOControllerProfile attributes for SRP target ports that have @@ -240,6 +242,7 @@ enum rdma_ch_state { /** * struct srpt_rdma_ch - RDMA channel + * @nexus: I_T nexus this channel is associated with. * @cm_id: IB CM ID associated with the channel. * @qp: IB queue pair used for communicating over this channel. * @cq: IB completion queue for this channel. @@ -251,8 +254,6 @@ enum rdma_ch_state { * @sq_wr_avail: number of work requests available in the send queue. * @sport: pointer to the information of the HCA port used by this * channel. - * @i_port_id: 128-bit initiator port identifier copied from SRP_LOGIN_REQ. - * @t_port_id: 128-bit target port identifier copied from SRP_LOGIN_REQ. * @max_ti_iu_len: maximum target-to-initiator information unit length. * @req_lim: request limit: maximum number of requests that may be sent * by the initiator without having received a response. @@ -262,7 +263,7 @@ enum rdma_ch_state { * @state: channel state. See also enum rdma_ch_state. * @ioctx_ring: Send ring. * @ioctx_recv_ring: Receive I/O context ring. - * @list: Node in srpt_port.rch_list. + * @list: Node in srpt_nexus.ch_list. * @cmd_wait_list: List of SCSI commands that arrived before the RTU event. This * list contains struct srpt_ioctx elements and is protected * against concurrent modification by the cm_id spinlock. @@ -272,6 +273,7 @@ enum rdma_ch_state { * @release_work: Allows scheduling of srpt_release_channel(). */ struct srpt_rdma_ch { + struct srpt_nexus *nexus; struct ib_cm_id *cm_id; struct ib_qp *qp; struct ib_cq *cq; @@ -282,8 +284,6 @@ struct srpt_rdma_ch { u32 max_rsp_size; atomic_t sq_wr_avail; struct srpt_port *sport; - u8 i_port_id[16]; - u8 t_port_id[16]; int max_ti_iu_len; atomic_t req_lim; atomic_t req_lim_delta; @@ -300,6 +300,22 @@ struct srpt_rdma_ch { struct work_struct release_work; }; +/** + * struct srpt_nexus - I_T nexus + * @rcu: RCU head for this data structure. + * @entry: srpt_port.nexus_list list node. + * @ch_list: struct srpt_rdma_ch list. Protected by srpt_port.mutex. + * @i_port_id: 128-bit initiator port identifier copied from SRP_LOGIN_REQ. + * @t_port_id: 128-bit target port identifier copied from SRP_LOGIN_REQ. + */ +struct srpt_nexus { + struct rcu_head rcu; + struct list_head entry; + struct list_head ch_list; + u8 i_port_id[16]; + u8 t_port_id[16]; +}; + /** * struct srpt_port_attib - attributes for SRPT port * @srp_max_rdma_size: Maximum size of SRP RDMA transfers for new connections. @@ -332,9 +348,9 @@ struct srpt_port_attrib { * @port_gid_tpg: TPG associated with target port GID. * @port_gid_wwn: WWN associated with target port GID. * @port_attrib: Port attributes that can be accessed through configfs. - * @ch_releaseQ: Enables waiting for removal from rch_list. - * @mutex: Protects rch_list. - * @rch_list: Channel list. See also srpt_rdma_ch.list. + * @ch_releaseQ: Enables waiting for removal from nexus_list. + * @mutex: Protects nexus_list. + * @nexus_list: Nexus list. See also srpt_nexus.entry. */ struct srpt_port { struct srpt_device *sdev; @@ -354,7 +370,7 @@ struct srpt_port { struct srpt_port_attrib port_attrib; wait_queue_head_t ch_releaseQ; struct mutex mutex; - struct list_head rch_list; + struct list_head nexus_list; }; /** -- cgit v1.2.3 From 940874f8beae5b954350317920170e84ce5dcbee Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 16 Jan 2018 16:14:11 -0800 Subject: IB/srpt: Simplify srpt_close_session() Move a mutex lock and unlock statement from srpt_close_session() into srpt_disconnect_ch_sync(). Since the previous patch removed the last user of the return value of that function, change the return value of srpt_disconnect_ch_sync() into void. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index de3e77df146e..b248515a4fe4 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1868,22 +1868,16 @@ done: return res; } -/* - * Send DREQ and wait for DREP. Return true if and only if this function - * changed the state of @ch. - */ -static bool srpt_disconnect_ch_sync(struct srpt_rdma_ch *ch) - __must_hold(&sdev->mutex) +/* Send DREQ and wait for DREP. */ +static void srpt_disconnect_ch_sync(struct srpt_rdma_ch *ch) { struct srpt_port *sport = ch->sport; - int ret; - - lockdep_assert_held(&sport->mutex); pr_debug("ch %s-%d state %d\n", ch->sess_name, ch->qp->qp_num, ch->state); - ret = srpt_disconnect_ch(ch); + mutex_lock(&sport->mutex); + srpt_disconnect_ch(ch); mutex_unlock(&sport->mutex); while (wait_event_timeout(sport->ch_releaseQ, srpt_ch_closed(sport, ch), @@ -1891,8 +1885,6 @@ static bool srpt_disconnect_ch_sync(struct srpt_rdma_ch *ch) pr_info("%s(%s-%d state %d): still waiting ...\n", __func__, ch->sess_name, ch->qp->qp_num, ch->state); - mutex_lock(&sport->mutex); - return ret == 0; } static void __srpt_close_all_ch(struct srpt_port *sport) @@ -2991,11 +2983,8 @@ static void srpt_release_cmd(struct se_cmd *se_cmd) static void srpt_close_session(struct se_session *se_sess) { struct srpt_rdma_ch *ch = se_sess->fabric_sess_ptr; - struct srpt_port *sport = ch->sport; - mutex_lock(&sport->mutex); srpt_disconnect_ch_sync(ch); - mutex_unlock(&sport->mutex); } /** -- cgit v1.2.3 From 63d370a6a929b17859c140d58cb54ce36d0c4f04 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 16 Jan 2018 16:14:12 -0800 Subject: IB/srpt: Log all zero-length writes and completions The new pr_debug() statements are useful when debugging the ib_srpt driver. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index b248515a4fe4..866ff4be553c 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -840,6 +840,9 @@ static int srpt_zerolength_write(struct srpt_rdma_ch *ch) { struct ib_send_wr wr, *bad_wr; + pr_debug("%s-%d: queued zerolength write\n", ch->sess_name, + ch->qp->qp_num); + memset(&wr, 0, sizeof(wr)); wr.opcode = IB_WR_RDMA_WRITE; wr.wr_cqe = &ch->zw_cqe; @@ -851,6 +854,9 @@ static void srpt_zerolength_write_done(struct ib_cq *cq, struct ib_wc *wc) { struct srpt_rdma_ch *ch = cq->cq_context; + pr_debug("%s-%d wc->status %d\n", ch->sess_name, ch->qp->qp_num, + wc->status); + if (wc->status == IB_WC_SUCCESS) { srpt_process_wait_list(ch); } else { @@ -1804,8 +1810,6 @@ static bool srpt_close_ch(struct srpt_rdma_ch *ch) pr_err("%s-%d: changing queue pair into error state failed: %d\n", ch->sess_name, ch->qp->qp_num, ret); - pr_debug("%s-%d: queued zerolength write\n", ch->sess_name, - ch->qp->qp_num); ret = srpt_zerolength_write(ch); if (ret < 0) { pr_err("%s-%d: queuing zero-length write failed: %d\n", -- cgit v1.2.3 From db7683d7deb25d6edc9c59ac45c56c6a48a45514 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 16 Jan 2018 16:14:13 -0800 Subject: IB/srpt: Fix login-related race conditions Make sure that sport->mutex is not released between the duplicate channel check, adding a channel to the channel list and performing the sport enabled check. Avoid that srpt_disconnect_ch() can be invoked concurrently with the ib_send_cm_rep() call by srpt_cm_req_recv(). Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 195 +++++++++++++++++++--------------- 1 file changed, 111 insertions(+), 84 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 866ff4be553c..6278c4448061 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -2040,7 +2040,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, struct srpt_rdma_ch *ch; char i_port_id[36]; u32 it_iu_len; - int i, ret = 0; + int i, ret; WARN_ON_ONCE(irqs_disabled()); @@ -2063,69 +2063,43 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, goto out; } + ret = -ENOMEM; rsp = kzalloc(sizeof(*rsp), GFP_KERNEL); rej = kzalloc(sizeof(*rej), GFP_KERNEL); rep_param = kzalloc(sizeof(*rep_param), GFP_KERNEL); - - if (!rsp || !rej || !rep_param) { - ret = -ENOMEM; + if (!rsp || !rej || !rep_param) goto out; - } + ret = -EINVAL; if (it_iu_len > srp_max_req_size || it_iu_len < 64) { rej->reason = cpu_to_be32( - SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE); - ret = -EINVAL; - pr_err("rejected SRP_LOGIN_REQ because its" - " length (%d bytes) is out of range (%d .. %d)\n", + SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE); + pr_err("rejected SRP_LOGIN_REQ because its length (%d bytes) is out of range (%d .. %d)\n", it_iu_len, 64, srp_max_req_size); goto reject; } if (!sport->enabled) { - rej->reason = cpu_to_be32( - SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); - ret = -EINVAL; - pr_err("rejected SRP_LOGIN_REQ because the target port" - " has not yet been enabled\n"); + rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); + pr_info("rejected SRP_LOGIN_REQ because target port %s_%d has not yet been enabled\n", + sport->sdev->device->name, param->port); goto reject; } - if ((req->req_flags & SRP_MTCH_ACTION) == SRP_MULTICHAN_SINGLE) { - struct srpt_rdma_ch *ch2; - - rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_NO_CHAN; - - mutex_lock(&sport->mutex); - list_for_each_entry(ch2, &nexus->ch_list, list) { - if (srpt_disconnect_ch(ch2) < 0) - continue; - pr_info("Relogin - closed existing channel %s\n", - ch2->sess_name); - rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_TERMINATED; - } - mutex_unlock(&sport->mutex); - } else { - rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_MAINTAINED; - } - if (*(__be64 *)req->target_port_id != cpu_to_be64(srpt_service_guid) || *(__be64 *)(req->target_port_id + 8) != cpu_to_be64(srpt_service_guid)) { rej->reason = cpu_to_be32( - SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL); - ret = -ENOMEM; - pr_err("rejected SRP_LOGIN_REQ because it" - " has an invalid target port identifier.\n"); + SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL); + pr_err("rejected SRP_LOGIN_REQ because it has an invalid target port identifier.\n"); goto reject; } + ret = -ENOMEM; ch = kzalloc(sizeof(*ch), GFP_KERNEL); if (!ch) { - rej->reason = cpu_to_be32( - SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); - pr_err("rejected SRP_LOGIN_REQ because no memory.\n"); - ret = -ENOMEM; + rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); + pr_err("rejected SRP_LOGIN_REQ because out of memory.\n"); goto reject; } @@ -2153,8 +2127,11 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, srpt_alloc_ioctx_ring(ch->sport->sdev, ch->rq_size, sizeof(*ch->ioctx_ring[0]), ch->max_rsp_size, DMA_TO_DEVICE); - if (!ch->ioctx_ring) + if (!ch->ioctx_ring) { + pr_err("rejected SRP_LOGIN_REQ because creating a new QP SQ ring failed.\n"); + rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); goto free_ch; + } INIT_LIST_HEAD(&ch->free_list); for (i = 0; i < ch->rq_size; i++) { @@ -2176,20 +2153,10 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, } ret = srpt_create_ch_ib(ch); - if (ret) { - rej->reason = cpu_to_be32( - SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); - pr_err("rejected SRP_LOGIN_REQ because creating" - " a new RDMA channel failed.\n"); - goto free_recv_ring; - } - - ret = srpt_ch_qp_rtr(ch, ch->qp); if (ret) { rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); - pr_err("rejected SRP_LOGIN_REQ because enabling" - " RTR failed (error code = %d)\n", ret); - goto destroy_ib; + pr_err("rejected SRP_LOGIN_REQ because creating a new RDMA channel failed.\n"); + goto free_recv_ring; } srpt_format_guid(ch->sess_name, sizeof(ch->sess_name), @@ -2214,11 +2181,51 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, TARGET_PROT_NORMAL, i_port_id + 2, ch, NULL); if (IS_ERR_OR_NULL(ch->sess)) { - pr_info("Rejected login because no ACL has been configured yet for initiator %s.\n", - ch->sess_name); - rej->reason = cpu_to_be32((PTR_ERR(ch->sess) == -ENOMEM) ? + ret = PTR_ERR(ch->sess); + pr_info("Rejected login for initiator %s: ret = %d.\n", + ch->sess_name, ret); + rej->reason = cpu_to_be32(ret == -ENOMEM ? SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES : SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED); + goto reject; + } + + mutex_lock(&sport->mutex); + + if ((req->req_flags & SRP_MTCH_ACTION) == SRP_MULTICHAN_SINGLE) { + struct srpt_rdma_ch *ch2; + + rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_NO_CHAN; + + list_for_each_entry(ch2, &nexus->ch_list, list) { + if (srpt_disconnect_ch(ch2) < 0) + continue; + pr_info("Relogin - closed existing channel %s\n", + ch2->sess_name); + rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_TERMINATED; + } + } else { + rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_MAINTAINED; + } + + list_add_tail_rcu(&ch->list, &nexus->ch_list); + + if (!sport->enabled) { + rej->reason = cpu_to_be32( + SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); + pr_info("rejected SRP_LOGIN_REQ because target %s_%d is not enabled\n", + sdev->device->name, param->port); + mutex_unlock(&sport->mutex); + goto reject; + } + + mutex_unlock(&sport->mutex); + + ret = srpt_ch_qp_rtr(ch, ch->qp); + if (ret) { + rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); + pr_err("rejected SRP_LOGIN_REQ because enabling RTR failed (error code = %d)\n", + ret); goto destroy_ib; } @@ -2231,8 +2238,8 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, rsp->max_it_iu_len = req->req_it_iu_len; rsp->max_ti_iu_len = req->req_it_iu_len; ch->max_ti_iu_len = it_iu_len; - rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT - | SRP_BUF_FORMAT_INDIRECT); + rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | + SRP_BUF_FORMAT_INDIRECT); rsp->req_lim_delta = cpu_to_be32(ch->rq_size); atomic_set(&ch->req_lim, ch->rq_size); atomic_set(&ch->req_lim_delta, 0); @@ -2248,24 +2255,30 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, rep_param->responder_resources = 4; rep_param->initiator_depth = 4; - ret = ib_send_cm_rep(cm_id, rep_param); - if (ret) { - pr_err("sending SRP_LOGIN_REQ response failed" - " (error code = %d)\n", ret); - goto release_channel; - } - + /* + * Hold the sport mutex while accepting a connection to avoid that + * srpt_disconnect_ch() is invoked concurrently with this code. + */ mutex_lock(&sport->mutex); - list_add_tail_rcu(&ch->list, &nexus->ch_list); + if (sport->enabled && ch->state == CH_CONNECTING) + ret = ib_send_cm_rep(cm_id, rep_param); + else + ret = -EINVAL; mutex_unlock(&sport->mutex); - goto out; + switch (ret) { + case 0: + break; + case -EINVAL: + goto reject; + default: + rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); + pr_err("sending SRP_LOGIN_REQ response failed (error code = %d)\n", + ret); + goto reject; + } -release_channel: - srpt_disconnect_ch(ch); - transport_deregister_session_configfs(ch->sess); - transport_deregister_session(ch->sess); - ch->sess = NULL; + goto out; destroy_ib: srpt_destroy_ch_ib(ch); @@ -2280,13 +2293,18 @@ free_ring: ch->sport->sdev, ch->rq_size, ch->max_rsp_size, DMA_TO_DEVICE); free_ch: + cm_id->context = NULL; kfree(ch); + ch = NULL; + + WARN_ON_ONCE(ret == 0); reject: + pr_info("Rejecting login with reason %#x\n", be32_to_cpu(rej->reason)); rej->opcode = SRP_LOGIN_REJ; rej->tag = req->tag; - rej->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT - | SRP_BUF_FORMAT_INDIRECT); + rej->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | + SRP_BUF_FORMAT_INDIRECT); ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED, NULL, 0, (void *)rej, sizeof(*rej)); @@ -2329,17 +2347,26 @@ static void srpt_cm_rtu_recv(struct srpt_rdma_ch *ch) { int ret; - if (srpt_set_ch_state(ch, CH_LIVE)) { - ret = srpt_ch_qp_rts(ch, ch->qp); - - if (ret == 0) { - /* Trigger wait list processing. */ - ret = srpt_zerolength_write(ch); - WARN_ONCE(ret < 0, "%d\n", ret); - } else { - srpt_close_ch(ch); - } + ret = srpt_ch_qp_rts(ch, ch->qp); + if (ret < 0) { + pr_err("%s-%d: QP transition to RTS failed\n", ch->sess_name, + ch->qp->qp_num); + srpt_close_ch(ch); + return; } + + /* Trigger wait list processing. */ + ret = srpt_zerolength_write(ch); + WARN_ONCE(ret < 0, "%d\n", ret); + + /* + * Note: calling srpt_close_ch() if the transition to the LIVE state + * fails is not necessary since that means that that function has + * already been invoked from another thread. + */ + if (!srpt_set_ch_state(ch, CH_LIVE)) + pr_err("%s-%d: channel transition to LIVE state failed\n", + ch->sess_name, ch->qp->qp_num); } /** -- cgit v1.2.3 From e28a547da6e9c6dd5ba64b978d361222db3592e7 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 16 Jan 2018 16:14:14 -0800 Subject: IB/srpt: Fix a race condition related to wait list processing Wait list processing only occurs if the channel state >= CH_LIVE. Hence set the channel state to CH_LIVE before triggering wait list processing asynchronously. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 6278c4448061..372f1eb2fa49 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -2355,18 +2355,20 @@ static void srpt_cm_rtu_recv(struct srpt_rdma_ch *ch) return; } - /* Trigger wait list processing. */ - ret = srpt_zerolength_write(ch); - WARN_ONCE(ret < 0, "%d\n", ret); - /* * Note: calling srpt_close_ch() if the transition to the LIVE state * fails is not necessary since that means that that function has * already been invoked from another thread. */ - if (!srpt_set_ch_state(ch, CH_LIVE)) + if (!srpt_set_ch_state(ch, CH_LIVE)) { pr_err("%s-%d: channel transition to LIVE state failed\n", ch->sess_name, ch->qp->qp_num); + return; + } + + /* Trigger wait list processing. */ + ret = srpt_zerolength_write(ch); + WARN_ONCE(ret < 0, "%d\n", ret); } /** -- cgit v1.2.3 From fcf589364f2a106544d79594dcf722d97528031b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 16 Jan 2018 16:14:15 -0800 Subject: IB/srpt: Don't allow reordering of commands on wait list If a receive I/O context is removed from the wait list and srpt_handle_new_iu() fails to allocate a send I/O context then re-adding the receive I/O context to the wait list can cause reordering. Avoid this by only removing a receive I/O context from the wait list after allocating a send I/O context succeeded. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 82 ++++++++++++++++++++--------------- drivers/infiniband/ulp/srpt/ib_srpt.h | 2 + 2 files changed, 49 insertions(+), 35 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 372f1eb2fa49..5b2e74b1d808 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1533,39 +1533,39 @@ fail: * srpt_handle_new_iu - process a newly received information unit * @ch: RDMA channel through which the information unit has been received. * @recv_ioctx: Receive I/O context associated with the information unit. - * @send_ioctx: Send I/O context. */ -static void srpt_handle_new_iu(struct srpt_rdma_ch *ch, - struct srpt_recv_ioctx *recv_ioctx, - struct srpt_send_ioctx *send_ioctx) +static bool +srpt_handle_new_iu(struct srpt_rdma_ch *ch, struct srpt_recv_ioctx *recv_ioctx) { + struct srpt_send_ioctx *send_ioctx = NULL; struct srp_cmd *srp_cmd; + bool res = false; + u8 opcode; BUG_ON(!ch); BUG_ON(!recv_ioctx); + if (unlikely(ch->state == CH_CONNECTING)) + goto push; + ib_dma_sync_single_for_cpu(ch->sport->sdev->device, recv_ioctx->ioctx.dma, srp_max_req_size, DMA_FROM_DEVICE); - if (unlikely(ch->state == CH_CONNECTING)) - goto out_wait; - - if (unlikely(ch->state != CH_LIVE)) - return; - srp_cmd = recv_ioctx->ioctx.buf; - if (srp_cmd->opcode == SRP_CMD || srp_cmd->opcode == SRP_TSK_MGMT) { - if (!send_ioctx) { - if (!list_empty(&ch->cmd_wait_list)) - goto out_wait; - send_ioctx = srpt_get_send_ioctx(ch); - } + opcode = srp_cmd->opcode; + if (opcode == SRP_CMD || opcode == SRP_TSK_MGMT) { + send_ioctx = srpt_get_send_ioctx(ch); if (unlikely(!send_ioctx)) - goto out_wait; + goto push; } - switch (srp_cmd->opcode) { + if (!list_empty(&recv_ioctx->wait_list)) { + WARN_ON_ONCE(!ch->processing_wait_list); + list_del_init(&recv_ioctx->wait_list); + } + + switch (opcode) { case SRP_CMD: srpt_handle_cmd(ch, recv_ioctx, send_ioctx); break; @@ -1585,16 +1585,22 @@ static void srpt_handle_new_iu(struct srpt_rdma_ch *ch, pr_err("Received SRP_RSP\n"); break; default: - pr_err("received IU with unknown opcode 0x%x\n", - srp_cmd->opcode); + pr_err("received IU with unknown opcode 0x%x\n", opcode); break; } srpt_post_recv(ch->sport->sdev, ch, recv_ioctx); - return; + res = true; -out_wait: - list_add_tail(&recv_ioctx->wait_list, &ch->cmd_wait_list); +out: + return res; + +push: + if (list_empty(&recv_ioctx->wait_list)) { + WARN_ON_ONCE(ch->processing_wait_list); + list_add_tail(&recv_ioctx->wait_list, &ch->cmd_wait_list); + } + goto out; } static void srpt_recv_done(struct ib_cq *cq, struct ib_wc *wc) @@ -1609,7 +1615,7 @@ static void srpt_recv_done(struct ib_cq *cq, struct ib_wc *wc) req_lim = atomic_dec_return(&ch->req_lim); if (unlikely(req_lim < 0)) pr_err("req_lim = %d < 0\n", req_lim); - srpt_handle_new_iu(ch, ioctx, NULL); + srpt_handle_new_iu(ch, ioctx); } else { pr_info_ratelimited("receiving failed for ioctx %p with status %d\n", ioctx, wc->status); @@ -1623,19 +1629,21 @@ static void srpt_recv_done(struct ib_cq *cq, struct ib_wc *wc) */ static void srpt_process_wait_list(struct srpt_rdma_ch *ch) { - struct srpt_send_ioctx *ioctx; + struct srpt_recv_ioctx *recv_ioctx, *tmp; - while (!list_empty(&ch->cmd_wait_list) && - ch->state >= CH_LIVE && - (ioctx = srpt_get_send_ioctx(ch)) != NULL) { - struct srpt_recv_ioctx *recv_ioctx; + WARN_ON_ONCE(ch->state == CH_CONNECTING); - recv_ioctx = list_first_entry(&ch->cmd_wait_list, - struct srpt_recv_ioctx, - wait_list); - list_del(&recv_ioctx->wait_list); - srpt_handle_new_iu(ch, recv_ioctx, ioctx); + if (list_empty(&ch->cmd_wait_list)) + return; + + WARN_ON_ONCE(ch->processing_wait_list); + ch->processing_wait_list = true; + list_for_each_entry_safe(recv_ioctx, tmp, &ch->cmd_wait_list, + wait_list) { + if (!srpt_handle_new_iu(ch, recv_ioctx)) + break; } + ch->processing_wait_list = false; } /** @@ -2150,6 +2158,8 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); goto free_ring; } + for (i = 0; i < ch->rq_size; i++) + INIT_LIST_HEAD(&ch->ioctx_recv_ring[i]->wait_list); } ret = srpt_create_ch_ib(ch); @@ -2773,8 +2783,10 @@ static int srpt_alloc_srq(struct srpt_device *sdev) sdev->use_srq = true; sdev->srq = srq; - for (i = 0; i < sdev->srq_size; ++i) + for (i = 0; i < sdev->srq_size; ++i) { + INIT_LIST_HEAD(&sdev->ioctx_ring[i]->wait_list); srpt_post_recv(sdev, NULL, sdev->ioctx_ring[i]); + } return 0; } diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 59261d5de292..10f9b2667ef2 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -261,6 +261,7 @@ enum rdma_ch_state { * @spinlock: Protects free_list and state. * @free_list: Head of list with free send I/O contexts. * @state: channel state. See also enum rdma_ch_state. + * @processing_wait_list: Whether or not cmd_wait_list is being processed. * @ioctx_ring: Send ring. * @ioctx_recv_ring: Receive I/O context ring. * @list: Node in srpt_nexus.ch_list. @@ -295,6 +296,7 @@ struct srpt_rdma_ch { struct list_head list; struct list_head cmd_wait_list; uint16_t pkey; + bool processing_wait_list; struct se_session *sess; u8 sess_name[24]; struct work_struct release_work; -- cgit v1.2.3 From 090fa24bf239ce1ec58f2b90c5ba54feca456cb0 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 16 Jan 2018 16:14:16 -0800 Subject: IB/srpt: Preparations for adding RDMA/CM support Introduce a union in struct srpt_rdma_ch for member variables that depend on the type of connection manager. Avoid that error messages report the IB/CM ID. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 32 ++++++++++++++++---------------- drivers/infiniband/ulp/srpt/ib_srpt.h | 8 ++++++-- 2 files changed, 22 insertions(+), 18 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 5b2e74b1d808..f066fac19f13 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -215,12 +215,12 @@ static const char *get_ch_state_name(enum rdma_ch_state s) */ static void srpt_qp_event(struct ib_event *event, struct srpt_rdma_ch *ch) { - pr_debug("QP event %d on cm_id=%p sess_name=%s state=%d\n", - event->event, ch->cm_id, ch->sess_name, ch->state); + pr_debug("QP event %d on ch=%p sess_name=%s state=%d\n", + event->event, ch, ch->sess_name, ch->state); switch (event->event) { case IB_EVENT_COMM_EST: - ib_cm_notify(ch->cm_id, event->event); + ib_cm_notify(ch->ib_cm.cm_id, event->event); break; case IB_EVENT_QP_LAST_WQE_REACHED: pr_debug("%s-%d, state %s: received Last WQE event.\n", @@ -1097,7 +1097,7 @@ static int srpt_ch_qp_rtr(struct srpt_rdma_ch *ch, struct ib_qp *qp) int ret; qp_attr.qp_state = IB_QPS_RTR; - ret = ib_cm_init_qp_attr(ch->cm_id, &qp_attr, &attr_mask); + ret = ib_cm_init_qp_attr(ch->ib_cm.cm_id, &qp_attr, &attr_mask); if (ret) goto out; @@ -1127,7 +1127,7 @@ static int srpt_ch_qp_rts(struct srpt_rdma_ch *ch, struct ib_qp *qp) int ret; qp_attr.qp_state = IB_QPS_RTS; - ret = ib_cm_init_qp_attr(ch->cm_id, &qp_attr, &attr_mask); + ret = ib_cm_init_qp_attr(ch->ib_cm.cm_id, &qp_attr, &attr_mask); if (ret) goto out; @@ -1509,9 +1509,9 @@ static void srpt_handle_tsk_mgmt(struct srpt_rdma_ch *ch, srp_tsk = recv_ioctx->ioctx.buf; cmd = &send_ioctx->cmd; - pr_debug("recv tsk_mgmt fn %d for task_tag %lld and cmd tag %lld" - " cm_id %p sess %p\n", srp_tsk->tsk_mgmt_func, - srp_tsk->task_tag, srp_tsk->tag, ch->cm_id, ch->sess); + pr_debug("recv tsk_mgmt fn %d for task_tag %lld and cmd tag %lld ch %p sess %p\n", + srp_tsk->tsk_mgmt_func, srp_tsk->task_tag, srp_tsk->tag, ch, + ch->sess); srpt_set_cmd_state(send_ioctx, SRPT_STATE_MGMT); send_ioctx->cmd.tag = srp_tsk->tag; @@ -1762,9 +1762,9 @@ retry: atomic_set(&ch->sq_wr_avail, qp_init->cap.max_send_wr); - pr_debug("%s: max_cqe= %d max_sge= %d sq_size = %d cm_id= %p\n", + pr_debug("%s: max_cqe= %d max_sge= %d sq_size = %d ch= %p\n", __func__, ch->cq->cqe, qp_init->cap.max_send_sge, - qp_init->cap.max_send_wr, ch->cm_id); + qp_init->cap.max_send_wr, ch); ret = srpt_init_ch_qp(ch, ch->qp); if (ret) @@ -1849,9 +1849,9 @@ static int srpt_disconnect_ch(struct srpt_rdma_ch *ch) if (!srpt_set_ch_state(ch, CH_DISCONNECTING)) return -ENOTCONN; - ret = ib_send_cm_dreq(ch->cm_id, NULL, 0); + ret = ib_send_cm_dreq(ch->ib_cm.cm_id, NULL, 0); if (ret < 0) - ret = ib_send_cm_drep(ch->cm_id, NULL, 0); + ret = ib_send_cm_drep(ch->ib_cm.cm_id, NULL, 0); if (ret < 0 && srpt_close_ch(ch)) ret = 0; @@ -2003,7 +2003,7 @@ static void srpt_release_channel_work(struct work_struct *w) transport_deregister_session(se_sess); ch->sess = NULL; - ib_destroy_cm_id(ch->cm_id); + ib_destroy_cm_id(ch->ib_cm.cm_id); srpt_destroy_ch_ib(ch); @@ -2118,7 +2118,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, ch->zw_cqe.done = srpt_zerolength_write_done; INIT_WORK(&ch->release_work, srpt_release_channel_work); ch->sport = &sdev->port[param->port - 1]; - ch->cm_id = cm_id; + ch->ib_cm.cm_id = cm_id; cm_id->context = ch; /* * ch->rq_size should be at least as large as the initiator queue @@ -2239,8 +2239,8 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, goto destroy_ib; } - pr_debug("Establish connection sess=%p name=%s cm_id=%p\n", ch->sess, - ch->sess_name, ch->cm_id); + pr_debug("Establish connection sess=%p name=%s ch=%p\n", ch->sess, + ch->sess_name, ch); /* create srp_login_response */ rsp->opcode = SRP_LOGIN_RSP; diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 10f9b2667ef2..4d9199fd00dc 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -243,8 +243,8 @@ enum rdma_ch_state { /** * struct srpt_rdma_ch - RDMA channel * @nexus: I_T nexus this channel is associated with. - * @cm_id: IB CM ID associated with the channel. * @qp: IB queue pair used for communicating over this channel. + * @cm_id: IB CM ID associated with the channel. * @cq: IB completion queue for this channel. * @zw_cqe: Zero-length write CQE. * @rcu: RCU head. @@ -275,8 +275,12 @@ enum rdma_ch_state { */ struct srpt_rdma_ch { struct srpt_nexus *nexus; - struct ib_cm_id *cm_id; struct ib_qp *qp; + union { + struct { + struct ib_cm_id *cm_id; + } ib_cm; + }; struct ib_cq *cq; struct ib_cqe zw_cqe; struct rcu_head rcu; -- cgit v1.2.3 From 2ffcf04263832557dc55d5a7339d8f29428b679a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 16 Jan 2018 16:14:17 -0800 Subject: IB/srpt: Move the code for parsing struct ib_cm_req_event_param This patch does not change any functionality but makes srpt_cm_req_recv() independent of the IB/CM and hence simplifies the patch that introduces RDMA/CM support. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 49 +++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 19 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index f066fac19f13..bf37816a1b12 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -2028,20 +2028,22 @@ static void srpt_release_channel_work(struct work_struct *w) /** * srpt_cm_req_recv - process the event IB_CM_REQ_RECEIVED * @cm_id: IB/CM connection identifier. - * @param: IB/CM REQ parameters. - * @private_data: IB/CM REQ private data. + * @port_num: Port through which the IB/CM REQ message was received. + * @pkey: P_Key of the incoming connection. + * @req: SRP login request. + * @src_addr: GID of the port that submitted the login request. * * Ownership of the cm_id is transferred to the target session if this * functions returns zero. Otherwise the caller remains the owner of cm_id. */ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, - struct ib_cm_req_event_param *param, - void *private_data) + u8 port_num, __be16 pkey, + const struct srp_login_req *req, + const char *src_addr) { struct srpt_device *sdev = cm_id->context; - struct srpt_port *sport = &sdev->port[param->port - 1]; + struct srpt_port *sport = &sdev->port[port_num - 1]; struct srpt_nexus *nexus; - struct srp_login_req *req; struct srp_login_rsp *rsp = NULL; struct srp_login_rej *rej = NULL; struct ib_cm_rep_param *rep_param = NULL; @@ -2052,17 +2054,14 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, WARN_ON_ONCE(irqs_disabled()); - if (WARN_ON(!sdev || !private_data)) + if (WARN_ON(!sdev || !req)) return -EINVAL; - req = (struct srp_login_req *)private_data; - it_iu_len = be32_to_cpu(req->req_it_iu_len); pr_info("Received SRP_LOGIN_REQ with i_port_id %pI6, t_port_id %pI6 and it_iu_len %d on port %d (guid=%pI6); pkey %#04x\n", req->initiator_port_id, req->target_port_id, it_iu_len, - param->port, &sport->gid, - be16_to_cpu(param->primary_path->pkey)); + port_num, &sport->gid, be16_to_cpu(pkey)); nexus = srpt_get_nexus(sport, req->initiator_port_id, req->target_port_id); @@ -2090,7 +2089,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, if (!sport->enabled) { rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); pr_info("rejected SRP_LOGIN_REQ because target port %s_%d has not yet been enabled\n", - sport->sdev->device->name, param->port); + sport->sdev->device->name, port_num); goto reject; } @@ -2113,11 +2112,11 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, init_rcu_head(&ch->rcu); kref_init(&ch->kref); - ch->pkey = be16_to_cpu(param->primary_path->pkey); + ch->pkey = be16_to_cpu(pkey); ch->nexus = nexus; ch->zw_cqe.done = srpt_zerolength_write_done; INIT_WORK(&ch->release_work, srpt_release_channel_work); - ch->sport = &sdev->port[param->port - 1]; + ch->sport = sport; ch->ib_cm.cm_id = cm_id; cm_id->context = ch; /* @@ -2169,8 +2168,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, goto free_recv_ring; } - srpt_format_guid(ch->sess_name, sizeof(ch->sess_name), - ¶m->primary_path->dgid.global.interface_id); + strlcpy(ch->sess_name, src_addr, sizeof(ch->sess_name)); snprintf(i_port_id, sizeof(i_port_id), "0x%016llx%016llx", be64_to_cpu(*(__be64 *)nexus->i_port_id), be64_to_cpu(*(__be64 *)(nexus->i_port_id + 8))); @@ -2224,7 +2222,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, rej->reason = cpu_to_be32( SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); pr_info("rejected SRP_LOGIN_REQ because target %s_%d is not enabled\n", - sdev->device->name, param->port); + sdev->device->name, port_num); mutex_unlock(&sport->mutex); goto reject; } @@ -2327,6 +2325,19 @@ out: return ret; } +static int srpt_ib_cm_req_recv(struct ib_cm_id *cm_id, + struct ib_cm_req_event_param *param, + void *private_data) +{ + char sguid[40]; + + srpt_format_guid(sguid, sizeof(sguid), + ¶m->primary_path->dgid.global.interface_id); + + return srpt_cm_req_recv(cm_id, param->port, param->primary_path->pkey, + private_data, sguid); +} + static void srpt_cm_rej_recv(struct srpt_rdma_ch *ch, enum ib_cm_rej_reason reason, const u8 *private_data, @@ -2401,8 +2412,8 @@ static int srpt_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) ret = 0; switch (event->event) { case IB_CM_REQ_RECEIVED: - ret = srpt_cm_req_recv(cm_id, &event->param.req_rcvd, - event->private_data); + ret = srpt_ib_cm_req_recv(cm_id, &event->param.req_rcvd, + event->private_data); break; case IB_CM_REJ_RECEIVED: srpt_cm_rej_recv(ch, event->param.rej_rcvd.reason, -- cgit v1.2.3 From f97f43c9ed1dd9d1f7afc758fc31a619752d08f3 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 24 Jan 2018 08:56:05 +0200 Subject: RDMA/srpt: Fix RCU debug build error Combination of CONFIG_DEBUG_OBJECTS_RCU_HEAD=y and CONFIG_INFINIBAND_SRPT=m produces the following build error. ERROR: "init_rcu_head" [drivers/infiniband/ulp/srpt/ib_srpt.ko] undefined! make[1]: *** [scripts/Makefile.modpost:92: __modpost] Error 1 make: *** [Makefile:1216: modules] Error 2 The reason to it that init_rcu_head() is not exported and not supposed to be used in modules. It is needed for dynamic initialization of statically allocated rcu_head structures. Fixes: 795bc112cd5a ("IB/srpt: Make it safe to use RCU for srpt_device.rch_list") Fixes: a11253142e6d ("IB/srpt: Rework multi-channel support") Signed-off-by: Bart Van Assche Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/infiniband/ulp/srpt/ib_srpt.c') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index bf37816a1b12..0373b7c40902 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1950,7 +1950,6 @@ static struct srpt_nexus *srpt_get_nexus(struct srpt_port *sport, nexus = ERR_PTR(-ENOMEM); break; } - init_rcu_head(&tmp_nexus->rcu); INIT_LIST_HEAD(&tmp_nexus->ch_list); memcpy(tmp_nexus->i_port_id, i_port_id, 16); memcpy(tmp_nexus->t_port_id, t_port_id, 16); @@ -2110,7 +2109,6 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, goto reject; } - init_rcu_head(&ch->rcu); kref_init(&ch->kref); ch->pkey = be16_to_cpu(pkey); ch->nexus = nexus; -- cgit v1.2.3