summaryrefslogtreecommitdiff
path: root/drivers/target
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/target')
-rw-r--r--drivers/target/iscsi/cxgbit/cxgbit_cm.c6
-rw-r--r--drivers/target/iscsi/cxgbit/cxgbit_main.c4
-rw-r--r--drivers/target/iscsi/iscsi_target.c41
-rw-r--r--drivers/target/iscsi/iscsi_target_auth.c31
-rw-r--r--drivers/target/iscsi/iscsi_target_configfs.c1
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_login.c12
-rw-r--r--drivers/target/iscsi/iscsi_target_nego.c7
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.c72
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.h2
-rw-r--r--drivers/target/iscsi/iscsi_target_seq_pdu_list.c4
-rw-r--r--drivers/target/iscsi/iscsi_target_tpg.c4
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c10
-rw-r--r--drivers/target/loopback/tcm_loop.c46
-rw-r--r--drivers/target/sbp/sbp_target.c32
-rw-r--r--drivers/target/target_core_alua.c11
-rw-r--r--drivers/target/target_core_configfs.c149
-rw-r--r--drivers/target/target_core_device.c31
-rw-r--r--drivers/target/target_core_fabric_configfs.c66
-rw-r--r--drivers/target/target_core_fabric_lib.c90
-rw-r--r--drivers/target/target_core_file.c16
-rw-r--r--drivers/target/target_core_hba.c4
-rw-r--r--drivers/target/target_core_iblock.c26
-rw-r--r--drivers/target/target_core_internal.h4
-rw-r--r--drivers/target/target_core_pr.c80
-rw-r--r--drivers/target/target_core_pscsi.c12
-rw-r--r--drivers/target/target_core_rd.c11
-rw-r--r--drivers/target/target_core_sbc.c54
-rw-r--r--drivers/target/target_core_spc.c136
-rw-r--r--drivers/target/target_core_stat.c268
-rw-r--r--drivers/target/target_core_tmr.c2
-rw-r--r--drivers/target/target_core_tpg.c25
-rw-r--r--drivers/target/target_core_transport.c111
-rw-r--r--drivers/target/target_core_user.c32
-rw-r--r--drivers/target/target_core_xcopy.c4
-rw-r--r--drivers/target/tcm_fc/tfc_conf.c8
-rw-r--r--drivers/target/tcm_fc/tfc_sess.c4
-rw-r--r--drivers/target/tcm_remote/tcm_remote.c2
38 files changed, 928 insertions, 492 deletions
diff --git a/drivers/target/iscsi/cxgbit/cxgbit_cm.c b/drivers/target/iscsi/cxgbit/cxgbit_cm.c
index d9204c590d9a..146705845fa3 100644
--- a/drivers/target/iscsi/cxgbit/cxgbit_cm.c
+++ b/drivers/target/iscsi/cxgbit/cxgbit_cm.c
@@ -79,7 +79,7 @@ static struct np_info *
cxgbit_np_hash_add(struct cxgbit_device *cdev, struct cxgbit_np *cnp,
unsigned int stid)
{
- struct np_info *p = kzalloc(sizeof(*p), GFP_KERNEL);
+ struct np_info *p = kzalloc_obj(*p);
if (p) {
int bucket = cxgbit_np_hashfn(cnp);
@@ -431,7 +431,7 @@ int cxgbit_setup_np(struct iscsi_np *np, struct sockaddr_storage *ksockaddr)
(ksockaddr->ss_family != AF_INET6))
return -EINVAL;
- cnp = kzalloc(sizeof(*cnp), GFP_KERNEL);
+ cnp = kzalloc_obj(*cnp);
if (!cnp)
return -ENOMEM;
@@ -1288,7 +1288,7 @@ cxgbit_pass_accept_req(struct cxgbit_device *cdev, struct sk_buff *skb)
goto reject;
}
- csk = kzalloc(sizeof(*csk), GFP_ATOMIC);
+ csk = kzalloc_obj(*csk, GFP_ATOMIC);
if (!csk) {
dst_release(dst);
goto rel_skb;
diff --git a/drivers/target/iscsi/cxgbit/cxgbit_main.c b/drivers/target/iscsi/cxgbit/cxgbit_main.c
index 2c1950df3b3e..b6036820fc95 100644
--- a/drivers/target/iscsi/cxgbit/cxgbit_main.c
+++ b/drivers/target/iscsi/cxgbit/cxgbit_main.c
@@ -57,7 +57,7 @@ static void *cxgbit_uld_add(const struct cxgb4_lld_info *lldi)
if (is_t4(lldi->adapter_type))
return ERR_PTR(-ENODEV);
- cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+ cdev = kzalloc_obj(*cdev);
if (!cdev)
return ERR_PTR(-ENOMEM);
@@ -646,7 +646,7 @@ cxgbit_dcbevent_notify(struct notifier_block *nb, unsigned long action,
struct cxgbit_dcb_work *dcb_work;
struct dcb_app_type *dcb_app = data;
- dcb_work = kzalloc(sizeof(*dcb_work), GFP_ATOMIC);
+ dcb_work = kzalloc_obj(*dcb_work, GFP_ATOMIC);
if (!dcb_work)
return NOTIFY_DONE;
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index a2dde08c8a62..124ff269b8e7 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -121,7 +121,7 @@ struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *buf)
return ERR_PTR(-EINVAL);
}
- tiqn = kzalloc(sizeof(*tiqn), GFP_KERNEL);
+ tiqn = kzalloc_obj(*tiqn);
if (!tiqn)
return ERR_PTR(-ENOMEM);
@@ -352,7 +352,7 @@ struct iscsi_np *iscsit_add_np(
return np;
}
- np = kzalloc(sizeof(*np), GFP_KERNEL);
+ np = kzalloc_obj(*np);
if (!np) {
mutex_unlock(&np_lock);
return ERR_PTR(-ENOMEM);
@@ -674,7 +674,7 @@ static int __init iscsi_target_init_module(void)
int ret = 0, size;
pr_debug("iSCSI-Target "ISCSIT_VERSION"\n");
- iscsit_global = kzalloc(sizeof(*iscsit_global), GFP_KERNEL);
+ iscsit_global = kzalloc_obj(*iscsit_global);
if (!iscsit_global)
return -1;
@@ -981,7 +981,7 @@ static int iscsit_allocate_iovecs(struct iscsit_cmd *cmd)
u32 iov_count = max(1UL, DIV_ROUND_UP(cmd->se_cmd.data_length, PAGE_SIZE));
iov_count += ISCSI_IOV_DATA_BUFFER;
- cmd->iov_data = kcalloc(iov_count, sizeof(*cmd->iov_data), GFP_KERNEL);
+ cmd->iov_data = kzalloc_objs(*cmd->iov_data, iov_count);
if (!cmd->iov_data)
return -ENOMEM;
@@ -995,6 +995,7 @@ int iscsit_setup_scsi_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
int data_direction, payload_length;
struct iscsi_ecdb_ahdr *ecdb_ahdr;
struct iscsi_scsi_req *hdr;
+ u16 ahslength, cdb_length;
int iscsi_task_attr;
unsigned char *cdb;
int sam_task_attr;
@@ -1108,14 +1109,27 @@ int iscsit_setup_scsi_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
ISCSI_REASON_CMD_NOT_SUPPORTED, buf);
}
- cdb = kmalloc(be16_to_cpu(ecdb_ahdr->ahslength) + 15,
- GFP_KERNEL);
+ ahslength = be16_to_cpu(ecdb_ahdr->ahslength);
+ if (!ahslength) {
+ pr_err("Extended CDB AHS with zero length, protocol error.\n");
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_PROTOCOL_ERROR, buf);
+ }
+ if (ahslength > (hdr->hlength * 4) - 3) {
+ pr_err("Extended CDB AHS length %u exceeds available PDU buffer.\n",
+ ahslength);
+ return iscsit_add_reject_cmd(cmd,
+ ISCSI_REASON_PROTOCOL_ERROR, buf);
+ }
+
+ cdb_length = ahslength - 1 + ISCSI_CDB_SIZE;
+
+ cdb = kmalloc(cdb_length, GFP_KERNEL);
if (cdb == NULL)
return iscsit_add_reject_cmd(cmd,
ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
memcpy(cdb, hdr->cdb, ISCSI_CDB_SIZE);
- memcpy(cdb + ISCSI_CDB_SIZE, ecdb_ahdr->ecdb,
- be16_to_cpu(ecdb_ahdr->ahslength) - 1);
+ memcpy(cdb + ISCSI_CDB_SIZE, ecdb_ahdr->ecdb, cdb_length - ISCSI_CDB_SIZE);
}
data_direction = (hdr->flags & ISCSI_FLAG_CMD_WRITE) ? DMA_TO_DEVICE :
@@ -1519,8 +1533,10 @@ __iscsit_check_dataout_hdr(struct iscsit_conn *conn, void *buf,
*/
if (se_cmd->transport_state & CMD_T_ABORTED) {
if (hdr->flags & ISCSI_FLAG_CMD_FINAL &&
- --cmd->outstanding_r2ts < 1)
+ --cmd->outstanding_r2ts < 1) {
iscsit_stop_dataout_timer(cmd);
+ target_complete_cmd(se_cmd, SAM_STAT_TASK_ABORTED);
+ }
return iscsit_dump_data_payload(conn, payload_length, 1);
}
@@ -1992,7 +2008,7 @@ iscsit_handle_task_mgt_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
hdr->refcmdsn = cpu_to_be32(ISCSI_RESERVED_TAG);
cmd->data_direction = DMA_NONE;
- cmd->tmr_req = kzalloc(sizeof(*cmd->tmr_req), GFP_KERNEL);
+ cmd->tmr_req = kzalloc_obj(*cmd->tmr_req);
if (!cmd->tmr_req) {
return iscsit_add_reject_cmd(cmd,
ISCSI_REASON_BOOKMARK_NO_RESOURCES,
@@ -2281,7 +2297,9 @@ iscsit_handle_text_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
goto reject;
if (conn->conn_ops->DataDigest) {
- data_crc = iscsit_crc_buf(text_in, rx_size, 0, NULL);
+ data_crc = iscsit_crc_buf(text_in,
+ ALIGN(payload_length, 4),
+ 0, NULL);
if (checksum != data_crc) {
pr_err("Text data CRC32C DataDigest"
" 0x%08x does not match computed"
@@ -2300,6 +2318,7 @@ iscsit_handle_text_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
" Command CmdSN: 0x%08x due to"
" DataCRC error.\n", hdr->cmdsn);
kfree(text_in);
+ cmd->text_in_ptr = NULL;
return 0;
}
} else {
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c
index c8a248bd11be..f3c0cdd31830 100644
--- a/drivers/target/iscsi/iscsi_target_auth.c
+++ b/drivers/target/iscsi/iscsi_target_auth.c
@@ -9,9 +9,11 @@
******************************************************************************/
#include <crypto/hash.h>
+#include <crypto/utils.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/err.h>
+#include <linux/hex.h>
#include <linux/random.h>
#include <linux/scatterlist.h>
#include <target/iscsi/iscsi_target_core.h>
@@ -151,7 +153,7 @@ static struct iscsi_chap *chap_server_open(
return NULL;
}
- conn->auth_protocol = kzalloc(sizeof(struct iscsi_chap), GFP_KERNEL);
+ conn->auth_protocol = kzalloc_obj(struct iscsi_chap);
if (!conn->auth_protocol)
return NULL;
@@ -339,13 +341,22 @@ static int chap_server_compute_hash(
goto out;
}
break;
- case BASE64:
+ case BASE64: {
+ size_t r_len = strlen(chap_r);
+
+ while (r_len > 0 && chap_r[r_len - 1] == '=')
+ r_len--;
+ if (r_len > DIV_ROUND_UP(chap->digest_size * 4, 3)) {
+ pr_err("Malformed CHAP_R: base64 payload too long\n");
+ goto out;
+ }
if (chap_base64_decode(client_digest, chap_r, strlen(chap_r)) !=
chap->digest_size) {
pr_err("Malformed CHAP_R: invalid BASE64\n");
goto out;
}
break;
+ }
default:
pr_err("Could not find CHAP_R\n");
goto out;
@@ -398,7 +409,7 @@ static int chap_server_compute_hash(
pr_debug("[server] %s Server Digest: %s\n",
chap->digest_name, response);
- if (memcmp(server_digest, client_digest, chap->digest_size) != 0) {
+ if (crypto_memneq(server_digest, client_digest, chap->digest_size)) {
pr_debug("[server] %s Digests do not match!\n\n",
chap->digest_name);
goto out;
@@ -428,9 +439,11 @@ static int chap_server_compute_hash(
}
if (type == HEX)
- ret = kstrtoul(&identifier[2], 0, &id);
+ ret = kstrtoul(identifier, 16, &id);
+ else if (type == DECIMAL)
+ ret = kstrtoul(identifier, 10, &id);
else
- ret = kstrtoul(identifier, 0, &id);
+ ret = -EINVAL;
if (ret < 0) {
pr_err("kstrtoul() failed for CHAP identifier: %d\n", ret);
@@ -472,6 +485,14 @@ static int chap_server_compute_hash(
}
break;
case BASE64:
+ /*
+ * No overflow check needed: initiatorchg_binhex is
+ * CHAP_CHALLENGE_STR_LEN bytes and extract_param() caps
+ * initiatorchg at CHAP_CHALLENGE_STR_LEN characters, so
+ * the decoded output is at most DIV_ROUND_UP(
+ * (CHAP_CHALLENGE_STR_LEN - 1) * 3, 4) bytes, which is
+ * less than CHAP_CHALLENGE_STR_LEN.
+ */
initiatorchg_len = chap_base64_decode(initiatorchg_binhex,
initiatorchg,
strlen(initiatorchg));
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index efe8cdb20060..704ec94383c3 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -1591,6 +1591,7 @@ const struct target_core_fabric_ops iscsi_ops = {
.write_pending_must_be_called = 1,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_DIRECT_SUBMIT,
.direct_submit_supp = 1,
};
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c
index 56d78af7cec7..bda254a0d4ed 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.c
+++ b/drivers/target/iscsi/iscsi_target_erl2.c
@@ -268,7 +268,7 @@ int iscsit_prepare_cmds_for_reallegiance(struct iscsit_conn *conn)
* (struct iscsit_cmd->cr) so we need to allocate this before preparing the
* connection's command list for connection recovery.
*/
- cr = kzalloc(sizeof(struct iscsi_conn_recovery), GFP_KERNEL);
+ cr = kzalloc_obj(struct iscsi_conn_recovery);
if (!cr) {
pr_err("Unable to allocate memory for"
" struct iscsi_conn_recovery.\n");
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 53aca059dc16..c282b6a70296 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -38,7 +38,7 @@ static struct iscsi_login *iscsi_login_init_conn(struct iscsit_conn *conn)
{
struct iscsi_login *login;
- login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL);
+ login = kzalloc_obj(struct iscsi_login);
if (!login) {
pr_err("Unable to allocate memory for struct iscsi_login.\n");
return NULL;
@@ -47,7 +47,7 @@ static struct iscsi_login *iscsi_login_init_conn(struct iscsit_conn *conn)
login->conn = conn;
login->first_request = 1;
- login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
+ login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS + 1, GFP_KERNEL);
if (!login->req_buf) {
pr_err("Unable to allocate memory for response buffer.\n");
goto out_login;
@@ -219,7 +219,7 @@ static int iscsi_login_zero_tsih_s1(
struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf;
int ret;
- sess = kzalloc(sizeof(struct iscsit_session), GFP_KERNEL);
+ sess = kzalloc_obj(struct iscsit_session);
if (!sess) {
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
ISCSI_LOGIN_STATUS_NO_RESOURCES);
@@ -267,7 +267,7 @@ static int iscsi_login_zero_tsih_s1(
*/
atomic_set(&sess->max_cmd_sn, be32_to_cpu(pdu->cmdsn));
- sess->sess_ops = kzalloc(sizeof(struct iscsi_sess_ops), GFP_KERNEL);
+ sess->sess_ops = kzalloc_obj(struct iscsi_sess_ops);
if (!sess->sess_ops) {
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
ISCSI_LOGIN_STATUS_NO_RESOURCES);
@@ -1002,7 +1002,7 @@ static struct iscsit_conn *iscsit_alloc_conn(struct iscsi_np *np)
{
struct iscsit_conn *conn;
- conn = kzalloc(sizeof(struct iscsit_conn), GFP_KERNEL);
+ conn = kzalloc_obj(struct iscsit_conn);
if (!conn) {
pr_err("Could not allocate memory for new connection\n");
return NULL;
@@ -1040,7 +1040,7 @@ static struct iscsit_conn *iscsit_alloc_conn(struct iscsi_np *np)
if (iscsit_conn_set_transport(conn, np->np_transport) < 0)
goto free_conn;
- conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL);
+ conn->conn_ops = kzalloc_obj(struct iscsi_conn_ops);
if (!conn->conn_ops) {
pr_err("Unable to allocate memory for struct iscsi_conn_ops.\n");
goto put_transport;
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index 832588f21f91..b03ed154ca34 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -899,10 +899,14 @@ static int iscsi_target_handle_csg_zero(
SENDER_TARGET,
login->rsp_buf,
&login->rsp_length,
+ MAX_KEY_VALUE_PAIRS,
conn->param_list,
conn->tpg->tpg_attrib.login_keys_workaround);
- if (ret < 0)
+ if (ret < 0) {
+ iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+ ISCSI_LOGIN_STATUS_INIT_ERR);
return -1;
+ }
if (!iscsi_check_negotiated_keys(conn->param_list)) {
bool auth_required = iscsi_conn_auth_required(conn);
@@ -986,6 +990,7 @@ static int iscsi_target_handle_csg_one(struct iscsit_conn *conn, struct iscsi_lo
SENDER_TARGET,
login->rsp_buf,
&login->rsp_length,
+ MAX_KEY_VALUE_PAIRS,
conn->param_list,
conn->tpg->tpg_attrib.login_keys_workaround);
if (ret < 0) {
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 1d4e1788e073..2b318b13268e 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -73,7 +73,7 @@ static struct iscsi_param *iscsi_set_default_param(struct iscsi_param_list *para
{
struct iscsi_param *param = NULL;
- param = kzalloc(sizeof(struct iscsi_param), GFP_KERNEL);
+ param = kzalloc_obj(struct iscsi_param);
if (!param) {
pr_err("Unable to allocate memory for parameter.\n");
goto out;
@@ -148,7 +148,7 @@ int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr)
struct iscsi_param *param = NULL;
struct iscsi_param_list *pl;
- pl = kzalloc(sizeof(struct iscsi_param_list), GFP_KERNEL);
+ pl = kzalloc_obj(struct iscsi_param_list);
if (!pl) {
pr_err("Unable to allocate memory for"
" struct iscsi_param_list.\n");
@@ -519,7 +519,7 @@ int iscsi_copy_param_list(
struct iscsi_param *new_param = NULL;
struct iscsi_param_list *param_list = NULL;
- param_list = kzalloc(sizeof(struct iscsi_param_list), GFP_KERNEL);
+ param_list = kzalloc_obj(struct iscsi_param_list);
if (!param_list) {
pr_err("Unable to allocate memory for struct iscsi_param_list.\n");
return -ENOMEM;
@@ -535,7 +535,7 @@ int iscsi_copy_param_list(
continue;
}
- new_param = kzalloc(sizeof(struct iscsi_param), GFP_KERNEL);
+ new_param = kzalloc_obj(struct iscsi_param);
if (!new_param) {
pr_err("Unable to allocate memory for struct iscsi_param.\n");
goto err_out;
@@ -670,7 +670,7 @@ static int iscsi_add_notunderstood_response(
return -1;
}
- extra_response = kzalloc(sizeof(struct iscsi_extra_response), GFP_KERNEL);
+ extra_response = kzalloc_obj(struct iscsi_extra_response);
if (!extra_response) {
pr_err("Unable to allocate memory for"
" struct iscsi_extra_response.\n");
@@ -1371,19 +1371,42 @@ free_buffer:
return -1;
}
+/*
+ * Append "key=value" plus a trailing NUL into @textbuf at *@length.
+ * Returns 0 on success and advances *@length, or -EMSGSIZE if the
+ * record (including the NUL) would not fit in the remaining buffer.
+ */
+static int iscsi_encode_text_record(char *textbuf, u32 *length,
+ u32 textbuf_size,
+ const char *key, const char *value)
+{
+ int n;
+ u32 avail;
+
+ if (*length >= textbuf_size)
+ return -EMSGSIZE;
+
+ avail = textbuf_size - *length;
+ n = snprintf(textbuf + *length, avail, "%s=%s", key, value);
+ if (n < 0 || (u32)n + 1 > avail)
+ return -EMSGSIZE;
+
+ *length += n + 1;
+ return 0;
+}
+
int iscsi_encode_text_output(
u8 phase,
u8 sender,
char *textbuf,
u32 *length,
+ u32 textbuf_size,
struct iscsi_param_list *param_list,
bool keys_workaround)
{
- char *output_buf = NULL;
struct iscsi_extra_response *er;
struct iscsi_param *param;
-
- output_buf = textbuf + *length;
+ int ret;
if (iscsi_enforce_integrity_rules(phase, param_list) < 0)
return -1;
@@ -1395,10 +1418,12 @@ int iscsi_encode_text_output(
!IS_PSTATE_RESPONSE_SENT(param) &&
!IS_PSTATE_REPLY_OPTIONAL(param) &&
(param->phase & phase)) {
- *length += sprintf(output_buf, "%s=%s",
- param->name, param->value);
- *length += 1;
- output_buf = textbuf + *length;
+ ret = iscsi_encode_text_record(textbuf, length,
+ textbuf_size,
+ param->name,
+ param->value);
+ if (ret < 0)
+ goto err_overflow;
SET_PSTATE_RESPONSE_SENT(param);
pr_debug("Sending key: %s=%s\n",
param->name, param->value);
@@ -1408,10 +1433,12 @@ int iscsi_encode_text_output(
!IS_PSTATE_ACCEPTOR(param) &&
!IS_PSTATE_PROPOSER(param) &&
(param->phase & phase)) {
- *length += sprintf(output_buf, "%s=%s",
- param->name, param->value);
- *length += 1;
- output_buf = textbuf + *length;
+ ret = iscsi_encode_text_record(textbuf, length,
+ textbuf_size,
+ param->name,
+ param->value);
+ if (ret < 0)
+ goto err_overflow;
SET_PSTATE_PROPOSER(param);
iscsi_check_proposer_for_optional_reply(param,
keys_workaround);
@@ -1421,14 +1448,21 @@ int iscsi_encode_text_output(
}
list_for_each_entry(er, &param_list->extra_response_list, er_list) {
- *length += sprintf(output_buf, "%s=%s", er->key, er->value);
- *length += 1;
- output_buf = textbuf + *length;
+ ret = iscsi_encode_text_record(textbuf, length, textbuf_size,
+ er->key, er->value);
+ if (ret < 0)
+ goto err_overflow;
pr_debug("Sending key: %s=%s\n", er->key, er->value);
}
iscsi_release_extra_responses(param_list);
return 0;
+
+err_overflow:
+ pr_err("iSCSI login response buffer (%u bytes) exhausted, dropping login.\n",
+ textbuf_size);
+ iscsi_release_extra_responses(param_list);
+ return -1;
}
int iscsi_check_negotiated_keys(struct iscsi_param_list *param_list)
diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h
index c672a971fcb7..38d2238dfe08 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.h
+++ b/drivers/target/iscsi/iscsi_target_parameters.h
@@ -43,7 +43,7 @@ extern struct iscsi_param *iscsi_find_param_from_key(char *, struct iscsi_param_
extern int iscsi_extract_key_value(char *, char **, char **);
extern int iscsi_update_param_value(struct iscsi_param *, char *);
extern int iscsi_decode_text_input(u8, u8, char *, u32, struct iscsit_conn *);
-extern int iscsi_encode_text_output(u8, u8, char *, u32 *,
+extern int iscsi_encode_text_output(u8, u8, char *, u32 *, u32,
struct iscsi_param_list *, bool);
extern int iscsi_check_negotiated_keys(struct iscsi_param_list *);
extern void iscsi_set_connection_parameters(struct iscsi_conn_ops *,
diff --git a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
index 66de2b8de463..75c37c8866c8 100644
--- a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
+++ b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
@@ -535,7 +535,7 @@ int iscsit_build_pdu_and_seq_lists(
iscsit_determine_counts_for_list(cmd, &bl, &seq_count, &pdu_count);
if (!conn->sess->sess_ops->DataSequenceInOrder) {
- seq = kcalloc(seq_count, sizeof(struct iscsi_seq), GFP_ATOMIC);
+ seq = kzalloc_objs(struct iscsi_seq, seq_count, GFP_ATOMIC);
if (!seq) {
pr_err("Unable to allocate struct iscsi_seq list\n");
return -ENOMEM;
@@ -545,7 +545,7 @@ int iscsit_build_pdu_and_seq_lists(
}
if (!conn->sess->sess_ops->DataPDUInOrder) {
- pdu = kcalloc(pdu_count, sizeof(struct iscsi_pdu), GFP_ATOMIC);
+ pdu = kzalloc_objs(struct iscsi_pdu, pdu_count, GFP_ATOMIC);
if (!pdu) {
pr_err("Unable to allocate struct iscsi_pdu list.\n");
kfree(seq);
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c
index bf06cfdfb012..99772364c88e 100644
--- a/drivers/target/iscsi/iscsi_target_tpg.c
+++ b/drivers/target/iscsi/iscsi_target_tpg.c
@@ -26,7 +26,7 @@ struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *tiqn, u1
{
struct iscsi_portal_group *tpg;
- tpg = kzalloc(sizeof(struct iscsi_portal_group), GFP_KERNEL);
+ tpg = kzalloc_obj(struct iscsi_portal_group);
if (!tpg) {
pr_err("Unable to allocate struct iscsi_portal_group\n");
return NULL;
@@ -464,7 +464,7 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal(
}
}
- tpg_np = kzalloc(sizeof(struct iscsi_tpg_np), GFP_KERNEL);
+ tpg_np = kzalloc_obj(struct iscsi_tpg_np);
if (!tpg_np) {
pr_err("Unable to allocate memory for"
" struct iscsi_tpg_np.\n");
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 5e6cf34929b5..c1888c42afdd 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -741,8 +741,11 @@ void iscsit_dec_session_usage_count(struct iscsit_session *sess)
spin_lock_bh(&sess->session_usage_lock);
sess->session_usage_count--;
- if (!sess->session_usage_count && sess->session_waiting_on_uc)
+ if (!sess->session_usage_count && sess->session_waiting_on_uc) {
+ spin_unlock_bh(&sess->session_usage_lock);
complete(&sess->session_waiting_on_uc_comp);
+ return;
+ }
spin_unlock_bh(&sess->session_usage_lock);
}
@@ -810,8 +813,11 @@ void iscsit_dec_conn_usage_count(struct iscsit_conn *conn)
spin_lock_bh(&conn->conn_usage_lock);
conn->conn_usage_count--;
- if (!conn->conn_usage_count && conn->conn_waiting_on_uc)
+ if (!conn->conn_usage_count && conn->conn_waiting_on_uc) {
+ spin_unlock_bh(&conn->conn_usage_lock);
complete(&conn->conn_waiting_on_uc_comp);
+ return;
+ }
spin_unlock_bh(&conn->conn_usage_lock);
}
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index 01a8e349dc4d..d29830b951f7 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -26,6 +26,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/configfs.h>
+#include <linux/blk-mq.h>
#include <scsi/scsi.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_host.h>
@@ -165,7 +166,8 @@ out_done:
* ->queuecommand can be and usually is called from interrupt context, so
* defer the actual submission to a workqueue.
*/
-static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
+static enum scsi_qc_status tcm_loop_queuecommand(struct Scsi_Host *sh,
+ struct scsi_cmnd *sc)
{
struct tcm_loop_cmd *tl_cmd = scsi_cmd_priv(sc);
@@ -268,30 +270,6 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc)
return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED;
}
-static int tcm_loop_target_reset(struct scsi_cmnd *sc)
-{
- struct tcm_loop_hba *tl_hba;
- struct tcm_loop_tpg *tl_tpg;
-
- /*
- * Locate the tcm_loop_hba_t pointer
- */
- tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
- if (!tl_hba) {
- pr_err("Unable to perform device reset without active I_T Nexus\n");
- return FAILED;
- }
- /*
- * Locate the tl_tpg pointer from TargetID in sc->device->id
- */
- tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
- if (tl_tpg) {
- tl_tpg->tl_transport_status = TCM_TRANSPORT_ONLINE;
- return SUCCESS;
- }
- return FAILED;
-}
-
static const struct scsi_host_template tcm_loop_driver_template = {
.show_info = tcm_loop_show_info,
.proc_name = "tcm_loopback",
@@ -300,7 +278,6 @@ static const struct scsi_host_template tcm_loop_driver_template = {
.change_queue_depth = scsi_change_queue_depth,
.eh_abort_handler = tcm_loop_abort_task,
.eh_device_reset_handler = tcm_loop_device_reset,
- .eh_target_reset_handler = tcm_loop_target_reset,
.this_id = -1,
.sg_tablesize = 256,
.max_sectors = 0xFFFF,
@@ -352,6 +329,7 @@ static int tcm_loop_driver_probe(struct device *dev)
if (error) {
pr_err("%s: scsi_add_host failed\n", __func__);
scsi_host_put(sh);
+ tl_hba->sh = NULL;
return -ENODEV;
}
return 0;
@@ -365,8 +343,10 @@ static void tcm_loop_driver_remove(struct device *dev)
tl_hba = to_tcm_loop_hba(dev);
sh = tl_hba->sh;
- scsi_remove_host(sh);
- scsi_host_put(sh);
+ if (sh) {
+ scsi_remove_host(sh);
+ scsi_host_put(sh);
+ }
}
static void tcm_loop_release_adapter(struct device *dev)
@@ -395,6 +375,11 @@ static int tcm_loop_setup_hba_bus(struct tcm_loop_hba *tl_hba, int tcm_loop_host
return -ENODEV;
}
+ if (!tl_hba->sh) {
+ device_unregister(&tl_hba->dev);
+ return -ENODEV;
+ }
+
return 0;
}
@@ -692,7 +677,7 @@ static int tcm_loop_make_nexus(
return -EEXIST;
}
- tl_nexus = kzalloc(sizeof(*tl_nexus), GFP_KERNEL);
+ tl_nexus = kzalloc_obj(*tl_nexus);
if (!tl_nexus)
return -ENOMEM;
@@ -993,7 +978,7 @@ static struct se_wwn *tcm_loop_make_scsi_hba(
char *ptr;
int ret, off = 0;
- tl_hba = kzalloc(sizeof(*tl_hba), GFP_KERNEL);
+ tl_hba = kzalloc_obj(*tl_hba);
if (!tl_hba)
return ERR_PTR(-ENOMEM);
@@ -1106,6 +1091,7 @@ static const struct target_core_fabric_ops loop_ops = {
.tfc_wwn_attrs = tcm_loop_wwn_attrs,
.tfc_tpg_base_attrs = tcm_loop_tpg_attrs,
.tfc_tpg_attrib_attrs = tcm_loop_tpg_attrib_attrs,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_QUEUE_SUBMIT,
.direct_submit_supp = 0,
};
diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c
index 3b89b5a70331..896fc0f0379f 100644
--- a/drivers/target/sbp/sbp_target.c
+++ b/drivers/target/sbp/sbp_target.c
@@ -5,8 +5,7 @@
* Copyright (C) 2011 Chris Boot <bootc@bootc.net>
*/
-#define KMSG_COMPONENT "sbp_target"
-#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+#define pr_fmt(fmt) "sbp_target: " fmt
#include <linux/kernel.h>
#include <linux/module.h>
@@ -187,7 +186,7 @@ static struct sbp_session *sbp_session_create(
snprintf(guid_str, sizeof(guid_str), "%016llx", guid);
- sess = kmalloc(sizeof(*sess), GFP_KERNEL);
+ sess = kmalloc_obj(*sess);
if (!sess)
return ERR_PTR(-ENOMEM);
@@ -392,7 +391,7 @@ static void sbp_management_request_login(
1 << LOGIN_ORB_RECONNECT(be32_to_cpu(req->orb.misc)),
tport->max_reconnect_timeout) - 1;
- login = kmalloc(sizeof(*login), GFP_KERNEL);
+ login = kmalloc_obj(*login);
if (!login) {
pr_err("failed to allocate login descriptor\n");
@@ -429,7 +428,7 @@ static void sbp_management_request_login(
spin_unlock_bh(&sess->lock);
already_logged_in:
- response = kzalloc(sizeof(*response), GFP_KERNEL);
+ response = kzalloc_obj(*response);
if (!response) {
pr_err("failed to allocate login response block\n");
@@ -730,7 +729,7 @@ static int tgt_agent_rw_orb_pointer(struct fw_card *card, int tcode, void *data,
pr_debug("tgt_agent ORB_POINTER write: 0x%llx\n",
agent->orb_pointer);
- queue_work(system_unbound_wq, &agent->work);
+ queue_work(system_dfl_wq, &agent->work);
return RCODE_COMPLETE;
@@ -764,7 +763,7 @@ static int tgt_agent_rw_doorbell(struct fw_card *card, int tcode, void *data,
pr_debug("tgt_agent DOORBELL\n");
- queue_work(system_unbound_wq, &agent->work);
+ queue_work(system_dfl_wq, &agent->work);
return RCODE_COMPLETE;
@@ -990,7 +989,7 @@ static void tgt_agent_fetch_work(struct work_struct *work)
if (tgt_agent_check_active(agent) && !doorbell) {
INIT_WORK(&req->work, tgt_agent_process_work);
- queue_work(system_unbound_wq, &req->work);
+ queue_work(system_dfl_wq, &req->work);
} else {
/* don't process this request, just check next_ORB */
sbp_free_request(req);
@@ -1015,7 +1014,7 @@ static struct sbp_target_agent *sbp_target_agent_register(
struct sbp_target_agent *agent;
int ret;
- agent = kmalloc(sizeof(*agent), GFP_KERNEL);
+ agent = kmalloc_obj(*agent);
if (!agent)
return ERR_PTR(-ENOMEM);
@@ -1604,7 +1603,7 @@ static void sbp_mgt_agent_rw(struct fw_card *card,
rcode = RCODE_CONFLICT_ERROR;
goto out;
}
- req = kzalloc(sizeof(*req), GFP_ATOMIC);
+ req = kzalloc_obj(*req, GFP_ATOMIC);
if (!req) {
rcode = RCODE_CONFLICT_ERROR;
goto out;
@@ -1618,7 +1617,7 @@ static void sbp_mgt_agent_rw(struct fw_card *card,
agent->orb_offset = sbp2_pointer_to_addr(ptr);
agent->request = req;
- queue_work(system_unbound_wq, &agent->work);
+ queue_work(system_dfl_wq, &agent->work);
rcode = RCODE_COMPLETE;
} else if (tcode == TCODE_READ_BLOCK_REQUEST) {
addr_to_sbp2_pointer(agent->orb_offset, ptr);
@@ -1637,7 +1636,7 @@ static struct sbp_management_agent *sbp_management_agent_register(
int ret;
struct sbp_management_agent *agent;
- agent = kmalloc(sizeof(*agent), GFP_KERNEL);
+ agent = kmalloc_obj(*agent);
if (!agent)
return ERR_PTR(-ENOMEM);
@@ -1961,12 +1960,12 @@ static struct se_portal_group *sbp_make_tpg(struct se_wwn *wwn,
container_of(wwn, struct sbp_tport, tport_wwn);
struct sbp_tpg *tpg;
- unsigned long tpgt;
+ u16 tpgt;
int ret;
if (strstr(name, "tpgt_") != name)
return ERR_PTR(-EINVAL);
- if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)
+ if (kstrtou16(name + 5, 10, &tpgt))
return ERR_PTR(-EINVAL);
if (tport->tpg) {
@@ -1974,7 +1973,7 @@ static struct se_portal_group *sbp_make_tpg(struct se_wwn *wwn,
return ERR_PTR(-EBUSY);
}
- tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
+ tpg = kzalloc_obj(*tpg);
if (!tpg)
return ERR_PTR(-ENOMEM);
@@ -2031,7 +2030,7 @@ static struct se_wwn *sbp_make_tport(
if (sbp_parse_wwn(name, &guid) < 0)
return ERR_PTR(-EINVAL);
- tport = kzalloc(sizeof(*tport), GFP_KERNEL);
+ tport = kzalloc_obj(*tport);
if (!tport)
return ERR_PTR(-ENOMEM);
@@ -2279,6 +2278,7 @@ static const struct target_core_fabric_ops sbp_ops = {
.tfc_tpg_base_attrs = sbp_tpg_base_attrs,
.tfc_tpg_attrib_attrs = sbp_tpg_attrib_attrs,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_DIRECT_SUBMIT,
.direct_submit_supp = 1,
};
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 10250aca5a81..140154d93c43 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -18,6 +18,8 @@
#include <linux/fcntl.h>
#include <linux/file.h>
#include <linux/fs.h>
+#include <linux/fs_struct.h>
+#include <linux/kthread.h>
#include <scsi/scsi_proto.h>
#include <linux/unaligned.h>
@@ -856,10 +858,17 @@ static int core_alua_write_tpg_metadata(
unsigned char *md_buf,
u32 md_buf_len)
{
- struct file *file = filp_open(path, O_RDWR | O_CREAT | O_TRUNC, 0600);
+ struct file *file;
loff_t pos = 0;
int ret;
+ if (tsk_is_kthread(current)) {
+ scoped_with_init_fs()
+ file = filp_open(path, O_RDWR | O_CREAT | O_TRUNC, 0600);
+ } else {
+ file = filp_open(path, O_RDWR | O_CREAT | O_TRUNC, 0600);
+ }
+
if (IS_ERR(file)) {
pr_err("filp_open(%s) for ALUA metadata failed\n", path);
return -ENODEV;
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 9e51c535ba8c..2b19a956007b 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -108,8 +108,8 @@ static ssize_t target_core_item_dbroot_store(struct config_item *item,
const char *page, size_t count)
{
ssize_t read_bytes;
- struct file *fp;
ssize_t r = -EINVAL;
+ struct path path = {};
mutex_lock(&target_devices_lock);
if (target_devices) {
@@ -131,17 +131,14 @@ static ssize_t target_core_item_dbroot_store(struct config_item *item,
db_root_stage[read_bytes - 1] = '\0';
/* validate new db root before accepting it */
- fp = filp_open(db_root_stage, O_RDONLY, 0);
- if (IS_ERR(fp)) {
+ r = kern_path(db_root_stage, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
+ if (r) {
pr_err("db_root: cannot open: %s\n", db_root_stage);
+ if (r == -ENOTDIR)
+ pr_err("db_root: not a directory: %s\n", db_root_stage);
goto unlock;
}
- if (!S_ISDIR(file_inode(fp)->i_mode)) {
- filp_close(fp, NULL);
- pr_err("db_root: not a directory: %s\n", db_root_stage);
- goto unlock;
- }
- filp_close(fp, NULL);
+ path_put(&path);
strscpy(db_root, db_root_stage);
pr_debug("Target_Core_ConfigFS: db_root set to %s\n", db_root);
@@ -288,7 +285,7 @@ static void target_core_deregister_fabric(
config_item_put(item);
}
-static struct configfs_group_operations target_core_fabric_group_ops = {
+static const struct configfs_group_operations target_core_fabric_group_ops = {
.make_group = &target_core_register_fabric,
.drop_item = &target_core_deregister_fabric,
};
@@ -475,12 +472,12 @@ int target_register_template(const struct target_core_fabric_ops *fo)
if (ret)
return ret;
- tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL);
+ tf = kzalloc_obj(struct target_fabric_configfs);
if (!tf) {
pr_err("%s: could not allocate memory!\n", __func__);
return -ENOMEM;
}
- tfo = kzalloc(sizeof(struct target_core_fabric_ops), GFP_KERNEL);
+ tfo = kzalloc_obj(struct target_core_fabric_ops);
if (!tfo) {
kfree(tf);
pr_err("%s: could not allocate memory!\n", __func__);
@@ -578,6 +575,12 @@ DEF_CONFIGFS_ATTRIB_SHOW(unmap_zeroes_data);
DEF_CONFIGFS_ATTRIB_SHOW(max_write_same_len);
DEF_CONFIGFS_ATTRIB_SHOW(emulate_rsoc);
DEF_CONFIGFS_ATTRIB_SHOW(submit_type);
+DEF_CONFIGFS_ATTRIB_SHOW(complete_type);
+DEF_CONFIGFS_ATTRIB_SHOW(atomic_max_len);
+DEF_CONFIGFS_ATTRIB_SHOW(atomic_alignment);
+DEF_CONFIGFS_ATTRIB_SHOW(atomic_granularity);
+DEF_CONFIGFS_ATTRIB_SHOW(atomic_max_with_boundary);
+DEF_CONFIGFS_ATTRIB_SHOW(atomic_max_boundary);
#define DEF_CONFIGFS_ATTRIB_STORE_U32(_name) \
static ssize_t _name##_store(struct config_item *item, const char *page,\
@@ -1264,6 +1267,24 @@ static ssize_t submit_type_store(struct config_item *item, const char *page,
return count;
}
+static ssize_t complete_type_store(struct config_item *item, const char *page,
+ size_t count)
+{
+ struct se_dev_attrib *da = to_attrib(item);
+ int ret;
+ u8 val;
+
+ ret = kstrtou8(page, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val > TARGET_QUEUE_COMPL)
+ return -EINVAL;
+
+ da->complete_type = val;
+ return count;
+}
+
CONFIGFS_ATTR(, emulate_model_alias);
CONFIGFS_ATTR(, emulate_dpo);
CONFIGFS_ATTR(, emulate_fua_write);
@@ -1300,6 +1321,12 @@ CONFIGFS_ATTR(, max_write_same_len);
CONFIGFS_ATTR(, alua_support);
CONFIGFS_ATTR(, pgr_support);
CONFIGFS_ATTR(, submit_type);
+CONFIGFS_ATTR(, complete_type);
+CONFIGFS_ATTR_RO(, atomic_max_len);
+CONFIGFS_ATTR_RO(, atomic_alignment);
+CONFIGFS_ATTR_RO(, atomic_granularity);
+CONFIGFS_ATTR_RO(, atomic_max_with_boundary);
+CONFIGFS_ATTR_RO(, atomic_max_boundary);
/*
* dev_attrib attributes for devices using the target core SBC/SPC
@@ -1343,6 +1370,12 @@ struct configfs_attribute *sbc_attrib_attrs[] = {
&attr_pgr_support,
&attr_emulate_rsoc,
&attr_submit_type,
+ &attr_complete_type,
+ &attr_atomic_alignment,
+ &attr_atomic_max_len,
+ &attr_atomic_granularity,
+ &attr_atomic_max_with_boundary,
+ &attr_atomic_max_boundary,
NULL,
};
EXPORT_SYMBOL(sbc_attrib_attrs);
@@ -1361,6 +1394,7 @@ struct configfs_attribute *passthrough_attrib_attrs[] = {
&attr_alua_support,
&attr_pgr_support,
&attr_submit_type,
+ &attr_complete_type,
NULL,
};
EXPORT_SYMBOL(passthrough_attrib_attrs);
@@ -1726,6 +1760,54 @@ static ssize_t target_wwn_vpd_protocol_identifier_show(struct config_item *item,
return len;
}
+static ssize_t target_wwn_pd_text_id_info_show(struct config_item *item,
+ char *page)
+{
+ return sysfs_emit(page, "%s\n", &to_t10_wwn(item)->pd_text_id_info[0]);
+}
+
+static ssize_t target_wwn_pd_text_id_info_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct t10_wwn *t10_wwn = to_t10_wwn(item);
+ struct se_device *dev = t10_wwn->t10_dev;
+
+ /* +2 to allow for a trailing (stripped) '\n' and null-terminator */
+ unsigned char buf[PD_TEXT_ID_INFO_LEN + 2];
+ char *stripped;
+
+ /*
+ * Check to see if any active exports exist. If they do exist, fail
+ * here as changing this information on the fly (underneath the
+ * initiator side OS dependent multipath code) could cause negative
+ * effects.
+ */
+ if (dev->export_count) {
+ pr_err("Unable to set the peripheral device text id info while active %d exports exist\n",
+ dev->export_count);
+ return -EINVAL;
+ }
+
+ if (strscpy(buf, page, sizeof(buf)) < 0)
+ return -EOVERFLOW;
+
+ /* Strip any newline added from userspace. */
+ stripped = strstrip(buf);
+ if (strlen(stripped) >= PD_TEXT_ID_INFO_LEN) {
+ pr_err("Emulated peripheral device text id info exceeds PD_TEXT_ID_INFO_LEN: " __stringify(PD_TEXT_ID_INFO_LEN "\n"));
+ return -EOVERFLOW;
+ }
+
+ BUILD_BUG_ON(sizeof(dev->t10_wwn.pd_text_id_info) != PD_TEXT_ID_INFO_LEN);
+ strscpy(dev->t10_wwn.pd_text_id_info, stripped,
+ sizeof(dev->t10_wwn.pd_text_id_info));
+
+ pr_debug("Target_Core_ConfigFS: Set emulated peripheral dev text id info:"
+ " %s\n", dev->t10_wwn.pd_text_id_info);
+
+ return count;
+}
+
/*
* Generic wrapper for dumping VPD identifiers by association.
*/
@@ -1782,6 +1864,7 @@ CONFIGFS_ATTR_RO(target_wwn_, vpd_protocol_identifier);
CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_logical_unit);
CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_target_port);
CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_scsi_target_device);
+CONFIGFS_ATTR(target_wwn_, pd_text_id_info);
static struct configfs_attribute *target_core_dev_wwn_attrs[] = {
&target_wwn_attr_vendor_id,
@@ -1793,6 +1876,7 @@ static struct configfs_attribute *target_core_dev_wwn_attrs[] = {
&target_wwn_attr_vpd_assoc_logical_unit,
&target_wwn_attr_vpd_assoc_target_port,
&target_wwn_attr_vpd_assoc_scsi_target_device,
+ &target_wwn_attr_pd_text_id_info,
NULL,
};
@@ -2758,33 +2842,24 @@ static ssize_t target_lu_gp_lu_gp_id_store(struct config_item *item,
static ssize_t target_lu_gp_members_show(struct config_item *item, char *page)
{
struct t10_alua_lu_gp *lu_gp = to_lu_gp(item);
- struct se_device *dev;
- struct se_hba *hba;
struct t10_alua_lu_gp_member *lu_gp_mem;
- ssize_t len = 0, cur_len;
- unsigned char buf[LU_GROUP_NAME_BUF] = { };
+ const char *const end = page + PAGE_SIZE;
+ char *cur = page;
spin_lock(&lu_gp->lu_gp_lock);
list_for_each_entry(lu_gp_mem, &lu_gp->lu_gp_mem_list, lu_gp_mem_list) {
- dev = lu_gp_mem->lu_gp_mem_dev;
- hba = dev->se_hba;
+ struct se_device *dev = lu_gp_mem->lu_gp_mem_dev;
+ struct se_hba *hba = dev->se_hba;
- cur_len = snprintf(buf, LU_GROUP_NAME_BUF, "%s/%s\n",
+ cur += scnprintf(cur, end - cur, "%s/%s\n",
config_item_name(&hba->hba_group.cg_item),
config_item_name(&dev->dev_group.cg_item));
- cur_len++; /* Extra byte for NULL terminator */
-
- if ((cur_len + len) > PAGE_SIZE || cur_len > LU_GROUP_NAME_BUF) {
- pr_warn("Ran out of lu_gp_show_attr"
- "_members buffer\n");
+ if (WARN_ON_ONCE(cur >= end))
break;
- }
- memcpy(page+len, buf, cur_len);
- len += cur_len;
}
spin_unlock(&lu_gp->lu_gp_lock);
- return len;
+ return cur - page;
}
CONFIGFS_ATTR(target_lu_gp_, lu_gp_id);
@@ -2804,7 +2879,7 @@ static void target_core_alua_lu_gp_release(struct config_item *item)
core_alua_free_lu_gp(lu_gp);
}
-static struct configfs_item_operations target_core_alua_lu_gp_ops = {
+static const struct configfs_item_operations target_core_alua_lu_gp_ops = {
.release = target_core_alua_lu_gp_release,
};
@@ -2861,7 +2936,7 @@ static void target_core_alua_drop_lu_gp(
config_item_put(item);
}
-static struct configfs_group_operations target_core_alua_lu_gps_group_ops = {
+static const struct configfs_group_operations target_core_alua_lu_gps_group_ops = {
.make_group = &target_core_alua_create_lu_gp,
.drop_item = &target_core_alua_drop_lu_gp,
};
@@ -3174,7 +3249,7 @@ static ssize_t target_tg_pt_gp_members_show(struct config_item *item,
config_item_name(&lun->lun_group.cg_item));
cur_len++; /* Extra byte for NULL terminator */
- if ((cur_len + len) > PAGE_SIZE) {
+ if (cur_len > TG_PT_GROUP_NAME_BUF || (cur_len + len) > PAGE_SIZE) {
pr_warn("Ran out of lu_gp_show_attr"
"_members buffer\n");
break;
@@ -3234,7 +3309,7 @@ static void target_core_alua_tg_pt_gp_release(struct config_item *item)
core_alua_free_tg_pt_gp(tg_pt_gp);
}
-static struct configfs_item_operations target_core_alua_tg_pt_gp_ops = {
+static const struct configfs_item_operations target_core_alua_tg_pt_gp_ops = {
.release = target_core_alua_tg_pt_gp_release,
};
@@ -3292,7 +3367,7 @@ static void target_core_alua_drop_tg_pt_gp(
config_item_put(item);
}
-static struct configfs_group_operations target_core_alua_tg_pt_gps_group_ops = {
+static const struct configfs_group_operations target_core_alua_tg_pt_gps_group_ops = {
.make_group = &target_core_alua_create_tg_pt_gp,
.drop_item = &target_core_alua_drop_tg_pt_gp,
};
@@ -3333,7 +3408,7 @@ static void target_core_stat_rmdir(
return;
}
-static struct configfs_group_operations target_core_stat_group_ops = {
+static const struct configfs_group_operations target_core_stat_group_ops = {
.make_group = &target_core_stat_mkdir,
.drop_item = &target_core_stat_rmdir,
};
@@ -3460,7 +3535,7 @@ static void target_core_drop_subdev(
mutex_unlock(&hba->hba_access_mutex);
}
-static struct configfs_group_operations target_core_hba_group_ops = {
+static const struct configfs_group_operations target_core_hba_group_ops = {
.make_group = target_core_make_subdev,
.drop_item = target_core_drop_subdev,
};
@@ -3539,7 +3614,7 @@ static struct configfs_attribute *target_core_hba_attrs[] = {
NULL,
};
-static struct configfs_item_operations target_core_hba_item_ops = {
+static const struct configfs_item_operations target_core_hba_item_ops = {
.release = target_core_hba_release,
};
@@ -3620,7 +3695,7 @@ static void target_core_call_delhbafromtarget(
config_item_put(item);
}
-static struct configfs_group_operations target_core_group_ops = {
+static const struct configfs_group_operations target_core_group_ops = {
.make_group = target_core_call_addhbatotarget,
.drop_item = target_core_call_delhbafromtarget,
};
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 7bb711b24c0d..9db2201aa553 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -324,7 +324,7 @@ int core_enable_device_list_for_node(
struct se_dev_entry *orig, *new;
int ret = 0;
- new = kzalloc(sizeof(*new), GFP_KERNEL);
+ new = kzalloc_obj(*new);
if (!new) {
pr_err("Unable to allocate se_dev_entry memory\n");
return -ENOMEM;
@@ -591,7 +591,7 @@ struct se_lun_acl *core_dev_init_initiator_node_lun_acl(
*ret = -EOVERFLOW;
return NULL;
}
- lacl = kzalloc(sizeof(struct se_lun_acl), GFP_KERNEL);
+ lacl = kzalloc_obj(struct se_lun_acl);
if (!lacl) {
pr_err("Unable to allocate memory for struct se_lun_acl.\n");
*ret = -ENOMEM;
@@ -726,7 +726,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
if (!dev->stats)
goto free_device;
- dev->queues = kcalloc(nr_cpu_ids, sizeof(*dev->queues), GFP_KERNEL);
+ dev->queues = kzalloc_objs(*dev->queues, nr_cpu_ids);
if (!dev->queues)
goto free_stats;
@@ -813,7 +813,9 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
DA_UNMAP_ZEROES_DATA_DEFAULT;
dev->dev_attrib.max_write_same_len = DA_MAX_WRITE_SAME_LEN;
dev->dev_attrib.submit_type = TARGET_FABRIC_DEFAULT_SUBMIT;
+ dev->dev_attrib.complete_type = TARGET_FABRIC_DEFAULT_COMPL;
+ /* Skip allocating lun_stats since we can't export them. */
xcopy_lun = &dev->xcopy_lun;
rcu_assign_pointer(xcopy_lun->lun_se_dev, dev);
init_completion(&xcopy_lun->lun_shutdown_comp);
@@ -840,12 +842,29 @@ free_device:
return NULL;
}
+void target_configure_write_atomic_from_bdev(struct se_dev_attrib *attrib,
+ struct block_device *bdev)
+{
+ struct request_queue *q = bdev_get_queue(bdev);
+ int block_size = bdev_logical_block_size(bdev);
+
+ if (!bdev_can_atomic_write(bdev))
+ return;
+
+ attrib->atomic_max_len = queue_atomic_write_max_bytes(q) / block_size;
+ attrib->atomic_granularity = attrib->atomic_alignment =
+ queue_atomic_write_unit_min_bytes(q) / block_size;
+ attrib->atomic_max_with_boundary = 0;
+ attrib->atomic_max_boundary = 0;
+}
+EXPORT_SYMBOL_GPL(target_configure_write_atomic_from_bdev);
+
/*
* Check if the underlying struct block_device supports discard and if yes
* configure the UNMAP parameters.
*/
-bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib,
- struct block_device *bdev)
+bool target_configure_unmap_from_bdev(struct se_dev_attrib *attrib,
+ struct block_device *bdev)
{
int block_size = bdev_logical_block_size(bdev);
@@ -863,7 +882,7 @@ bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib,
bdev_discard_alignment(bdev) / block_size;
return true;
}
-EXPORT_SYMBOL(target_configure_unmap_from_queue);
+EXPORT_SYMBOL(target_configure_unmap_from_bdev);
/*
* Convert from blocksize advertised to the initiator to the 512 byte
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
index 7156a4dc1ca7..ab8f81650710 100644
--- a/drivers/target/target_core_fabric_configfs.c
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -59,7 +59,7 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf)
pr_debug("Setup generic %s\n", __stringify(_name)); \
}
-static struct configfs_item_operations target_fabric_port_item_ops;
+static const struct configfs_item_operations target_fabric_port_item_ops;
/* Start of tfc_tpg_mappedlun_cit */
@@ -219,7 +219,7 @@ static void target_fabric_mappedlun_release(struct config_item *item)
core_dev_free_initiator_node_lun_acl(se_tpg, lacl);
}
-static struct configfs_item_operations target_fabric_mappedlun_item_ops = {
+static const struct configfs_item_operations target_fabric_mappedlun_item_ops = {
.release = target_fabric_mappedlun_release,
.allow_link = target_fabric_mappedlun_link,
.drop_link = target_fabric_mappedlun_unlink,
@@ -246,7 +246,7 @@ static void target_core_mappedlun_stat_rmdir(
return;
}
-static struct configfs_group_operations target_fabric_mappedlun_stat_group_ops = {
+static const struct configfs_group_operations target_fabric_mappedlun_stat_group_ops = {
.make_group = target_core_mappedlun_stat_mkdir,
.drop_item = target_core_mappedlun_stat_rmdir,
};
@@ -345,11 +345,11 @@ static void target_fabric_nacl_base_release(struct config_item *item)
core_tpg_del_initiator_node_acl(se_nacl);
}
-static struct configfs_item_operations target_fabric_nacl_base_item_ops = {
+static const struct configfs_item_operations target_fabric_nacl_base_item_ops = {
.release = target_fabric_nacl_base_release,
};
-static struct configfs_group_operations target_fabric_nacl_base_group_ops = {
+static const struct configfs_group_operations target_fabric_nacl_base_group_ops = {
.make_group = target_fabric_make_mappedlun,
.drop_item = target_fabric_drop_mappedlun,
};
@@ -433,7 +433,7 @@ static void target_fabric_drop_nodeacl(
config_item_put(item);
}
-static struct configfs_group_operations target_fabric_nacl_group_ops = {
+static const struct configfs_group_operations target_fabric_nacl_group_ops = {
.make_group = target_fabric_make_nodeacl,
.drop_item = target_fabric_drop_nodeacl,
};
@@ -454,7 +454,7 @@ static void target_fabric_np_base_release(struct config_item *item)
tf->tf_ops->fabric_drop_np(se_tpg_np);
}
-static struct configfs_item_operations target_fabric_np_base_item_ops = {
+static const struct configfs_item_operations target_fabric_np_base_item_ops = {
.release = target_fabric_np_base_release,
};
@@ -499,7 +499,7 @@ static void target_fabric_drop_np(
config_item_put(item);
}
-static struct configfs_group_operations target_fabric_np_group_ops = {
+static const struct configfs_group_operations target_fabric_np_group_ops = {
.make_group = &target_fabric_make_np,
.drop_item = &target_fabric_drop_np,
};
@@ -690,6 +690,14 @@ static void target_fabric_port_unlink(
}
core_dev_del_lun(se_tpg, lun);
+
+ if (tf->tf_ops->fabric_post_unlink) {
+ /*
+ * Allow fabrics to release state that must remain valid until
+ * core_dev_del_lun() has drained all active LUN references.
+ */
+ tf->tf_ops->fabric_post_unlink(se_tpg, lun);
+ }
}
static void target_fabric_port_release(struct config_item *item)
@@ -697,10 +705,10 @@ static void target_fabric_port_release(struct config_item *item)
struct se_lun *lun = container_of(to_config_group(item),
struct se_lun, lun_group);
- kfree_rcu(lun, rcu_head);
+ call_rcu(&lun->rcu_head, target_tpg_free_lun);
}
-static struct configfs_item_operations target_fabric_port_item_ops = {
+static const struct configfs_item_operations target_fabric_port_item_ops = {
.release = target_fabric_port_release,
.allow_link = target_fabric_port_link,
.drop_link = target_fabric_port_unlink,
@@ -726,7 +734,7 @@ static void target_core_port_stat_rmdir(
return;
}
-static struct configfs_group_operations target_fabric_port_stat_group_ops = {
+static const struct configfs_group_operations target_fabric_port_stat_group_ops = {
.make_group = target_core_port_stat_mkdir,
.drop_item = target_core_port_stat_rmdir,
};
@@ -787,7 +795,7 @@ static void target_fabric_drop_lun(
config_item_put(item);
}
-static struct configfs_group_operations target_fabric_lun_group_ops = {
+static const struct configfs_group_operations target_fabric_lun_group_ops = {
.make_group = &target_fabric_make_lun,
.drop_item = &target_fabric_drop_lun,
};
@@ -812,7 +820,7 @@ static void target_fabric_tpg_release(struct config_item *item)
tf->tf_ops->fabric_drop_tpg(se_tpg);
}
-static struct configfs_item_operations target_fabric_tpg_base_item_ops = {
+static const struct configfs_item_operations target_fabric_tpg_base_item_ops = {
.release = target_fabric_tpg_release,
};
@@ -899,7 +907,7 @@ target_fabric_setup_tpg_base_cit(struct target_fabric_configfs *tf)
nr_attrs++;
/* + 1 for final NULL in the array */
- attrs = kcalloc(nr_attrs + 1, sizeof(*attrs), GFP_KERNEL);
+ attrs = kzalloc_objs(*attrs, nr_attrs + 1);
if (!attrs)
return -ENOMEM;
@@ -998,11 +1006,11 @@ static void target_fabric_release_wwn(struct config_item *item)
tf->tf_ops->fabric_drop_wwn(wwn);
}
-static struct configfs_item_operations target_fabric_tpg_item_ops = {
+static const struct configfs_item_operations target_fabric_tpg_item_ops = {
.release = target_fabric_release_wwn,
};
-static struct configfs_group_operations target_fabric_tpg_group_ops = {
+static const struct configfs_group_operations target_fabric_tpg_group_ops = {
.make_group = target_fabric_make_tpg,
.drop_item = target_fabric_drop_tpg,
};
@@ -1066,6 +1074,28 @@ target_fabric_wwn_cmd_completion_affinity_store(struct config_item *item,
CONFIGFS_ATTR(target_fabric_wwn_, cmd_completion_affinity);
static ssize_t
+target_fabric_wwn_default_complete_type_show(struct config_item *item,
+ char *page)
+{
+ struct se_wwn *wwn = container_of(to_config_group(item), struct se_wwn,
+ param_group);
+ return sysfs_emit(page, "%u\n",
+ wwn->wwn_tf->tf_ops->default_compl_type);
+}
+CONFIGFS_ATTR_RO(target_fabric_wwn_, default_complete_type);
+
+static ssize_t
+target_fabric_wwn_direct_complete_supported_show(struct config_item *item,
+ char *page)
+{
+ struct se_wwn *wwn = container_of(to_config_group(item), struct se_wwn,
+ param_group);
+ return sysfs_emit(page, "%u\n",
+ wwn->wwn_tf->tf_ops->direct_compl_supp);
+}
+CONFIGFS_ATTR_RO(target_fabric_wwn_, direct_complete_supported);
+
+static ssize_t
target_fabric_wwn_default_submit_type_show(struct config_item *item,
char *page)
{
@@ -1089,6 +1119,8 @@ CONFIGFS_ATTR_RO(target_fabric_wwn_, direct_submit_supported);
static struct configfs_attribute *target_fabric_wwn_param_attrs[] = {
&target_fabric_wwn_attr_cmd_completion_affinity,
+ &target_fabric_wwn_attr_default_complete_type,
+ &target_fabric_wwn_attr_direct_complete_supported,
&target_fabric_wwn_attr_default_submit_type,
&target_fabric_wwn_attr_direct_submit_supported,
NULL,
@@ -1144,7 +1176,7 @@ static void target_fabric_drop_wwn(
config_item_put(item);
}
-static struct configfs_group_operations target_fabric_wwn_group_ops = {
+static const struct configfs_group_operations target_fabric_wwn_group_ops = {
.make_group = target_fabric_make_wwn,
.drop_item = target_fabric_drop_wwn,
};
diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c
index ec7bc6e30228..2853b95b2c59 100644
--- a/drivers/target/target_core_fabric_lib.c
+++ b/drivers/target/target_core_fabric_lib.c
@@ -16,6 +16,7 @@
* on the formats implemented in this file.
*/
+#include <linux/hex.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ctype.h>
@@ -289,13 +290,24 @@ static void sbp_parse_pr_out_transport_id(char *buf, char *i_str)
static bool iscsi_parse_pr_out_transport_id(
struct se_portal_group *se_tpg,
char *buf,
+ u32 buf_len,
u32 *out_tid_len,
char **port_nexus_ptr,
char *i_str)
{
char *p;
+ u32 tid_len;
int i;
- u8 format_code = (buf[0] & 0xc0);
+ u8 format_code;
+
+ /*
+ * The 4-byte iSCSI TransportID header (FORMAT CODE + 2-byte ADDITIONAL
+ * LENGTH) must be present before any of it can be parsed.
+ */
+ if (buf_len < 4)
+ return false;
+
+ format_code = buf[0] & 0xc0;
/*
* Check for FORMAT CODE 00b or 01b from spc4r17, section 7.5.4.6:
*
@@ -315,15 +327,17 @@ static bool iscsi_parse_pr_out_transport_id(
return false;
}
/*
- * If the caller wants the TransportID Length, we set that value for the
- * entire iSCSI Tarnsport ID now.
+ * Reconstruct the self-described TransportID length from the ADDITIONAL
+ * LENGTH field plus the 4-byte header. Reject it if it is below the
+ * spc4r17 section 7.5.4.6 minimum (ADDITIONAL LENGTH shall be at least
+ * 20) or if it runs past the bytes actually received, so that every
+ * access below stays inside the TransportID.
*/
- if (out_tid_len) {
- /* The shift works thanks to integer promotion rules */
- *out_tid_len = get_unaligned_be16(&buf[2]);
- /* Add four bytes for iSCSI Transport ID header */
- *out_tid_len += 4;
- }
+ tid_len = get_unaligned_be16(&buf[2]) + 4;
+ if (tid_len < 24 || tid_len > buf_len)
+ return false;
+ if (out_tid_len)
+ *out_tid_len = tid_len;
/*
* Check for ',i,0x' separator between iSCSI Name and iSCSI Initiator
@@ -331,16 +345,32 @@ static bool iscsi_parse_pr_out_transport_id(
* format.
*/
if (format_code == 0x40) {
- p = strstr(&buf[4], ",i,0x");
+ p = strnstr(&buf[4], ",i,0x", tid_len - 4);
if (!p) {
- pr_err("Unable to locate \",i,0x\" separator"
- " for Initiator port identifier: %s\n",
- &buf[4]);
+ pr_err("Unable to locate \",i,0x\" separator in iSCSI TransportID\n");
+ return false;
+ }
+ /*
+ * The iSCSI name runs from &buf[4] up to the separator; reject it
+ * if it cannot fit in i_str[TRANSPORT_IQN_LEN].
+ */
+ if (p - &buf[4] >= TRANSPORT_IQN_LEN) {
+ pr_err("iSCSI Initiator port name too long in TransportID\n");
return false;
}
*p = '\0'; /* Terminate iSCSI Name */
p += 5; /* Skip over ",i,0x" separator */
+ /*
+ * The ISID must follow the separator. A ",i,0x" sitting at the
+ * very end of the TransportID leaves no ISID and would point the
+ * port nexus at buf + tid_len, i.e. past the descriptor, which
+ * the registration code then reads as the ISID string.
+ */
+ if (p >= buf + tid_len) {
+ pr_err("Missing ISID in iSCSI Initiator port TransportID\n");
+ return false;
+ }
*port_nexus_ptr = p;
/*
* Go ahead and do the lower case conversion of the received
@@ -348,7 +378,7 @@ static bool iscsi_parse_pr_out_transport_id(
* for comparison against the running iSCSI session's ISID from
* iscsi_target.c:lio_sess_get_initiator_sid()
*/
- for (i = 0; i < 12; i++) {
+ for (i = 0; i < 12 && p < buf + tid_len; i++) {
/*
* The first ISCSI INITIATOR SESSION ID field byte
* containing an ASCII null character terminates the
@@ -366,10 +396,22 @@ static bool iscsi_parse_pr_out_transport_id(
*p = tolower(*p);
p++;
}
- } else
+ strscpy(i_str, &buf[4], TRANSPORT_IQN_LEN);
+ } else {
*port_nexus_ptr = NULL;
-
- strscpy(i_str, &buf[4], TRANSPORT_IQN_LEN);
+ /*
+ * FORMAT CODE 00b: the name occupies buf[4..tid_len-1]. The
+ * declared length tid_len - 4 must fit in i_str[TRANSPORT_IQN_LEN].
+ * (For 01b the same tid_len bound would be over-restrictive: the
+ * descriptor also carries the separator and ISID, so a legal
+ * <=223-byte name gives tid_len up to 244.)
+ */
+ if (tid_len - 4 >= TRANSPORT_IQN_LEN) {
+ pr_err("iSCSI Initiator port name too long in TransportID\n");
+ return false;
+ }
+ strscpy(i_str, &buf[4], tid_len - 4);
+ }
return true;
}
@@ -419,8 +461,16 @@ int target_get_pr_transport_id(struct se_node_acl *nacl,
}
bool target_parse_pr_out_transport_id(struct se_portal_group *tpg,
- char *buf, u32 *out_tid_len, char **port_nexus_ptr, char *i_str)
+ char *buf, u32 buf_len, u32 *out_tid_len,
+ char **port_nexus_ptr, char *i_str)
{
+ /*
+ * The fixed-length SAS/SRP/FCP/SBP TransportIDs are 24 bytes; the iSCSI
+ * format is variable and bounds itself against buf_len below.
+ */
+ if (tpg->proto_id != SCSI_PROTOCOL_ISCSI && buf_len < 24)
+ return false;
+
switch (tpg->proto_id) {
case SCSI_PROTOCOL_SAS:
/*
@@ -439,8 +489,8 @@ bool target_parse_pr_out_transport_id(struct se_portal_group *tpg,
sbp_parse_pr_out_transport_id(buf, i_str);
break;
case SCSI_PROTOCOL_ISCSI:
- return iscsi_parse_pr_out_transport_id(tpg, buf, out_tid_len,
- port_nexus_ptr, i_str);
+ return iscsi_parse_pr_out_transport_id(tpg, buf, buf_len,
+ out_tid_len, port_nexus_ptr, i_str);
default:
pr_err("Unknown proto_id: 0x%02x\n", tpg->proto_id);
return false;
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index 2d78ef74633c..62ced9f5102f 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -38,7 +38,7 @@ static int fd_attach_hba(struct se_hba *hba, u32 host_id)
{
struct fd_host *fd_host;
- fd_host = kzalloc(sizeof(struct fd_host), GFP_KERNEL);
+ fd_host = kzalloc_obj(struct fd_host);
if (!fd_host) {
pr_err("Unable to allocate memory for struct fd_host\n");
return -ENOMEM;
@@ -73,7 +73,7 @@ static struct se_device *fd_alloc_device(struct se_hba *hba, const char *name)
struct fd_dev *fd_dev;
struct fd_host *fd_host = hba->hba_ptr;
- fd_dev = kzalloc(sizeof(struct fd_dev), GFP_KERNEL);
+ fd_dev = kzalloc_obj(struct fd_dev);
if (!fd_dev) {
pr_err("Unable to allocate memory for struct fd_dev\n");
return NULL;
@@ -92,8 +92,8 @@ static bool fd_configure_unmap(struct se_device *dev)
struct inode *inode = file->f_mapping->host;
if (S_ISBLK(inode->i_mode))
- return target_configure_unmap_from_queue(&dev->dev_attrib,
- I_BDEV(inode));
+ return target_configure_unmap_from_bdev(&dev->dev_attrib,
+ I_BDEV(inode));
/* Limit UNMAP emulation to 8k Number of LBAs (NoLB) */
dev->dev_attrib.max_unmap_lba_count = 0x2000;
@@ -173,7 +173,7 @@ static int fd_configure_device(struct se_device *dev)
*/
dev->dev_attrib.max_write_same_len = 0xFFFF;
- if (bdev_nonrot(bdev))
+ if (!bdev_rot(bdev))
dev->dev_attrib.is_nonrot = 1;
} else {
if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) {
@@ -276,7 +276,7 @@ fd_execute_rw_aio(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
ssize_t len = 0;
int ret = 0, i;
- aio_cmd = kmalloc(struct_size(aio_cmd, bvecs, sgl_nents), GFP_KERNEL);
+ aio_cmd = kzalloc_flex(*aio_cmd, bvecs, sgl_nents);
if (!aio_cmd)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@@ -320,7 +320,7 @@ static int fd_do_rw(struct se_cmd *cmd, struct file *fd,
loff_t pos = (cmd->t_task_lba * block_size);
int ret = 0, i;
- bvec = kcalloc(sgl_nents, sizeof(struct bio_vec), GFP_KERNEL);
+ bvec = kzalloc_objs(struct bio_vec, sgl_nents);
if (!bvec) {
pr_err("Unable to allocate fd_do_readv iov[]\n");
return -ENOMEM;
@@ -455,7 +455,7 @@ fd_execute_write_same(struct se_cmd *cmd)
return TCM_INVALID_CDB_FIELD;
}
- bvec = kcalloc(nolb, sizeof(struct bio_vec), GFP_KERNEL);
+ bvec = kzalloc_objs(struct bio_vec, nolb);
if (!bvec)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c
index d508b343ba7b..61c54b489b7f 100644
--- a/drivers/target/target_core_hba.c
+++ b/drivers/target/target_core_hba.c
@@ -39,7 +39,7 @@ int transport_backend_register(const struct target_backend_ops *ops)
{
struct target_backend *tb, *old;
- tb = kzalloc(sizeof(*tb), GFP_KERNEL);
+ tb = kzalloc_obj(*tb);
if (!tb)
return -ENOMEM;
tb->ops = ops;
@@ -111,7 +111,7 @@ core_alloc_hba(const char *plugin_name, u32 plugin_dep_id, u32 hba_flags)
struct se_hba *hba;
int ret = 0;
- hba = kzalloc(sizeof(*hba), GFP_KERNEL);
+ hba = kzalloc_obj(*hba);
if (!hba) {
pr_err("Unable to allocate struct se_hba\n");
return ERR_PTR(-ENOMEM);
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 66c292b7d74b..ea65d39fef88 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -59,15 +59,14 @@ static struct se_device *iblock_alloc_device(struct se_hba *hba, const char *nam
{
struct iblock_dev *ib_dev = NULL;
- ib_dev = kzalloc(sizeof(struct iblock_dev), GFP_KERNEL);
+ ib_dev = kzalloc_obj(struct iblock_dev);
if (!ib_dev) {
pr_err("Unable to allocate struct iblock_dev\n");
return NULL;
}
ib_dev->ibd_exclusive = true;
- ib_dev->ibd_plug = kcalloc(nr_cpu_ids, sizeof(*ib_dev->ibd_plug),
- GFP_KERNEL);
+ ib_dev->ibd_plug = kzalloc_objs(*ib_dev->ibd_plug, nr_cpu_ids);
if (!ib_dev->ibd_plug)
goto free_dev;
@@ -84,8 +83,8 @@ static bool iblock_configure_unmap(struct se_device *dev)
{
struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
- return target_configure_unmap_from_queue(&dev->dev_attrib,
- ib_dev->ibd_bd);
+ return target_configure_unmap_from_bdev(&dev->dev_attrib,
+ ib_dev->ibd_bd);
}
static int iblock_configure_device(struct se_device *dev)
@@ -149,9 +148,11 @@ static int iblock_configure_device(struct se_device *dev)
else
dev->dev_attrib.max_write_same_len = 0xFFFF;
- if (bdev_nonrot(bd))
+ if (!bdev_rot(bd))
dev->dev_attrib.is_nonrot = 1;
+ target_configure_write_atomic_from_bdev(&dev->dev_attrib, bd);
+
bi = bdev_get_integrity(bd);
if (!bi)
return 0;
@@ -521,7 +522,7 @@ iblock_execute_write_same(struct se_cmd *cmd)
return 0;
}
- ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL);
+ ibr = kzalloc_obj(struct iblock_req);
if (!ibr)
goto fail;
cmd->priv = ibr;
@@ -773,12 +774,15 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
else if (!bdev_write_cache(ib_dev->ibd_bd))
opf |= REQ_FUA;
}
+
+ if (cmd->se_cmd_flags & SCF_ATOMIC)
+ opf |= REQ_ATOMIC;
} else {
opf = REQ_OP_READ;
miter_dir = SG_MITER_FROM_SG;
}
- ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL);
+ ibr = kzalloc_obj(struct iblock_req);
if (!ibr)
goto fail;
cmd->priv = ibr;
@@ -902,7 +906,7 @@ static sense_reason_t iblock_execute_pr_out(struct se_cmd *cmd, u8 sa, u64 key,
break;
case PRO_PREEMPT:
case PRO_PREEMPT_AND_ABORT:
- if (!ops->pr_clear) {
+ if (!ops->pr_preempt) {
pr_err("block_device does not support pr_preempt.\n");
return TCM_UNSUPPORTED_SCSI_OPCODE;
}
@@ -912,8 +916,8 @@ static sense_reason_t iblock_execute_pr_out(struct se_cmd *cmd, u8 sa, u64 key,
sa == PRO_PREEMPT_AND_ABORT);
break;
case PRO_RELEASE:
- if (!ops->pr_clear) {
- pr_err("block_device does not support pr_pclear.\n");
+ if (!ops->pr_release) {
+ pr_err("block_device does not support pr_release.\n");
return TCM_UNSUPPORTED_SCSI_OPCODE;
}
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index 20aab1f50565..f0886ea29034 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -104,7 +104,8 @@ int target_get_pr_transport_id(struct se_node_acl *nacl,
struct t10_pr_registration *pr_reg, int *format_code,
unsigned char *buf);
bool target_parse_pr_out_transport_id(struct se_portal_group *tpg,
- char *buf, u32 *out_tid_len, char **port_nexus_ptr, char *i_str);
+ char *buf, u32 buf_len, u32 *out_tid_len,
+ char **port_nexus_ptr, char *i_str);
/* target_core_hba.c */
struct se_hba *core_alloc_hba(const char *, u32, u32);
@@ -125,6 +126,7 @@ void core_tpg_add_node_to_devs(struct se_node_acl *, struct se_portal_group *,
struct se_lun *);
void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *);
struct se_lun *core_tpg_alloc_lun(struct se_portal_group *, u64);
+void target_tpg_free_lun(struct rcu_head *head);
int core_tpg_add_lun(struct se_portal_group *, struct se_lun *,
bool, struct se_device *);
void core_tpg_remove_lun(struct se_portal_group *, struct se_lun *);
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 83e172c92238..25b1bcacc0c8 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -18,6 +18,7 @@
#include <linux/file.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
+#include <linux/fs_struct.h>
#include <scsi/scsi_proto.h>
#include <linux/unaligned.h>
@@ -1490,7 +1491,7 @@ core_scsi3_decode_spec_i_port(
* local_node_acl pointer and add to struct list_head tid_dest_list
* for add registration processing in the loop of tid_dest_list below.
*/
- tidh_new = kzalloc(sizeof(struct pr_transport_id_holder), GFP_KERNEL);
+ tidh_new = kzalloc_obj(struct pr_transport_id_holder);
if (!tidh_new) {
pr_err("Unable to allocate tidh_new\n");
return TCM_INSUFFICIENT_REGISTRATION_RESOURCES;
@@ -1573,7 +1574,7 @@ core_scsi3_decode_spec_i_port(
iport_ptr = NULL;
tid_found = target_parse_pr_out_transport_id(tmp_tpg,
- ptr, &tid_len, &iport_ptr, i_str);
+ ptr, tpdl, &tid_len, &iport_ptr, i_str);
if (!tid_found)
continue;
/*
@@ -1712,8 +1713,7 @@ core_scsi3_decode_spec_i_port(
* the dest_node_acl and dest_se_deve pointers for the
* loop below.
*/
- tidh_new = kzalloc(sizeof(struct pr_transport_id_holder),
- GFP_KERNEL);
+ tidh_new = kzalloc_obj(struct pr_transport_id_holder);
if (!tidh_new) {
pr_err("Unable to allocate tidh_new\n");
core_scsi3_lunacl_undepend_item(dest_se_deve);
@@ -1970,7 +1970,8 @@ static int __core_scsi3_write_aptpl_to_file(
if (!path)
return -ENOMEM;
- file = filp_open(path, flags, 0600);
+ scoped_with_init_fs()
+ file = filp_open(path, flags, 0600);
if (IS_ERR(file)) {
pr_err("filp_open(%s) for APTPL metadata"
" failed\n", path);
@@ -2810,7 +2811,7 @@ static void core_scsi3_release_preempt_and_abort(
}
static sense_reason_t
-core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
+core_scsi3_emulate_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
u64 sa_res_key, enum preempt_type preempt_type)
{
struct se_device *dev = cmd->se_dev;
@@ -2839,11 +2840,6 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
core_scsi3_put_pr_reg(pr_reg_n);
return TCM_RESERVATION_CONFLICT;
}
- if (scope != PR_SCOPE_LU_SCOPE) {
- pr_err("SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope);
- core_scsi3_put_pr_reg(pr_reg_n);
- return TCM_INVALID_PARAMETER_LIST;
- }
spin_lock(&dev->dev_reservation_lock);
pr_res_holder = dev->dev_pr_res_holder;
@@ -2857,6 +2853,37 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
core_scsi3_put_pr_reg(pr_reg_n);
return TCM_INVALID_PARAMETER_LIST;
}
+
+ /* Validate TYPE and SCOPE fields if they will be used */
+ if (pr_res_holder &&
+ (pr_res_holder->pr_res_key == sa_res_key ||
+ (all_reg && !sa_res_key))) {
+ switch (type) {
+ case PR_TYPE_WRITE_EXCLUSIVE:
+ case PR_TYPE_EXCLUSIVE_ACCESS:
+ case PR_TYPE_WRITE_EXCLUSIVE_REGONLY:
+ case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY:
+ case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:
+ case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
+ break;
+ default:
+ pr_err("SPC-3 PR: Unknown Service Action PREEMPT%s"
+ " Type: 0x%02x\n",
+ (preempt_type == PREEMPT_AND_ABORT) ?
+ "_AND_ABORT" : "", type);
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg_n);
+ return TCM_INVALID_CDB_FIELD;
+ }
+
+ if (scope != PR_SCOPE_LU_SCOPE) {
+ pr_err("SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope);
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg_n);
+ return TCM_INVALID_PARAMETER_LIST;
+ }
+ }
+
/*
* From spc4r17, section 5.7.11.4.4 Removing Registrations:
*
@@ -3120,27 +3147,6 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,
}
static sense_reason_t
-core_scsi3_emulate_pro_preempt(struct se_cmd *cmd, int type, int scope,
- u64 res_key, u64 sa_res_key, enum preempt_type preempt_type)
-{
- switch (type) {
- case PR_TYPE_WRITE_EXCLUSIVE:
- case PR_TYPE_EXCLUSIVE_ACCESS:
- case PR_TYPE_WRITE_EXCLUSIVE_REGONLY:
- case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY:
- case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:
- case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
- return core_scsi3_pro_preempt(cmd, type, scope, res_key,
- sa_res_key, preempt_type);
- default:
- pr_err("SPC-3 PR: Unknown Service Action PREEMPT%s"
- " Type: 0x%02x\n", (preempt_type == PREEMPT_AND_ABORT) ? "_AND_ABORT" : "", type);
- return TCM_INVALID_CDB_FIELD;
- }
-}
-
-
-static sense_reason_t
core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,
u64 sa_res_key, int aptpl, int unreg)
{
@@ -3281,7 +3287,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,
goto out;
}
tid_found = target_parse_pr_out_transport_id(dest_se_tpg,
- &buf[24], &tmp_tid_len, &iport_ptr, initiator_str);
+ &buf[24], tid_len, &tmp_tid_len, &iport_ptr, initiator_str);
if (!tid_found) {
pr_err("SPC-3 PR REGISTER_AND_MOVE: Unable to locate"
" initiator_str from Transport ID\n");
@@ -3289,9 +3295,6 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,
goto out;
}
- transport_kunmap_data_sg(cmd);
- buf = NULL;
-
pr_debug("SPC-3 PR [%s] Extracted initiator %s identifier: %s"
" %s\n", dest_tf_ops->fabric_name, (iport_ptr != NULL) ?
"port" : "device", initiator_str, (iport_ptr != NULL) ?
@@ -3528,6 +3531,11 @@ after_iport_check:
core_scsi3_update_and_write_aptpl(cmd->se_dev, aptpl);
core_scsi3_put_pr_reg(dest_pr_reg);
+ /*
+ * iport_ptr aliases the PR-OUT parameter list mapped above, so the
+ * buffer is unmapped only here on success (and at out: on error).
+ */
+ transport_kunmap_data_sg(cmd);
return 0;
out:
if (buf)
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index db4e09042469..9ed2818c3028 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -39,7 +39,8 @@ static inline struct pscsi_dev_virt *PSCSI_DEV(struct se_device *dev)
}
static sense_reason_t pscsi_execute_cmd(struct se_cmd *cmd);
-static enum rq_end_io_ret pscsi_req_done(struct request *, blk_status_t);
+static enum rq_end_io_ret pscsi_req_done(struct request *, blk_status_t,
+ const struct io_comp_batch *);
/* pscsi_attach_hba():
*
@@ -50,7 +51,7 @@ static int pscsi_attach_hba(struct se_hba *hba, u32 host_id)
{
struct pscsi_hba_virt *phv;
- phv = kzalloc(sizeof(struct pscsi_hba_virt), GFP_KERNEL);
+ phv = kzalloc_obj(struct pscsi_hba_virt);
if (!phv) {
pr_err("Unable to allocate struct pscsi_hba_virt\n");
return -ENOMEM;
@@ -246,7 +247,7 @@ pscsi_get_inquiry_vpd_device_ident(struct scsi_device *sdev,
}
pr_debug("T10 VPD Identifier Length: %d\n", ident_len);
- vpd = kzalloc(sizeof(struct t10_vpd), GFP_KERNEL);
+ vpd = kzalloc_obj(struct t10_vpd);
if (!vpd) {
pr_err("Unable to allocate memory for"
" struct t10_vpd\n");
@@ -333,7 +334,7 @@ static struct se_device *pscsi_alloc_device(struct se_hba *hba,
{
struct pscsi_dev_virt *pdv;
- pdv = kzalloc(sizeof(struct pscsi_dev_virt), GFP_KERNEL);
+ pdv = kzalloc_obj(struct pscsi_dev_virt);
if (!pdv) {
pr_err("Unable to allocate memory for struct pscsi_dev_virt\n");
return NULL;
@@ -1001,7 +1002,8 @@ static sector_t pscsi_get_blocks(struct se_device *dev)
}
static enum rq_end_io_ret pscsi_req_done(struct request *req,
- blk_status_t status)
+ blk_status_t status,
+ const struct io_comp_batch *iob)
{
struct se_cmd *cmd = req->end_io_data;
struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(req);
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c
index 6f67cc09c2b5..092d9fe0d4e3 100644
--- a/drivers/target/target_core_rd.c
+++ b/drivers/target/target_core_rd.c
@@ -34,7 +34,7 @@ static int rd_attach_hba(struct se_hba *hba, u32 host_id)
{
struct rd_host *rd_host;
- rd_host = kzalloc(sizeof(*rd_host), GFP_KERNEL);
+ rd_host = kzalloc_obj(*rd_host);
if (!rd_host)
return -ENOMEM;
@@ -131,8 +131,7 @@ static int rd_allocate_sgl_table(struct rd_dev *rd_dev, struct rd_dev_sg_table *
if (sg_per_table < total_sg_needed)
chain_entry = 1;
- sg = kmalloc_array(sg_per_table + chain_entry, sizeof(*sg),
- GFP_KERNEL);
+ sg = kmalloc_objs(*sg, sg_per_table + chain_entry);
if (!sg)
return -ENOMEM;
@@ -192,7 +191,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev)
total_sg_needed = rd_dev->rd_page_count;
sg_tables = (total_sg_needed / max_sg_per_table) + 1;
- sg_table = kcalloc(sg_tables, sizeof(*sg_table), GFP_KERNEL);
+ sg_table = kzalloc_objs(*sg_table, sg_tables);
if (!sg_table)
return -ENOMEM;
@@ -249,7 +248,7 @@ static int rd_build_prot_space(struct rd_dev *rd_dev, int prot_length, int block
total_sg_needed = (rd_dev->rd_page_count * prot_length / block_size) + 1;
sg_tables = (total_sg_needed / max_sg_per_table) + 1;
- sg_table = kcalloc(sg_tables, sizeof(*sg_table), GFP_KERNEL);
+ sg_table = kzalloc_objs(*sg_table, sg_tables);
if (!sg_table)
return -ENOMEM;
@@ -272,7 +271,7 @@ static struct se_device *rd_alloc_device(struct se_hba *hba, const char *name)
struct rd_dev *rd_dev;
struct rd_host *rd_host = hba->hba_ptr;
- rd_dev = kzalloc(sizeof(*rd_dev), GFP_KERNEL);
+ rd_dev = kzalloc_obj(*rd_dev);
if (!rd_dev)
return NULL;
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index fe8beb7dbab1..21f5cb86d70c 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -764,6 +764,49 @@ sbc_check_dpofua(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb)
return 0;
}
+static sense_reason_t
+sbc_check_atomic(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb)
+{
+ struct se_dev_attrib *attrib = &dev->dev_attrib;
+ u16 boundary, transfer_len;
+ u64 lba;
+
+ lba = transport_lba_64(cdb);
+ boundary = get_unaligned_be16(&cdb[10]);
+ transfer_len = get_unaligned_be16(&cdb[12]);
+
+ if (!attrib->atomic_max_len)
+ return TCM_UNSUPPORTED_SCSI_OPCODE;
+
+ if (boundary) {
+ if (transfer_len > attrib->atomic_max_with_boundary)
+ return TCM_INVALID_CDB_FIELD;
+
+ if (boundary > attrib->atomic_max_boundary)
+ return TCM_INVALID_CDB_FIELD;
+ } else {
+ if (transfer_len > attrib->atomic_max_len)
+ return TCM_INVALID_CDB_FIELD;
+ }
+
+ if (attrib->atomic_granularity) {
+ if (transfer_len % attrib->atomic_granularity)
+ return TCM_INVALID_CDB_FIELD;
+
+ if (boundary && boundary % attrib->atomic_granularity)
+ return TCM_INVALID_CDB_FIELD;
+ }
+
+ if (dev->dev_attrib.atomic_alignment) {
+ u64 _lba = lba;
+
+ if (do_div(_lba, dev->dev_attrib.atomic_alignment))
+ return TCM_INVALID_CDB_FIELD;
+ }
+
+ return 0;
+}
+
sense_reason_t
sbc_parse_cdb(struct se_cmd *cmd, struct exec_cmd_ops *ops)
{
@@ -861,6 +904,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct exec_cmd_ops *ops)
break;
case WRITE_16:
case WRITE_VERIFY_16:
+ case WRITE_ATOMIC_16:
sectors = transport_get_sectors_16(cdb);
cmd->t_task_lba = transport_lba_64(cdb);
@@ -872,6 +916,13 @@ sbc_parse_cdb(struct se_cmd *cmd, struct exec_cmd_ops *ops)
return ret;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+ if (cdb[0] == WRITE_ATOMIC_16) {
+ cmd->se_cmd_flags |= SCF_ATOMIC;
+
+ ret = sbc_check_atomic(dev, cmd, cdb);
+ if (ret)
+ return ret;
+ }
cmd->execute_cmd = sbc_execute_rw;
break;
case VARIABLE_LENGTH_CMD:
@@ -1136,7 +1187,8 @@ sbc_execute_unmap(struct se_cmd *cmd)
goto err;
}
- if (lba + range > dev->transport->get_blocks(dev) + 1) {
+ if (lba + range < lba ||
+ lba + range > dev->transport->get_blocks(dev) + 1) {
ret = TCM_ADDRESS_OUT_OF_RANGE;
goto err;
}
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index aad0096afa21..f964a531e053 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -7,6 +7,7 @@
* Nicholas A. Bellinger <nab@kernel.org>
*/
+#include <linux/hex.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/unaligned.h>
@@ -25,6 +26,8 @@
#include "target_core_ua.h"
#include "target_core_xcopy.h"
+#define PD_TEXT_ID_INFO_HDR_LEN 4
+
static void spc_fill_alua_data(struct se_lun *lun, unsigned char *buf)
{
struct t10_alua_tg_pt_gp *tg_pt_gp;
@@ -521,7 +524,6 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
have_tp = 1;
buf[0] = dev->transport->get_device_type(dev);
- buf[3] = have_tp ? 0x3c : 0x10;
/* Set WSNZ to 1 */
buf[4] = 0x01;
@@ -562,11 +564,10 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
else
put_unaligned_be32(dev->dev_attrib.optimal_sectors, &buf[12]);
- /*
- * Exit now if we don't support TP.
- */
+ put_unaligned_be16(12, &buf[2]);
+
if (!have_tp)
- goto max_write_same;
+ goto try_atomic;
/*
* Set MAXIMUM UNMAP LBA COUNT
@@ -595,9 +596,29 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
/*
* MAXIMUM WRITE SAME LENGTH
*/
-max_write_same:
put_unaligned_be64(dev->dev_attrib.max_write_same_len, &buf[36]);
+ put_unaligned_be16(40, &buf[2]);
+
+try_atomic:
+ /*
+ * ATOMIC
+ */
+ if (!dev->dev_attrib.atomic_max_len)
+ goto done;
+
+ if (dev->dev_attrib.atomic_max_len < io_max_blocks)
+ put_unaligned_be32(dev->dev_attrib.atomic_max_len, &buf[44]);
+ else
+ put_unaligned_be32(io_max_blocks, &buf[44]);
+
+ put_unaligned_be32(dev->dev_attrib.atomic_alignment, &buf[48]);
+ put_unaligned_be32(dev->dev_attrib.atomic_granularity, &buf[52]);
+ put_unaligned_be32(dev->dev_attrib.atomic_max_with_boundary, &buf[56]);
+ put_unaligned_be32(dev->dev_attrib.atomic_max_boundary, &buf[60]);
+
+ put_unaligned_be16(60, &buf[2]);
+done:
return 0;
}
@@ -1452,6 +1473,24 @@ static const struct target_opcode_descriptor tcm_opcode_write_same32 = {
.update_usage_bits = set_dpofua_usage_bits32,
};
+static bool tcm_is_atomic_enabled(const struct target_opcode_descriptor *descr,
+ struct se_cmd *cmd)
+{
+ return cmd->se_dev->dev_attrib.atomic_max_len;
+}
+
+static struct target_opcode_descriptor tcm_opcode_write_atomic16 = {
+ .support = SCSI_SUPPORT_FULL,
+ .opcode = WRITE_ATOMIC_16,
+ .cdb_size = 16,
+ .usage_bits = {WRITE_ATOMIC_16, 0xf8, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, SCSI_GROUP_NUMBER_MASK, SCSI_CONTROL_MASK},
+ .enabled = tcm_is_atomic_enabled,
+ .update_usage_bits = set_dpofua_usage_bits,
+};
+
static bool tcm_is_caw_enabled(const struct target_opcode_descriptor *descr,
struct se_cmd *cmd)
{
@@ -1963,6 +2002,18 @@ static const struct target_opcode_descriptor tcm_opcode_report_supp_opcodes = {
.enabled = spc_rsoc_enabled,
};
+static struct target_opcode_descriptor tcm_opcode_report_identifying_information = {
+ .support = SCSI_SUPPORT_FULL,
+ .serv_action_valid = 1,
+ .opcode = MAINTENANCE_IN,
+ .service_action = MI_REPORT_IDENTIFYING_INFORMATION,
+ .cdb_size = 12,
+ .usage_bits = {MAINTENANCE_IN, MI_REPORT_IDENTIFYING_INFORMATION,
+ 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, SCSI_CONTROL_MASK},
+};
+
static bool tcm_is_set_tpg_enabled(const struct target_opcode_descriptor *descr,
struct se_cmd *cmd)
{
@@ -2008,6 +2059,7 @@ static const struct target_opcode_descriptor *tcm_supported_opcodes[] = {
&tcm_opcode_write16,
&tcm_opcode_write_verify16,
&tcm_opcode_write_same32,
+ &tcm_opcode_write_atomic16,
&tcm_opcode_compare_write,
&tcm_opcode_read_capacity,
&tcm_opcode_read_capacity16,
@@ -2049,6 +2101,7 @@ static const struct target_opcode_descriptor *tcm_supported_opcodes[] = {
&tcm_opcode_report_target_pgs,
&tcm_opcode_report_supp_opcodes,
&tcm_opcode_set_tpg,
+ &tcm_opcode_report_identifying_information,
};
static int
@@ -2266,6 +2319,72 @@ out:
return ret;
}
+static sense_reason_t
+spc_fill_pd_text_id_info(struct se_cmd *cmd, u8 *cdb)
+{
+ struct se_device *dev = cmd->se_dev;
+ unsigned char *buf;
+ unsigned char *rbuf;
+ u32 buf_len;
+ u16 data_len;
+
+ buf_len = get_unaligned_be32(&cdb[6]);
+ if (buf_len < PD_TEXT_ID_INFO_HDR_LEN)
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+ data_len = strlen(dev->t10_wwn.pd_text_id_info);
+ if (data_len > 0)
+ /* trailing null */
+ data_len += 1;
+
+ data_len = data_len + PD_TEXT_ID_INFO_HDR_LEN;
+
+ if (data_len < buf_len)
+ buf_len = data_len;
+
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf) {
+ pr_err("Unable to allocate response buffer for IDENTITY INFO\n");
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ }
+
+ scnprintf(&buf[PD_TEXT_ID_INFO_HDR_LEN], buf_len - PD_TEXT_ID_INFO_HDR_LEN, "%s",
+ dev->t10_wwn.pd_text_id_info);
+
+ put_unaligned_be16(data_len, &buf[2]);
+
+ rbuf = transport_kmap_data_sg(cmd);
+ if (!rbuf) {
+ pr_err("transport_kmap_data_sg() failed in %s\n", __func__);
+ kfree(buf);
+ return TCM_OUT_OF_RESOURCES;
+ }
+
+ memcpy(rbuf, buf, buf_len);
+ transport_kunmap_data_sg(cmd);
+ kfree(buf);
+
+ target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, buf_len);
+ return TCM_NO_SENSE;
+}
+
+static sense_reason_t
+spc_emulate_report_id_info(struct se_cmd *cmd)
+{
+ u8 *cdb = cmd->t_task_cdb;
+ sense_reason_t rc;
+
+ switch ((cdb[10] >> 1)) {
+ case 2:
+ rc = spc_fill_pd_text_id_info(cmd, cdb);
+ break;
+ default:
+ return TCM_UNSUPPORTED_SCSI_OPCODE;
+ }
+
+ return rc;
+}
+
sense_reason_t
spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
{
@@ -2405,6 +2524,11 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
MI_REPORT_SUPPORTED_OPERATION_CODES)
cmd->execute_cmd =
spc_emulate_report_supp_op_codes;
+ if ((cdb[1] & 0x1f) ==
+ MI_REPORT_IDENTIFYING_INFORMATION) {
+ cmd->execute_cmd =
+ spc_emulate_report_id_info;
+ }
*size = get_unaligned_be32(&cdb[6]);
} else {
/*
diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c
index 6bdf2d8bd694..083205052be2 100644
--- a/drivers/target/target_core_stat.c
+++ b/drivers/target/target_core_stat.c
@@ -276,56 +276,39 @@ static ssize_t target_stat_lu_state_bit_show(struct config_item *item,
return snprintf(page, PAGE_SIZE, "exposed\n");
}
-static ssize_t target_stat_lu_num_cmds_show(struct config_item *item,
- char *page)
-{
- struct se_device *dev = to_stat_lu_dev(item);
- struct se_dev_io_stats *stats;
- unsigned int cpu;
- u32 cmds = 0;
-
- for_each_possible_cpu(cpu) {
- stats = per_cpu_ptr(dev->stats, cpu);
- cmds += stats->total_cmds;
- }
-
- /* scsiLuNumCommands */
- return snprintf(page, PAGE_SIZE, "%u\n", cmds);
-}
-
-static ssize_t target_stat_lu_read_mbytes_show(struct config_item *item,
- char *page)
-{
- struct se_device *dev = to_stat_lu_dev(item);
- struct se_dev_io_stats *stats;
- unsigned int cpu;
- u32 bytes = 0;
-
- for_each_possible_cpu(cpu) {
- stats = per_cpu_ptr(dev->stats, cpu);
- bytes += stats->read_bytes;
- }
-
- /* scsiLuReadMegaBytes */
- return snprintf(page, PAGE_SIZE, "%u\n", bytes >> 20);
-}
-
-static ssize_t target_stat_lu_write_mbytes_show(struct config_item *item,
- char *page)
-{
- struct se_device *dev = to_stat_lu_dev(item);
- struct se_dev_io_stats *stats;
- unsigned int cpu;
- u32 bytes = 0;
-
- for_each_possible_cpu(cpu) {
- stats = per_cpu_ptr(dev->stats, cpu);
- bytes += stats->write_bytes;
- }
-
- /* scsiLuWrittenMegaBytes */
- return snprintf(page, PAGE_SIZE, "%u\n", bytes >> 20);
-}
+#define per_cpu_stat_snprintf(stats_struct, prefix, field, shift) \
+static ssize_t \
+per_cpu_stat_##prefix##_snprintf(struct stats_struct __percpu *per_cpu_stats, \
+ char *page) \
+{ \
+ struct stats_struct *stats; \
+ unsigned int cpu; \
+ u64 sum = 0; \
+ \
+ for_each_possible_cpu(cpu) { \
+ stats = per_cpu_ptr(per_cpu_stats, cpu); \
+ sum += stats->field; \
+ } \
+ \
+ return snprintf(page, PAGE_SIZE, "%llu\n", sum >> shift); \
+}
+
+#define lu_show_per_cpu_stat(prefix, field, shift) \
+per_cpu_stat_snprintf(se_dev_io_stats, prefix, field, shift); \
+static ssize_t \
+target_stat_##prefix##_show(struct config_item *item, char *page) \
+{ \
+ struct se_device *dev = to_stat_lu_dev(item); \
+ \
+ return per_cpu_stat_##prefix##_snprintf(dev->stats, page); \
+} \
+
+/* scsiLuNumCommands */
+lu_show_per_cpu_stat(lu_num_cmds, total_cmds, 0);
+/* scsiLuReadMegaBytes */
+lu_show_per_cpu_stat(lu_read_mbytes, read_bytes, 20);
+/* scsiLuWrittenMegaBytes */
+lu_show_per_cpu_stat(lu_write_mbytes, write_bytes, 20);
static ssize_t target_stat_lu_resets_show(struct config_item *item, char *page)
{
@@ -623,53 +606,30 @@ static ssize_t target_stat_tgt_port_port_index_show(struct config_item *item,
return ret;
}
-static ssize_t target_stat_tgt_port_in_cmds_show(struct config_item *item,
- char *page)
-{
- struct se_lun *lun = to_stat_tgt_port(item);
- struct se_device *dev;
- ssize_t ret = -ENODEV;
-
- rcu_read_lock();
- dev = rcu_dereference(lun->lun_se_dev);
- if (dev)
- ret = snprintf(page, PAGE_SIZE, "%lu\n",
- atomic_long_read(&lun->lun_stats.cmd_pdus));
- rcu_read_unlock();
- return ret;
-}
-
-static ssize_t target_stat_tgt_port_write_mbytes_show(struct config_item *item,
- char *page)
-{
- struct se_lun *lun = to_stat_tgt_port(item);
- struct se_device *dev;
- ssize_t ret = -ENODEV;
-
- rcu_read_lock();
- dev = rcu_dereference(lun->lun_se_dev);
- if (dev)
- ret = snprintf(page, PAGE_SIZE, "%u\n",
- (u32)(atomic_long_read(&lun->lun_stats.rx_data_octets) >> 20));
- rcu_read_unlock();
- return ret;
-}
-
-static ssize_t target_stat_tgt_port_read_mbytes_show(struct config_item *item,
- char *page)
-{
- struct se_lun *lun = to_stat_tgt_port(item);
- struct se_device *dev;
- ssize_t ret = -ENODEV;
-
- rcu_read_lock();
- dev = rcu_dereference(lun->lun_se_dev);
- if (dev)
- ret = snprintf(page, PAGE_SIZE, "%u\n",
- (u32)(atomic_long_read(&lun->lun_stats.tx_data_octets) >> 20));
- rcu_read_unlock();
- return ret;
-}
+#define tgt_port_show_per_cpu_stat(prefix, field, shift) \
+per_cpu_stat_snprintf(scsi_port_stats, prefix, field, shift); \
+static ssize_t \
+target_stat_##prefix##_show(struct config_item *item, char *page) \
+{ \
+ struct se_lun *lun = to_stat_tgt_port(item); \
+ struct se_device *dev; \
+ int ret; \
+ \
+ rcu_read_lock(); \
+ dev = rcu_dereference(lun->lun_se_dev); \
+ if (!dev) { \
+ rcu_read_unlock(); \
+ return -ENODEV; \
+ } \
+ \
+ ret = per_cpu_stat_##prefix##_snprintf(lun->lun_stats, page); \
+ rcu_read_unlock(); \
+ return ret; \
+}
+
+tgt_port_show_per_cpu_stat(tgt_port_in_cmds, cmd_pdus, 0);
+tgt_port_show_per_cpu_stat(tgt_port_write_mbytes, rx_data_octets, 20);
+tgt_port_show_per_cpu_stat(tgt_port_read_mbytes, tx_data_octets, 20);
static ssize_t target_stat_tgt_port_hs_in_cmds_show(struct config_item *item,
char *page)
@@ -1035,92 +995,34 @@ static ssize_t target_stat_auth_att_count_show(struct config_item *item,
return ret;
}
-static ssize_t target_stat_auth_num_cmds_show(struct config_item *item,
- char *page)
-{
- struct se_lun_acl *lacl = auth_to_lacl(item);
- struct se_node_acl *nacl = lacl->se_lun_nacl;
- struct se_dev_entry_io_stats *stats;
- struct se_dev_entry *deve;
- unsigned int cpu;
- ssize_t ret;
- u32 cmds = 0;
-
- rcu_read_lock();
- deve = target_nacl_find_deve(nacl, lacl->mapped_lun);
- if (!deve) {
- rcu_read_unlock();
- return -ENODEV;
- }
-
- for_each_possible_cpu(cpu) {
- stats = per_cpu_ptr(deve->stats, cpu);
- cmds += stats->total_cmds;
- }
-
- /* scsiAuthIntrOutCommands */
- ret = snprintf(page, PAGE_SIZE, "%u\n", cmds);
- rcu_read_unlock();
- return ret;
-}
-
-static ssize_t target_stat_auth_read_mbytes_show(struct config_item *item,
- char *page)
-{
- struct se_lun_acl *lacl = auth_to_lacl(item);
- struct se_node_acl *nacl = lacl->se_lun_nacl;
- struct se_dev_entry_io_stats *stats;
- struct se_dev_entry *deve;
- unsigned int cpu;
- ssize_t ret;
- u32 bytes = 0;
-
- rcu_read_lock();
- deve = target_nacl_find_deve(nacl, lacl->mapped_lun);
- if (!deve) {
- rcu_read_unlock();
- return -ENODEV;
- }
-
- for_each_possible_cpu(cpu) {
- stats = per_cpu_ptr(deve->stats, cpu);
- bytes += stats->read_bytes;
- }
-
- /* scsiAuthIntrReadMegaBytes */
- ret = snprintf(page, PAGE_SIZE, "%u\n", bytes >> 20);
- rcu_read_unlock();
- return ret;
-}
-
-static ssize_t target_stat_auth_write_mbytes_show(struct config_item *item,
- char *page)
-{
- struct se_lun_acl *lacl = auth_to_lacl(item);
- struct se_node_acl *nacl = lacl->se_lun_nacl;
- struct se_dev_entry_io_stats *stats;
- struct se_dev_entry *deve;
- unsigned int cpu;
- ssize_t ret;
- u32 bytes = 0;
-
- rcu_read_lock();
- deve = target_nacl_find_deve(nacl, lacl->mapped_lun);
- if (!deve) {
- rcu_read_unlock();
- return -ENODEV;
- }
-
- for_each_possible_cpu(cpu) {
- stats = per_cpu_ptr(deve->stats, cpu);
- bytes += stats->write_bytes;
- }
-
- /* scsiAuthIntrWrittenMegaBytes */
- ret = snprintf(page, PAGE_SIZE, "%u\n", bytes >> 20);
- rcu_read_unlock();
- return ret;
-}
+#define auth_show_per_cpu_stat(prefix, field, shift) \
+per_cpu_stat_snprintf(se_dev_entry_io_stats, prefix, field, shift); \
+static ssize_t \
+target_stat_##prefix##_show(struct config_item *item, char *page) \
+{ \
+ struct se_lun_acl *lacl = auth_to_lacl(item); \
+ struct se_node_acl *nacl = lacl->se_lun_nacl; \
+ struct se_dev_entry *deve; \
+ int ret; \
+ \
+ rcu_read_lock(); \
+ deve = target_nacl_find_deve(nacl, lacl->mapped_lun); \
+ if (!deve) { \
+ rcu_read_unlock(); \
+ return -ENODEV; \
+ } \
+ \
+ ret = per_cpu_stat_##prefix##_snprintf(deve->stats, page); \
+ rcu_read_unlock(); \
+ return ret; \
+}
+
+/* scsiAuthIntrOutCommands */
+auth_show_per_cpu_stat(auth_num_cmds, total_cmds, 0);
+/* scsiAuthIntrReadMegaBytes */
+auth_show_per_cpu_stat(auth_read_mbytes, read_bytes, 20);
+/* scsiAuthIntrWrittenMegaBytes */
+auth_show_per_cpu_stat(auth_write_mbytes, write_bytes, 20);
static ssize_t target_stat_auth_hs_num_cmds_show(struct config_item *item,
char *page)
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index 4718db628222..db7388e207b2 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -31,7 +31,7 @@ int core_tmr_alloc_req(
{
struct se_tmr_req *tmr;
- tmr = kzalloc(sizeof(struct se_tmr_req), gfp_flags);
+ tmr = kzalloc_obj(struct se_tmr_req, gfp_flags);
if (!tmr) {
pr_err("Unable to allocate struct se_tmr_req\n");
return -ENOMEM;
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index c0e429e5ef31..ccff9f6e4826 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -548,7 +548,7 @@ int core_tpg_register(
ret = core_tpg_add_lun(se_tpg, se_tpg->tpg_virt_lun0,
true, g_lun0_dev);
if (ret < 0) {
- kfree(se_tpg->tpg_virt_lun0);
+ target_tpg_free_lun(&se_tpg->tpg_virt_lun0->rcu_head);
return ret;
}
}
@@ -595,7 +595,7 @@ int core_tpg_deregister(struct se_portal_group *se_tpg)
if (se_tpg->proto_id >= 0) {
core_tpg_remove_lun(se_tpg, se_tpg->tpg_virt_lun0);
- kfree_rcu(se_tpg->tpg_virt_lun0, rcu_head);
+ call_rcu(&se_tpg->tpg_virt_lun0->rcu_head, target_tpg_free_lun);
}
target_tpg_deregister_rtpi(se_tpg);
@@ -610,11 +610,18 @@ struct se_lun *core_tpg_alloc_lun(
{
struct se_lun *lun;
- lun = kzalloc(sizeof(*lun), GFP_KERNEL);
+ lun = kzalloc_obj(*lun);
if (!lun) {
pr_err("Unable to allocate se_lun memory\n");
return ERR_PTR(-ENOMEM);
}
+
+ lun->lun_stats = alloc_percpu(struct scsi_port_stats);
+ if (!lun->lun_stats) {
+ pr_err("Unable to allocate se_lun stats memory\n");
+ goto free_lun;
+ }
+
lun->unpacked_lun = unpacked_lun;
atomic_set(&lun->lun_acl_count, 0);
init_completion(&lun->lun_shutdown_comp);
@@ -628,6 +635,18 @@ struct se_lun *core_tpg_alloc_lun(
lun->lun_tpg = tpg;
return lun;
+
+free_lun:
+ kfree(lun);
+ return ERR_PTR(-ENOMEM);
+}
+
+void target_tpg_free_lun(struct rcu_head *head)
+{
+ struct se_lun *lun = container_of(head, struct se_lun, rcu_head);
+
+ free_percpu(lun->lun_stats);
+ kfree(lun);
}
int core_tpg_add_lun(
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 0a76bdfe5528..dcfe94594916 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -126,12 +126,12 @@ int init_se_kmem_caches(void)
}
target_completion_wq = alloc_workqueue("target_completion",
- WQ_MEM_RECLAIM, 0);
+ WQ_MEM_RECLAIM | WQ_PERCPU, 0);
if (!target_completion_wq)
goto out_free_lba_map_mem_cache;
target_submission_wq = alloc_workqueue("target_submission",
- WQ_MEM_RECLAIM, 0);
+ WQ_MEM_RECLAIM | WQ_PERCPU, 0);
if (!target_submission_wq)
goto out_free_completion_wq;
@@ -233,7 +233,7 @@ struct target_cmd_counter *target_alloc_cmd_counter(void)
struct target_cmd_counter *cmd_cnt;
int rc;
- cmd_cnt = kzalloc(sizeof(*cmd_cnt), GFP_KERNEL);
+ cmd_cnt = kzalloc_obj(*cmd_cnt);
if (!cmd_cnt)
return NULL;
@@ -902,13 +902,59 @@ static bool target_cmd_interrupted(struct se_cmd *cmd)
return false;
}
+static void target_complete(struct se_cmd *cmd, int success)
+{
+ struct se_wwn *wwn = cmd->se_sess->se_tpg->se_tpg_wwn;
+ struct se_dev_attrib *da;
+ u8 compl_type;
+ int cpu;
+
+ if (!wwn) {
+ cpu = cmd->cpuid;
+ goto queue_work;
+ }
+
+ da = &cmd->se_dev->dev_attrib;
+ if (da->complete_type == TARGET_FABRIC_DEFAULT_COMPL)
+ compl_type = wwn->wwn_tf->tf_ops->default_compl_type;
+ else if (da->complete_type == TARGET_DIRECT_COMPL &&
+ wwn->wwn_tf->tf_ops->direct_compl_supp)
+ compl_type = TARGET_DIRECT_COMPL;
+ else
+ compl_type = TARGET_QUEUE_COMPL;
+
+ if (compl_type == TARGET_DIRECT_COMPL) {
+ /*
+ * Failure handling and processing secondary stages of
+ * complex commands can be too heavy to handle from the
+ * fabric driver so always defer.
+ */
+ if (success && !cmd->transport_complete_callback) {
+ target_complete_ok_work(&cmd->work);
+ return;
+ }
+
+ compl_type = TARGET_QUEUE_COMPL;
+ }
+
+queue_work:
+ INIT_WORK(&cmd->work, success ? target_complete_ok_work :
+ target_complete_failure_work);
+
+ if (!wwn || wwn->cmd_compl_affinity == SE_COMPL_AFFINITY_CPUID)
+ cpu = cmd->cpuid;
+ else
+ cpu = wwn->cmd_compl_affinity;
+
+ queue_work_on(cpu, target_completion_wq, &cmd->work);
+}
+
/* May be called from interrupt context so must not sleep. */
void target_complete_cmd_with_sense(struct se_cmd *cmd, u8 scsi_status,
sense_reason_t sense_reason)
{
- struct se_wwn *wwn = cmd->se_sess->se_tpg->se_tpg_wwn;
- int success, cpu;
unsigned long flags;
+ int success;
if (target_cmd_interrupted(cmd))
return;
@@ -933,15 +979,7 @@ void target_complete_cmd_with_sense(struct se_cmd *cmd, u8 scsi_status,
cmd->transport_state |= (CMD_T_COMPLETE | CMD_T_ACTIVE);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- INIT_WORK(&cmd->work, success ? target_complete_ok_work :
- target_complete_failure_work);
-
- if (!wwn || wwn->cmd_compl_affinity == SE_COMPL_AFFINITY_CPUID)
- cpu = cmd->cpuid;
- else
- cpu = wwn->cmd_compl_affinity;
-
- queue_work_on(cpu, target_completion_wq, &cmd->work);
+ target_complete(cmd, success);
}
EXPORT_SYMBOL(target_complete_cmd_with_sense);
@@ -1112,7 +1150,7 @@ void transport_dump_vpd_proto_id(
}
if (p_buf)
- strncpy(p_buf, buf, p_buf_len);
+ strscpy(p_buf, buf, p_buf_len);
else
pr_debug("%s", buf);
}
@@ -1162,7 +1200,7 @@ int transport_dump_vpd_assoc(
}
if (p_buf)
- strncpy(p_buf, buf, p_buf_len);
+ strscpy(p_buf, buf, p_buf_len);
else
pr_debug("%s", buf);
@@ -1222,7 +1260,7 @@ int transport_dump_vpd_ident_type(
if (p_buf) {
if (p_buf_len < strlen(buf)+1)
return -EINVAL;
- strncpy(p_buf, buf, p_buf_len);
+ strscpy(p_buf, buf, p_buf_len);
} else {
pr_debug("%s", buf);
}
@@ -1276,7 +1314,7 @@ int transport_dump_vpd_ident(
}
if (p_buf)
- strncpy(p_buf, buf, p_buf_len);
+ strscpy(p_buf, buf, p_buf_len);
else
pr_debug("%s", buf);
@@ -1524,6 +1562,7 @@ target_cmd_init_cdb(struct se_cmd *cmd, unsigned char *cdb, gfp_t gfp)
if (scsi_command_size(cdb) > sizeof(cmd->__t_task_cdb)) {
cmd->t_task_cdb = kzalloc(scsi_command_size(cdb), gfp);
if (!cmd->t_task_cdb) {
+ cmd->t_task_cdb = &cmd->__t_task_cdb[0];
pr_err("Unable to allocate cmd->t_task_cdb"
" %u > sizeof(cmd->__t_task_cdb): %lu ops\n",
scsi_command_size(cdb),
@@ -1571,7 +1610,12 @@ target_cmd_parse_cdb(struct se_cmd *cmd)
return ret;
cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE;
- atomic_long_inc(&cmd->se_lun->lun_stats.cmd_pdus);
+ /*
+ * If this is the xcopy_lun then we won't have lun_stats since we
+ * can't export them.
+ */
+ if (cmd->se_lun->lun_stats)
+ this_cpu_inc(cmd->se_lun->lun_stats->cmd_pdus);
return 0;
}
EXPORT_SYMBOL(target_cmd_parse_cdb);
@@ -1690,6 +1734,7 @@ int target_init_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
u32 data_length, int task_attr, int data_dir, int flags)
{
struct se_portal_group *se_tpg;
+ int ret;
se_tpg = se_sess->se_tpg;
BUG_ON(!se_tpg);
@@ -1719,7 +1764,11 @@ int target_init_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
* necessary for fabrics using TARGET_SCF_ACK_KREF that expect a second
* kref_put() to happen during fabric packet acknowledgement.
*/
- return target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF);
+ ret = target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF);
+ if (ret)
+ se_cmd->cmd_cnt = NULL;
+
+ return ret;
}
EXPORT_SYMBOL_GPL(target_init_cmd);
@@ -1995,8 +2044,10 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
* allocation failure.
*/
ret = core_tmr_alloc_req(se_cmd, fabric_tmr_ptr, tm_type, gfp);
- if (ret < 0)
+ if (ret < 0) {
+ se_cmd->cmd_cnt = NULL;
return -ENOMEM;
+ }
if (tm_type == TMR_ABORT_TASK)
se_cmd->se_tmr_req->ref_task_tag = tag;
@@ -2004,6 +2055,7 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
/* See target_submit_cmd for commentary */
ret = target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF);
if (ret) {
+ se_cmd->cmd_cnt = NULL;
core_tmr_release_req(se_cmd->se_tmr_req);
return ret;
}
@@ -2597,8 +2649,9 @@ queue_rsp:
!(cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL))
goto queue_status;
- atomic_long_add(cmd->data_length,
- &cmd->se_lun->lun_stats.tx_data_octets);
+ if (cmd->se_lun->lun_stats)
+ this_cpu_add(cmd->se_lun->lun_stats->tx_data_octets,
+ cmd->data_length);
/*
* Perform READ_STRIP of PI using software emulation when
* backend had PI enabled, if the transport will not be
@@ -2621,14 +2674,16 @@ queue_rsp:
goto queue_full;
break;
case DMA_TO_DEVICE:
- atomic_long_add(cmd->data_length,
- &cmd->se_lun->lun_stats.rx_data_octets);
+ if (cmd->se_lun->lun_stats)
+ this_cpu_add(cmd->se_lun->lun_stats->rx_data_octets,
+ cmd->data_length);
/*
* Check if we need to send READ payload for BIDI-COMMAND
*/
if (cmd->se_cmd_flags & SCF_BIDI) {
- atomic_long_add(cmd->data_length,
- &cmd->se_lun->lun_stats.tx_data_octets);
+ if (cmd->se_lun->lun_stats)
+ this_cpu_add(cmd->se_lun->lun_stats->tx_data_octets,
+ cmd->data_length);
ret = cmd->se_tfo->queue_data_in(cmd);
if (ret)
goto queue_full;
@@ -2731,7 +2786,7 @@ void *transport_kmap_data_sg(struct se_cmd *cmd)
return kmap(sg_page(sg)) + sg->offset;
/* >1 page. use vmap */
- pages = kmalloc_array(cmd->t_data_nents, sizeof(*pages), GFP_KERNEL);
+ pages = kmalloc_objs(*pages, cmd->t_data_nents);
if (!pages)
return NULL;
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index 3fd963612775..edc2afd5f4ee 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -1293,7 +1293,7 @@ tcmu_tmr_notify(struct se_device *se_dev, enum tcm_tmreq_table tmf,
pr_debug("TMR event %d on dev %s, aborted cmds %d, afflicted cmd_ids %d\n",
tcmu_tmr_type(tmf), udev->name, i, cmd_cnt);
- tmr = kmalloc(struct_size(tmr, tmr_cmd_ids, cmd_cnt), GFP_NOIO);
+ tmr = kmalloc_flex(*tmr, tmr_cmd_ids, cmd_cnt, GFP_NOIO);
if (!tmr)
goto unlock;
@@ -1582,7 +1582,7 @@ static int tcmu_attach_hba(struct se_hba *hba, u32 host_id)
{
struct tcmu_hba *tcmu_hba;
- tcmu_hba = kzalloc(sizeof(struct tcmu_hba), GFP_KERNEL);
+ tcmu_hba = kzalloc_obj(struct tcmu_hba);
if (!tcmu_hba)
return -ENOMEM;
@@ -1602,7 +1602,7 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name)
{
struct tcmu_dev *udev;
- udev = kzalloc(sizeof(struct tcmu_dev), GFP_KERNEL);
+ udev = kzalloc_obj(struct tcmu_dev);
if (!udev)
return NULL;
kref_init(&udev->kref);
@@ -1860,6 +1860,17 @@ static struct page *tcmu_try_get_data_page(struct tcmu_dev *udev, uint32_t dpi)
return NULL;
}
+static int tcmu_vma_mapped(unsigned long start, unsigned long end, pgoff_t pgoff,
+ const struct file *file, void **vm_private_data)
+{
+ struct tcmu_dev *udev = *vm_private_data;
+
+ pr_debug("vma_mapped\n");
+
+ kref_get(&udev->kref);
+ return 0;
+}
+
static void tcmu_vma_open(struct vm_area_struct *vma)
{
struct tcmu_dev *udev = vma->vm_private_data;
@@ -1919,26 +1930,25 @@ static vm_fault_t tcmu_vma_fault(struct vm_fault *vmf)
}
static const struct vm_operations_struct tcmu_vm_ops = {
+ .mapped = tcmu_vma_mapped,
.open = tcmu_vma_open,
.close = tcmu_vma_close,
.fault = tcmu_vma_fault,
};
-static int tcmu_mmap(struct uio_info *info, struct vm_area_struct *vma)
+static int tcmu_mmap_prepare(struct uio_info *info, struct vm_area_desc *desc)
{
struct tcmu_dev *udev = container_of(info, struct tcmu_dev, uio_info);
- vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP);
- vma->vm_ops = &tcmu_vm_ops;
+ vma_desc_set_flags(desc, VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT);
+ desc->vm_ops = &tcmu_vm_ops;
- vma->vm_private_data = udev;
+ desc->private_data = udev;
/* Ensure the mmap is exactly the right size */
- if (vma_pages(vma) != udev->mmap_pages)
+ if (vma_desc_pages(desc) != udev->mmap_pages)
return -EINVAL;
- tcmu_vma_open(vma);
-
return 0;
}
@@ -2253,7 +2263,7 @@ static int tcmu_configure_device(struct se_device *dev)
info->irqcontrol = tcmu_irqcontrol;
info->irq = UIO_IRQ_CUSTOM;
- info->mmap = tcmu_mmap;
+ info->mmap_prepare = tcmu_mmap_prepare;
info->open = tcmu_open;
info->release = tcmu_release;
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c
index 877ce58c0a70..9e5e94f3aa5d 100644
--- a/drivers/target/target_core_xcopy.c
+++ b/drivers/target/target_core_xcopy.c
@@ -462,7 +462,7 @@ static const struct target_core_fabric_ops xcopy_pt_tfo = {
int target_xcopy_setup_pt(void)
{
- xcopy_wq = alloc_workqueue("xcopy_wq", WQ_MEM_RECLAIM, 0);
+ xcopy_wq = alloc_workqueue("xcopy_wq", WQ_MEM_RECLAIM | WQ_PERCPU, 0);
if (!xcopy_wq) {
pr_err("Unable to allocate xcopy_wq\n");
return -ENOMEM;
@@ -898,7 +898,7 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
return TCM_PARAMETER_LIST_LENGTH_ERROR;
}
- xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL);
+ xop = kzalloc_obj(struct xcopy_op);
if (!xop)
goto err;
xop->xop_se_cmd = se_cmd;
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c
index 639fc358ed0f..3920fb02d9fc 100644
--- a/drivers/target/tcm_fc/tfc_conf.c
+++ b/drivers/target/tcm_fc/tfc_conf.c
@@ -17,6 +17,7 @@
#include <linux/moduleparam.h>
#include <generated/utsrelease.h>
#include <linux/utsname.h>
+#include <linux/hex.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kthread.h>
@@ -243,14 +244,14 @@ static struct se_portal_group *ft_add_tpg(struct se_wwn *wwn, const char *name)
}
ft_wwn = container_of(wwn, struct ft_lport_wwn, se_wwn);
- tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
+ tpg = kzalloc_obj(*tpg);
if (!tpg)
return NULL;
tpg->index = index;
tpg->lport_wwn = ft_wwn;
INIT_LIST_HEAD(&tpg->lun_list);
- wq = alloc_workqueue("tcm_fc", 0, 1);
+ wq = alloc_workqueue("tcm_fc", WQ_PERCPU, 1);
if (!wq) {
kfree(tpg);
return NULL;
@@ -333,7 +334,7 @@ static struct se_wwn *ft_add_wwn(
pr_debug("add wwn %s\n", name);
if (ft_parse_wwn(name, &wwpn, 1) < 0)
return NULL;
- ft_wwn = kzalloc(sizeof(*ft_wwn), GFP_KERNEL);
+ ft_wwn = kzalloc_obj(*ft_wwn);
if (!ft_wwn)
return NULL;
ft_wwn->wwpn = wwpn;
@@ -433,6 +434,7 @@ static const struct target_core_fabric_ops ft_fabric_ops = {
.tfc_wwn_attrs = ft_wwn_attrs,
.tfc_tpg_nacl_base_attrs = ft_nacl_base_attrs,
+ .default_compl_type = TARGET_QUEUE_COMPL,
.default_submit_type = TARGET_DIRECT_SUBMIT,
.direct_submit_supp = 1,
};
diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c
index d6afaba52ea5..797be06ab71b 100644
--- a/drivers/target/tcm_fc/tfc_sess.c
+++ b/drivers/target/tcm_fc/tfc_sess.c
@@ -59,7 +59,7 @@ static struct ft_tport *ft_tport_get(struct fc_lport *lport)
return tport;
}
- tport = kzalloc(sizeof(*tport), GFP_KERNEL);
+ tport = kzalloc_obj(*tport);
if (!tport)
return NULL;
@@ -219,7 +219,7 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id,
if (sess->port_id == port_id)
return sess;
- sess = kzalloc(sizeof(*sess), GFP_KERNEL);
+ sess = kzalloc_obj(*sess);
if (!sess)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/target/tcm_remote/tcm_remote.c b/drivers/target/tcm_remote/tcm_remote.c
index cb8db2558056..03b00f6eca58 100644
--- a/drivers/target/tcm_remote/tcm_remote.c
+++ b/drivers/target/tcm_remote/tcm_remote.c
@@ -156,7 +156,7 @@ static struct se_wwn *tcm_remote_make_wwn(
char *ptr;
int ret, off = 0;
- remote_hba = kzalloc(sizeof(*remote_hba), GFP_KERNEL);
+ remote_hba = kzalloc_obj(*remote_hba);
if (!remote_hba)
return ERR_PTR(-ENOMEM);