// SPDX-License-Identifier: GPL-2.0-or-later /* * iSCSI Initiator over TCP/IP Data-Path * * Copyright (C) 2004 Dmitry Yusupov * Copyright (C) 2004 Alex Aizman * Copyright (C) 2005 - 2006 Mike Christie * Copyright (C) 2006 Red Hat, Inc. All rights reserved. * maintained by open-iscsi@googlegroups.com * * See the file COPYING included with this distribution for more details. * * Credits: * Christoph Hellwig * FUJITA Tomonori * Arne Redlich * Zhenyu Wang
*/
staticbool iscsi_recv_from_iscsi_q;
module_param_named(recv_from_iscsi_q, iscsi_recv_from_iscsi_q, bool, 0644);
MODULE_PARM_DESC(recv_from_iscsi_q, "Set to true to read iSCSI data/headers from the iscsi_q workqueue. The default is false which will perform reads from the network softirq context.");
staticint iscsi_sw_tcp_dbg;
module_param_named(debug_iscsi_tcp, iscsi_sw_tcp_dbg, int,
S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug_iscsi_tcp, "Turn on debugging for iscsi_tcp module " "Set to 1 to turn on, and zero to turn off. Default is off.");
/** * iscsi_sw_sk_state_check - check socket state * @sk: socket * * If the socket is in CLOSE or CLOSE_WAIT we should * not close the connection if there is still some * data pending. * * Must be called with sk_callback_lock.
*/ staticinlineint iscsi_sw_sk_state_check(struct sock *sk)
{ struct iscsi_conn *conn = sk->sk_user_data;
/* * Use rd_desc to pass 'conn' to iscsi_tcp_recv. * We set count to 1 because we want the network layer to * hand us all the skbs that are available. iscsi_tcp_recv * handled pdus that cross buffers or pdus that still need data.
*/
rd_desc.arg.data = conn;
rd_desc.count = 1;
tcp_read_sock(sk, &rd_desc, iscsi_sw_tcp_recv);
/* If we had to (atomically) map a highmem page,
* unmap it now. */
iscsi_tcp_segment_unmap(&tcp_conn->in.segment);
/** * iscsi_sw_tcp_write_space - Called when more output buffer space is available * @sk: socket space is available for
**/ staticvoid iscsi_sw_tcp_write_space(struct sock *sk)
{ struct iscsi_conn *conn; struct iscsi_tcp_conn *tcp_conn; struct iscsi_sw_tcp_conn *tcp_sw_conn; void (*old_write_space)(struct sock *);
read_lock_bh(&sk->sk_callback_lock);
conn = sk->sk_user_data; if (!conn) {
read_unlock_bh(&sk->sk_callback_lock); return;
}
/** * iscsi_sw_tcp_xmit_segment - transmit segment * @tcp_conn: the iSCSI TCP connection * @segment: the buffer to transmnit * * This function transmits as much of the buffer as * the network layer will accept, and returns the number of * bytes transmitted. * * If CRC hashing is enabled, the function will compute the * hash as it goes. When the entire segment has been transmitted, * it will retrieve the hash value and send it as well.
*/ staticint iscsi_sw_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn, struct iscsi_segment *segment)
{ struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; struct socket *sk = tcp_sw_conn->sock; unsignedint copied = 0; int r = 0;
while (1) {
rc = iscsi_sw_tcp_xmit_segment(tcp_conn, segment); /* * We may not have been able to send data because the conn * is getting stopped. libiscsi will know so propagate err * for it to do the right thing.
*/ if (rc == -EAGAIN) return rc; elseif (rc < 0) {
rc = ISCSI_ERR_XMIT_FAILED; goto error;
} elseif (rc == 0) break;
consumed += rc;
if (segment->total_copied >= segment->total_size) { if (segment->done != NULL) {
rc = segment->done(tcp_conn, segment); if (rc != 0) goto error;
}
}
}
/* * This is called when we're done sending the header. * Simply copy the data_segment to the send segment, and return.
*/ staticint iscsi_sw_tcp_send_hdr_done(struct iscsi_tcp_conn *tcp_conn, struct iscsi_segment *segment)
{ struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
/* Clear the data segment - needs to be filled in by the
* caller using iscsi_tcp_send_data_prep() */
memset(&tcp_sw_conn->out.data_segment, 0, sizeof(struct iscsi_segment));
/* If header digest is enabled, compute the CRC and * place the digest into the same buffer. We make * sure that both iscsi_tcp_task and mtask have * sufficient room.
*/ if (conn->hdrdgst_en) {
iscsi_tcp_dgst_header(hdr, hdrlen, hdr + hdrlen);
hdrlen += ISCSI_DIGEST_SIZE;
}
/* Remember header pointer for later, when we need * to decide whether there's a payload to go along
* with the header. */
tcp_sw_conn->out.hdr = hdr;
/* * Prepare the send buffer for the payload data. * Padding and checksumming will all be taken care * of by the iscsi_segment routines.
*/ staticint
iscsi_sw_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg, unsignedint count, unsignedint offset, unsignedint len)
{ struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
u32 *tx_crcp = NULL; unsignedint hdr_spec_len;
/* Make sure the datalen matches what the caller
said he would send. */
hdr_spec_len = ntoh24(tcp_sw_conn->out.hdr->dlength);
WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
if (conn->datadgst_en)
tx_crcp = &tcp_sw_conn->tx_crc;
/* Make sure the datalen matches what the caller
said he would send. */
hdr_spec_len = ntoh24(tcp_sw_conn->out.hdr->dlength);
WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
if (conn->datadgst_en)
tx_crcp = &tcp_sw_conn->tx_crc;
/* * The iscsi transport class will make sure we are not called in * parallel with start, stop, bind and destroys. However, this can be * called twice if userspace does a stop then a destroy.
*/ if (!sock) return;
/* * Make sure we start socket shutdown now in case userspace is up * but delayed in releasing the socket.
*/
kernel_sock_shutdown(sock, SHUT_RDWR);
switch(param) { case ISCSI_PARAM_CONN_PORT: case ISCSI_PARAM_CONN_ADDRESS: case ISCSI_PARAM_LOCAL_PORT:
spin_lock_bh(&conn->session->frwd_lock); if (!conn->session->leadconn) {
spin_unlock_bh(&conn->session->frwd_lock); return -ENOTCONN;
} /* * The conn has been setup and bound, so just grab a ref * incase a destroy runs while we are in the net layer.
*/
iscsi_get_conn(conn->cls_conn);
spin_unlock_bh(&conn->session->frwd_lock);
switch (param) { case ISCSI_HOST_PARAM_IPADDRESS:
session = tcp_sw_host->session; if (!session) return -ENOTCONN;
spin_lock_bh(&session->frwd_lock);
conn = session->leadconn; if (!conn) {
spin_unlock_bh(&session->frwd_lock); return -ENOTCONN;
}
tcp_conn = conn->dd_data;
tcp_sw_conn = tcp_conn->dd_data; /* * The conn has been setup and bound, so just grab a ref * incase a destroy runs while we are in the net layer.
*/
iscsi_get_conn(conn->cls_conn);
spin_unlock_bh(&session->frwd_lock);
iscsi_session_remove(cls_session); /* * Our get_host_param needs to access the session, so remove the * host from sysfs before freeing the session to make sure userspace * is no longer accessing the callout.
*/
iscsi_host_remove(shost, false);
static umode_t iscsi_sw_tcp_attr_is_visible(int param_type, int param)
{ switch (param_type) { case ISCSI_HOST_PARAM: switch (param) { case ISCSI_HOST_PARAM_NETDEV_NAME: case ISCSI_HOST_PARAM_HWADDRESS: case ISCSI_HOST_PARAM_IPADDRESS: case ISCSI_HOST_PARAM_INITIATOR_NAME: return S_IRUGO; default: return 0;
} case ISCSI_PARAM: switch (param) { case ISCSI_PARAM_MAX_RECV_DLENGTH: case ISCSI_PARAM_MAX_XMIT_DLENGTH: case ISCSI_PARAM_HDRDGST_EN: case ISCSI_PARAM_DATADGST_EN: case ISCSI_PARAM_CONN_ADDRESS: case ISCSI_PARAM_CONN_PORT: case ISCSI_PARAM_LOCAL_PORT: case ISCSI_PARAM_EXP_STATSN: case ISCSI_PARAM_PERSISTENT_ADDRESS: case ISCSI_PARAM_PERSISTENT_PORT: case ISCSI_PARAM_PING_TMO: case ISCSI_PARAM_RECV_TMO: case ISCSI_PARAM_INITIAL_R2T_EN: case ISCSI_PARAM_MAX_R2T: case ISCSI_PARAM_IMM_DATA_EN: case ISCSI_PARAM_FIRST_BURST: case ISCSI_PARAM_MAX_BURST: case ISCSI_PARAM_PDU_INORDER_EN: case ISCSI_PARAM_DATASEQ_INORDER_EN: case ISCSI_PARAM_ERL: case ISCSI_PARAM_TARGET_NAME: case ISCSI_PARAM_TPGT: case ISCSI_PARAM_USERNAME: case ISCSI_PARAM_PASSWORD: case ISCSI_PARAM_USERNAME_IN: case ISCSI_PARAM_PASSWORD_IN: case ISCSI_PARAM_FAST_ABORT: case ISCSI_PARAM_ABORT_TMO: case ISCSI_PARAM_LU_RESET_TMO: case ISCSI_PARAM_TGT_RESET_TMO: case ISCSI_PARAM_IFACE_NAME: case ISCSI_PARAM_INITIATOR_NAME: return S_IRUGO; default: return 0;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.