diff options
Diffstat (limited to 'drivers/target')
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, ¶m_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); |
