diff --git a/iscsi-scst/kernel/conn.c b/iscsi-scst/kernel/conn.c index e3396ddd5..42cce27ff 100644 --- a/iscsi-scst/kernel/conn.c +++ b/iscsi-scst/kernel/conn.c @@ -237,7 +237,7 @@ static void conn_sysfs_del(struct iscsi_conn *conn) return; } -static int conn_sysfs_add(struct iscsi_conn *conn) +int conn_sysfs_add(struct iscsi_conn *conn) { int res; struct iscsi_session *session = conn->session; @@ -311,7 +311,7 @@ out_err: conn_sysfs_del(conn); goto out; } - +EXPORT_SYMBOL(conn_sysfs_add); #endif /* CONFIG_SCST_PROC */ /* target_mutex supposed to be locked */ @@ -419,6 +419,7 @@ void mark_conn_closed(struct iscsi_conn *conn) { __mark_conn_closed(conn, ISCSI_CONN_ACTIVE_CLOSE); } +EXPORT_SYMBOL(mark_conn_closed); static void __iscsi_state_change(struct sock *sk) { @@ -846,35 +847,11 @@ void conn_free(struct iscsi_conn *conn) } } -/* target_mutex supposed to be locked */ -int iscsi_conn_alloc(struct iscsi_session *session, - struct iscsi_kern_conn_info *info, struct iscsi_conn **new_conn, - struct iscsit_transport *t) +int iscsi_init_conn(struct iscsi_session *session, + struct iscsi_kern_conn_info *info, + struct iscsi_conn *conn) { - struct iscsi_conn *conn; - int res = 0; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) - lockdep_assert_held(&session->target->target_mutex); -#endif - - conn = kmem_cache_zalloc(iscsi_conn_cache, GFP_KERNEL); - if (!conn) { - res = -ENOMEM; - goto out_err; - } - - TRACE_MGMT_DBG("Creating connection %p for sid %#Lx, cid %u", conn, - (long long unsigned int)session->sid, info->cid); - - conn->transport = t; - - /* Changing it, change ISCSI_CONN_IOV_MAX as well !! */ - conn->read_iov = (struct iovec *)get_zeroed_page(GFP_KERNEL); - if (conn->read_iov == NULL) { - res = -ENOMEM; - goto out_err_free_conn; - } + int res; atomic_set(&conn->conn_ref_cnt, 0); conn->session = session; @@ -890,7 +867,7 @@ int iscsi_conn_alloc(struct iscsi_session *session, conn->ddigest_type = session->sess_params.data_digest; res = digest_init(conn); if (res != 0) - goto out_free_iov; + return res; conn->target = session->target; spin_lock_init(&conn->cmd_list_lock); @@ -925,6 +902,44 @@ int iscsi_conn_alloc(struct iscsi_session *session, conn->nop_in_interval + ISCSI_ADD_SCHED_TIME); } + return 0; +} +EXPORT_SYMBOL(iscsi_init_conn); + +/* target_mutex supposed to be locked */ +int iscsi_conn_alloc(struct iscsi_session *session, + struct iscsi_kern_conn_info *info, struct iscsi_conn **new_conn, + struct iscsit_transport *t) +{ + struct iscsi_conn *conn; + int res = 0; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) + lockdep_assert_held(&session->target->target_mutex); +#endif + + conn = kmem_cache_zalloc(iscsi_conn_cache, GFP_KERNEL); + if (!conn) { + res = -ENOMEM; + goto out_err; + } + + TRACE_MGMT_DBG("Creating connection %p for sid %#Lx, cid %u", conn, + (long long unsigned int)session->sid, info->cid); + + conn->transport = t; + + /* Changing it, change ISCSI_CONN_IOV_MAX as well !! */ + conn->read_iov = (struct iovec *)get_zeroed_page(GFP_KERNEL); + if (conn->read_iov == NULL) { + res = -ENOMEM; + goto out_err_free_conn; + } + + res = iscsi_init_conn(session, info, conn); + if (res != 0) + goto out_free_iov; + conn->file = fget(info->fd); res = conn_setup_sock(conn); diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index 10d876715..1add43d72 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -65,11 +65,9 @@ static struct scatterlist dummy_sg; static void cmnd_remove_data_wait_hash(struct iscsi_cmnd *cmnd); static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status); static void iscsi_check_send_delayed_tm_resp(struct iscsi_session *sess); -static void req_cmnd_release(struct iscsi_cmnd *req); static int cmnd_insert_data_wait_hash(struct iscsi_cmnd *cmnd); static void iscsi_cmnd_init_write(struct iscsi_cmnd *rsp, int flags); static void iscsi_set_resid_no_scst_cmd(struct iscsi_cmnd *rsp); -static void iscsi_set_resid(struct iscsi_cmnd *rsp); static void iscsi_set_not_received_data_len(struct iscsi_cmnd *req, unsigned int not_received) @@ -310,14 +308,9 @@ void iscsi_fail_data_waiting_cmnd(struct iscsi_cmnd *cmnd) return; } -struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *conn, - struct iscsi_cmnd *parent) +void iscsi_cmnd_init(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd, + struct iscsi_cmnd *parent) { - struct iscsi_cmnd *cmnd; - - /* ToDo: __GFP_NOFAIL?? */ - cmnd = kmem_cache_zalloc(iscsi_cmnd_cache, GFP_KERNEL|__GFP_NOFAIL); - atomic_set(&cmnd->ref_cnt, 1); cmnd->scst_state = ISCSI_CMD_STATE_NEW; cmnd->conn = conn; @@ -326,9 +319,6 @@ struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *conn, if (parent == NULL) { conn_get(conn); -#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) - atomic_set(&cmnd->net_ref_cnt, 0); -#endif INIT_LIST_HEAD(&cmnd->rsp_cmd_list); INIT_LIST_HEAD(&cmnd->rx_ddigest_cmd_list); cmnd->target_task_tag = ISCSI_RESERVED_TAG_CPU32; @@ -337,6 +327,24 @@ struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *conn, list_add_tail(&cmnd->cmd_list_entry, &conn->cmd_list); spin_unlock_bh(&conn->cmd_list_lock); } +} +EXPORT_SYMBOL(iscsi_cmnd_init); + +struct iscsi_cmnd *cmnd_alloc(struct iscsi_conn *conn, + struct iscsi_cmnd *parent) +{ + struct iscsi_cmnd *cmnd; + + /* ToDo: __GFP_NOFAIL?? */ + cmnd = kmem_cache_zalloc(iscsi_cmnd_cache, GFP_KERNEL|__GFP_NOFAIL); + + iscsi_cmnd_init(conn, cmnd, parent); + + if (parent == NULL) { +#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) + atomic_set(&cmnd->net_ref_cnt, 0); +#endif + } TRACE_DBG("conn %p, parent %p, cmnd %p", conn, parent, cmnd); return cmnd; @@ -533,6 +541,7 @@ void cmnd_done(struct iscsi_cmnd *cmnd) TRACE_EXIT(); return; } +EXPORT_SYMBOL(cmnd_done); /* * Corresponding conn may also get destroyed after this function, except only @@ -635,7 +644,7 @@ out: return; } -static void req_cmnd_pre_release(struct iscsi_cmnd *req) +void req_cmnd_pre_release(struct iscsi_cmnd *req) { struct iscsi_cmnd *c, *t; @@ -695,12 +704,13 @@ static void req_cmnd_pre_release(struct iscsi_cmnd *req) TRACE_EXIT(); return; } +EXPORT_SYMBOL(req_cmnd_pre_release); /* * Corresponding conn may also get destroyed after this function, except only * if it's called from the read thread! */ -static void req_cmnd_release(struct iscsi_cmnd *req) +void req_cmnd_release(struct iscsi_cmnd *req) { TRACE_ENTRY(); @@ -710,6 +720,7 @@ static void req_cmnd_release(struct iscsi_cmnd *req) TRACE_EXIT(); return; } +EXPORT_SYMBOL(req_cmnd_release); /* * Corresponding conn may also get destroyed after this function, except only @@ -729,6 +740,7 @@ void rsp_cmnd_release(struct iscsi_cmnd *cmnd) cmnd_put(cmnd); return; } +EXPORT_SYMBOL(rsp_cmnd_release); static struct iscsi_cmnd *iscsi_alloc_rsp(struct iscsi_cmnd *parent) { @@ -877,7 +889,7 @@ static void iscsi_set_resid_no_scst_cmd(struct iscsi_cmnd *rsp) return; } -static void iscsi_set_resid(struct iscsi_cmnd *rsp) +void iscsi_set_resid(struct iscsi_cmnd *rsp) { struct iscsi_cmnd *req = rsp->parent_req; struct scst_cmd *scst_cmd = req->scst_cmd; @@ -931,6 +943,7 @@ out: TRACE_EXIT(); return; } +EXPORT_SYMBOL(iscsi_set_resid); static void send_data_rsp(struct iscsi_cmnd *req, u8 status, int send_status) { @@ -1041,7 +1054,7 @@ static void iscsi_init_status_rsp(struct iscsi_cmnd *rsp, return; } -static inline struct iscsi_cmnd *create_status_rsp(struct iscsi_cmnd *req, +struct iscsi_cmnd *create_status_rsp(struct iscsi_cmnd *req, int status, const u8 *sense_buf, int sense_len) { struct iscsi_cmnd *rsp; @@ -1057,6 +1070,7 @@ static inline struct iscsi_cmnd *create_status_rsp(struct iscsi_cmnd *req, TRACE_EXIT_HRES((unsigned long)rsp); return rsp; } +EXPORT_SYMBOL(create_status_rsp); static void iscsi_tcp_send_data_rsp(struct iscsi_cmnd *req, u8 *sense, int sense_len, u8 status, @@ -1252,7 +1266,7 @@ static inline int iscsi_get_allowed_cmds(struct iscsi_session *sess) return res; } -static __be32 cmnd_set_sn(struct iscsi_cmnd *cmnd, int set_stat_sn) +__be32 cmnd_set_sn(struct iscsi_cmnd *cmnd, int set_stat_sn) { struct iscsi_conn *conn = cmnd->conn; struct iscsi_session *sess = conn->session; @@ -1271,6 +1285,7 @@ static __be32 cmnd_set_sn(struct iscsi_cmnd *cmnd, int set_stat_sn) spin_unlock(&sess->sn_lock); return res; } +EXPORT_SYMBOL(cmnd_set_sn); /* Called under sn_lock */ static void update_stat_sn(struct iscsi_cmnd *cmnd) @@ -1822,16 +1837,90 @@ out: return err; } -int cmnd_rx_continue(struct iscsi_cmnd *req) +int iscsi_cmnd_set_write_buf(struct iscsi_cmnd *req) { struct iscsi_conn *conn = req->conn; struct iscsi_session *session = conn->session; struct iscsi_scsi_cmd_hdr *req_hdr = cmnd_hdr(req); struct scst_cmd *scst_cmd = req->scst_cmd; - scst_data_direction dir; bool unsolicited_data_expected = false; int res = 0; + req->bufflen = scst_cmd_get_write_fields(scst_cmd, &req->sg, + &req->sg_cnt); + unsolicited_data_expected = !(req_hdr->flags & ISCSI_CMD_FINAL); + + if (unlikely(session->sess_params.initial_r2t && + unsolicited_data_expected)) { + PRINT_ERROR("Initiator %s violated negotiated " + "parameters: initial R2T is required (ITT %x, " + "op %x)", session->initiator_name, + req->pdu.bhs.itt, req_hdr->scb[0]); + res = -EINVAL; + goto out_close; + } + + if (unlikely(!session->sess_params.immediate_data && + req->pdu.datasize)) { + PRINT_ERROR("Initiator %s violated negotiated " + "parameters: forbidden immediate data sent " + "(ITT %x, op %x)", session->initiator_name, + req->pdu.bhs.itt, req_hdr->scb[0]); + res = -EINVAL; + goto out_close; + } + + if (unlikely(session->sess_params.first_burst_length < req->pdu.datasize)) { + PRINT_ERROR("Initiator %s violated negotiated " + "parameters: immediate data len (%d) > " + "first_burst_length (%d) (ITT %x, op %x)", + session->initiator_name, + req->pdu.datasize, + session->sess_params.first_burst_length, + req->pdu.bhs.itt, req_hdr->scb[0]); + res = -EINVAL; + goto out_close; + } + + req->r2t_len_to_receive = be32_to_cpu(req_hdr->data_length) - + req->pdu.datasize; + + /* + * In case of residual overflow req->r2t_len_to_receive and + * req->pdu.datasize might be > req->bufflen + */ + + res = cmnd_insert_data_wait_hash(req); + + if (unsolicited_data_expected) { + req->outstanding_r2t = 1; + req->r2t_len_to_send = req->r2t_len_to_receive - + min_t(unsigned int, + session->sess_params.first_burst_length - + req->pdu.datasize, + req->r2t_len_to_receive); + } else + req->r2t_len_to_send = req->r2t_len_to_receive; + + if (likely(res == 0)) + req_add_to_write_timeout_list(req); + +out_close: + return res; +} +EXPORT_SYMBOL(iscsi_cmnd_set_write_buf); + +int cmnd_rx_continue(struct iscsi_cmnd *req) +{ + struct iscsi_conn *conn = req->conn; + struct iscsi_scsi_cmd_hdr *req_hdr = cmnd_hdr(req); + struct scst_cmd *scst_cmd = req->scst_cmd; + scst_data_direction dir; +#ifdef CONFIG_SCST_DEBUG + bool unsolicited_data_expected = false; +#endif + int res = 0; + TRACE_ENTRY(); TRACE_DBG("scsi command: %x", req_hdr->scb[0]); @@ -1857,48 +1946,7 @@ int cmnd_rx_continue(struct iscsi_cmnd *req) /* For prelim completed commands sg & K can be already set! */ if (dir & SCST_DATA_WRITE) { - req->bufflen = scst_cmd_get_write_fields(scst_cmd, &req->sg, - &req->sg_cnt); - unsolicited_data_expected = !(req_hdr->flags & ISCSI_CMD_FINAL); - - if (unlikely(session->sess_params.initial_r2t && - unsolicited_data_expected)) { - PRINT_ERROR("Initiator %s violated negotiated " - "parameters: initial R2T is required (ITT %x, " - "op %x)", session->initiator_name, - req->pdu.bhs.itt, req_hdr->scb[0]); - goto out_close; - } - - if (unlikely(!session->sess_params.immediate_data && - req->pdu.datasize)) { - PRINT_ERROR("Initiator %s violated negotiated " - "parameters: forbidden immediate data sent " - "(ITT %x, op %x)", session->initiator_name, - req->pdu.bhs.itt, req_hdr->scb[0]); - goto out_close; - } - - if (unlikely(session->sess_params.first_burst_length < req->pdu.datasize)) { - PRINT_ERROR("Initiator %s violated negotiated " - "parameters: immediate data len (%d) > " - "first_burst_length (%d) (ITT %x, op %x)", - session->initiator_name, - req->pdu.datasize, - session->sess_params.first_burst_length, - req->pdu.bhs.itt, req_hdr->scb[0]); - goto out_close; - } - - req->r2t_len_to_receive = be32_to_cpu(req_hdr->data_length) - - req->pdu.datasize; - - /* - * In case of residual overflow req->r2t_len_to_receive and - * req->pdu.datasize might be > req->bufflen - */ - - res = cmnd_insert_data_wait_hash(req); + res = iscsi_cmnd_set_write_buf(req); if (unlikely(res != 0)) { /* * We have to close connection, because otherwise a data @@ -1909,18 +1957,6 @@ int cmnd_rx_continue(struct iscsi_cmnd *req) goto out_close; } - if (unsolicited_data_expected) { - req->outstanding_r2t = 1; - req->r2t_len_to_send = req->r2t_len_to_receive - - min_t(unsigned int, - session->sess_params.first_burst_length - - req->pdu.datasize, - req->r2t_len_to_receive); - } else - req->r2t_len_to_send = req->r2t_len_to_receive; - - req_add_to_write_timeout_list(req); - if (req->pdu.datasize) { res = cmnd_prepare_recv_pdu(conn, req, 0, req->pdu.datasize); /* For performance better to send R2Ts ASAP */ @@ -3179,6 +3215,7 @@ out: TRACE_EXIT_RES(res); return res; } +EXPORT_SYMBOL(cmnd_rx_start); void cmnd_rx_end(struct iscsi_cmnd *cmnd) { @@ -3210,6 +3247,7 @@ out: TRACE_EXIT(); return; } +EXPORT_SYMBOL(cmnd_rx_end); static ssize_t iscsi_tcp_get_initiator_ip(struct iscsi_conn *conn, char *buf, int size) diff --git a/iscsi-scst/kernel/iscsi.h b/iscsi-scst/kernel/iscsi.h index 4ca1c988f..f5593320c 100644 --- a/iscsi-scst/kernel/iscsi.h +++ b/iscsi-scst/kernel/iscsi.h @@ -607,6 +607,7 @@ extern void target_del_all(void); extern int iscsi_procfs_init(void); extern void iscsi_procfs_exit(void); #else +extern int conn_sysfs_add(struct iscsi_conn *conn); extern const struct attribute *iscsi_attrs[]; extern int iscsi_add_attr(struct iscsi_target *target, const struct iscsi_kern_attr *user_info); @@ -836,4 +837,17 @@ extern int iscsi_conn_alloc(struct iscsi_session *session, extern int conn_activate(struct iscsi_conn *conn); extern void iscsi_tcp_mark_conn_closed(struct iscsi_conn *conn, int flags); extern void iscsi_tcp_conn_free(struct iscsi_conn *conn); +extern void iscsi_cmnd_init(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd, + struct iscsi_cmnd *parent); +extern struct iscsi_cmnd *iscsi_get_send_cmnd(struct iscsi_conn *conn); +extern void start_close_conn(struct iscsi_conn *conn); +extern __be32 cmnd_set_sn(struct iscsi_cmnd *cmnd, int set_stat_sn); +extern void iscsi_set_resid(struct iscsi_cmnd *rsp); +extern int iscsi_init_conn(struct iscsi_session *session, + struct iscsi_kern_conn_info *info, struct iscsi_conn *conn); +extern void req_cmnd_pre_release(struct iscsi_cmnd *req); +extern void req_cmnd_release(struct iscsi_cmnd *req); +extern struct iscsi_cmnd *create_status_rsp(struct iscsi_cmnd *req, + int status, const u8 *sense_buf, int sense_len); +extern int iscsi_cmnd_set_write_buf(struct iscsi_cmnd *req); #endif /* __ISCSI_H__ */ diff --git a/iscsi-scst/kernel/nthread.c b/iscsi-scst/kernel/nthread.c index 404de998e..665ee0da6 100644 --- a/iscsi-scst/kernel/nthread.c +++ b/iscsi-scst/kernel/nthread.c @@ -598,7 +598,7 @@ static int close_conn_thr(void *arg) } /* No locks */ -static void start_close_conn(struct iscsi_conn *conn) +void start_close_conn(struct iscsi_conn *conn) { struct task_struct *t; @@ -614,6 +614,7 @@ static void start_close_conn(struct iscsi_conn *conn) TRACE_EXIT(); return; } +EXPORT_SYMBOL(start_close_conn); static inline void iscsi_conn_init_read(struct iscsi_conn *conn, void __user *data, size_t len) @@ -638,7 +639,7 @@ static void iscsi_conn_prepare_read_ahs(struct iscsi_conn *conn, return; } -static struct iscsi_cmnd *iscsi_get_send_cmnd(struct iscsi_conn *conn) +struct iscsi_cmnd *iscsi_get_send_cmnd(struct iscsi_conn *conn) { struct iscsi_cmnd *cmnd = NULL; @@ -677,6 +678,7 @@ static struct iscsi_cmnd *iscsi_get_send_cmnd(struct iscsi_conn *conn) out: return cmnd; } +EXPORT_SYMBOL(iscsi_get_send_cmnd); /* Returns number of bytes left to receive or <0 for error */ static int do_recv(struct iscsi_conn *conn) diff --git a/iscsi-scst/kernel/target.c b/iscsi-scst/kernel/target.c index bef604c3d..17b83388f 100644 --- a/iscsi-scst/kernel/target.c +++ b/iscsi-scst/kernel/target.c @@ -346,6 +346,7 @@ void target_del_all_sess(struct iscsi_target *target, int flags) TRACE_EXIT(); return; } +EXPORT_SYMBOL(target_del_all_sess); void target_del_all(void) {