diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-06-10 05:30:17 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-06-10 05:30:17 -0300 |
commit | d635711daa98be86d4c7fd01499c34f566b54ccb (patch) | |
tree | aa5cc3760a27c3d57146498cb82fa549547de06c /drivers/target | |
parent | c91265cd0efb83778f015b4d4b1129bd2cfd075e (diff) |
Linux-libre 4.6.2-gnu
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/iscsi/iscsi_target.c | 86 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_auth.c | 98 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_configfs.c | 93 | ||||
-rw-r--r-- | drivers/target/iscsi/iscsi_target_login.c | 45 | ||||
-rw-r--r-- | drivers/target/loopback/tcm_loop.c | 46 | ||||
-rw-r--r-- | drivers/target/sbp/sbp_target.c | 95 | ||||
-rw-r--r-- | drivers/target/target_core_configfs.c | 203 | ||||
-rw-r--r-- | drivers/target/target_core_device.c | 41 | ||||
-rw-r--r-- | drivers/target/target_core_fabric_configfs.c | 250 | ||||
-rw-r--r-- | drivers/target/target_core_iblock.c | 34 | ||||
-rw-r--r-- | drivers/target/target_core_internal.h | 9 | ||||
-rw-r--r-- | drivers/target/target_core_spc.c | 3 | ||||
-rw-r--r-- | drivers/target/target_core_stat.c | 41 | ||||
-rw-r--r-- | drivers/target/target_core_tpg.c | 21 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 64 | ||||
-rw-r--r-- | drivers/target/target_core_user.c | 267 | ||||
-rw-r--r-- | drivers/target/tcm_fc/tfc_cmd.c | 20 | ||||
-rw-r--r-- | drivers/target/tcm_fc/tfc_sess.c | 44 |
18 files changed, 665 insertions, 795 deletions
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 576a7a434..961202f4e 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -16,9 +16,9 @@ * GNU General Public License for more details. ******************************************************************************/ +#include <crypto/hash.h> #include <linux/string.h> #include <linux/kthread.h> -#include <linux/crypto.h> #include <linux/completion.h> #include <linux/module.h> #include <linux/vmalloc.h> @@ -1190,7 +1190,7 @@ iscsit_handle_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, } static u32 iscsit_do_crypto_hash_sg( - struct hash_desc *hash, + struct ahash_request *hash, struct iscsi_cmd *cmd, u32 data_offset, u32 data_length, @@ -1201,7 +1201,7 @@ static u32 iscsit_do_crypto_hash_sg( struct scatterlist *sg; unsigned int page_off; - crypto_hash_init(hash); + crypto_ahash_init(hash); sg = cmd->first_data_sg; page_off = cmd->first_data_sg_off; @@ -1209,7 +1209,8 @@ static u32 iscsit_do_crypto_hash_sg( while (data_length) { u32 cur_len = min_t(u32, data_length, (sg->length - page_off)); - crypto_hash_update(hash, sg, cur_len); + ahash_request_set_crypt(hash, sg, NULL, cur_len); + crypto_ahash_update(hash); data_length -= cur_len; page_off = 0; @@ -1221,33 +1222,34 @@ static u32 iscsit_do_crypto_hash_sg( struct scatterlist pad_sg; sg_init_one(&pad_sg, pad_bytes, padding); - crypto_hash_update(hash, &pad_sg, padding); + ahash_request_set_crypt(hash, &pad_sg, (u8 *)&data_crc, + padding); + crypto_ahash_finup(hash); + } else { + ahash_request_set_crypt(hash, NULL, (u8 *)&data_crc, 0); + crypto_ahash_final(hash); } - crypto_hash_final(hash, (u8 *) &data_crc); return data_crc; } static void iscsit_do_crypto_hash_buf( - struct hash_desc *hash, + struct ahash_request *hash, const void *buf, u32 payload_length, u32 padding, u8 *pad_bytes, u8 *data_crc) { - struct scatterlist sg; + struct scatterlist sg[2]; - crypto_hash_init(hash); + sg_init_table(sg, ARRAY_SIZE(sg)); + sg_set_buf(sg, buf, payload_length); + sg_set_buf(sg + 1, pad_bytes, padding); - sg_init_one(&sg, buf, payload_length); - crypto_hash_update(hash, &sg, payload_length); + ahash_request_set_crypt(hash, sg, data_crc, payload_length + padding); - if (padding) { - sg_init_one(&sg, pad_bytes, padding); - crypto_hash_update(hash, &sg, padding); - } - crypto_hash_final(hash, data_crc); + crypto_ahash_digest(hash); } int @@ -1422,7 +1424,7 @@ iscsit_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, if (conn->conn_ops->DataDigest) { u32 data_crc; - data_crc = iscsit_do_crypto_hash_sg(&conn->conn_rx_hash, cmd, + data_crc = iscsit_do_crypto_hash_sg(conn->conn_rx_hash, cmd, be32_to_cpu(hdr->offset), payload_length, padding, cmd->pad_bytes); @@ -1682,7 +1684,7 @@ static int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, } if (conn->conn_ops->DataDigest) { - iscsit_do_crypto_hash_buf(&conn->conn_rx_hash, + iscsit_do_crypto_hash_buf(conn->conn_rx_hash, ping_data, payload_length, padding, cmd->pad_bytes, (u8 *)&data_crc); @@ -2101,7 +2103,7 @@ iscsit_handle_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, goto reject; if (conn->conn_ops->DataDigest) { - iscsit_do_crypto_hash_buf(&conn->conn_rx_hash, + iscsit_do_crypto_hash_buf(conn->conn_rx_hash, text_in, payload_length, padding, (u8 *)&pad_bytes, (u8 *)&data_crc); @@ -2440,7 +2442,7 @@ static int iscsit_handle_immediate_data( if (conn->conn_ops->DataDigest) { u32 data_crc; - data_crc = iscsit_do_crypto_hash_sg(&conn->conn_rx_hash, cmd, + data_crc = iscsit_do_crypto_hash_sg(conn->conn_rx_hash, cmd, cmd->write_data_done, length, padding, cmd->pad_bytes); @@ -2553,7 +2555,7 @@ static int iscsit_send_conn_drop_async_message( if (conn->conn_ops->HeaderDigest) { u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr, + iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr, ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest); cmd->tx_size += ISCSI_CRC_LEN; @@ -2683,7 +2685,7 @@ static int iscsit_send_datain(struct iscsi_cmd *cmd, struct iscsi_conn *conn) if (conn->conn_ops->HeaderDigest) { u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, cmd->pdu, + iscsit_do_crypto_hash_buf(conn->conn_tx_hash, cmd->pdu, ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest); iov[0].iov_len += ISCSI_CRC_LEN; @@ -2711,7 +2713,7 @@ static int iscsit_send_datain(struct iscsi_cmd *cmd, struct iscsi_conn *conn) cmd->padding); } if (conn->conn_ops->DataDigest) { - cmd->data_crc = iscsit_do_crypto_hash_sg(&conn->conn_tx_hash, cmd, + cmd->data_crc = iscsit_do_crypto_hash_sg(conn->conn_tx_hash, cmd, datain.offset, datain.length, cmd->padding, cmd->pad_bytes); iov[iov_count].iov_base = &cmd->data_crc; @@ -2857,7 +2859,7 @@ iscsit_send_logout(struct iscsi_cmd *cmd, struct iscsi_conn *conn) if (conn->conn_ops->HeaderDigest) { u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, &cmd->pdu[0], + iscsit_do_crypto_hash_buf(conn->conn_tx_hash, &cmd->pdu[0], ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest); iov[0].iov_len += ISCSI_CRC_LEN; @@ -2915,7 +2917,7 @@ static int iscsit_send_unsolicited_nopin( if (conn->conn_ops->HeaderDigest) { u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr, + iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr, ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest); tx_size += ISCSI_CRC_LEN; @@ -2963,7 +2965,7 @@ iscsit_send_nopin(struct iscsi_cmd *cmd, struct iscsi_conn *conn) if (conn->conn_ops->HeaderDigest) { u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr, + iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr, ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest); iov[0].iov_len += ISCSI_CRC_LEN; @@ -2993,7 +2995,7 @@ iscsit_send_nopin(struct iscsi_cmd *cmd, struct iscsi_conn *conn) " padding bytes.\n", padding); } if (conn->conn_ops->DataDigest) { - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, + iscsit_do_crypto_hash_buf(conn->conn_tx_hash, cmd->buf_ptr, cmd->buf_ptr_size, padding, (u8 *)&cmd->pad_bytes, (u8 *)&cmd->data_crc); @@ -3049,7 +3051,7 @@ static int iscsit_send_r2t( if (conn->conn_ops->HeaderDigest) { u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr, + iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr, ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest); cmd->iov_misc[0].iov_len += ISCSI_CRC_LEN; @@ -3239,7 +3241,7 @@ static int iscsit_send_response(struct iscsi_cmd *cmd, struct iscsi_conn *conn) } if (conn->conn_ops->DataDigest) { - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, + iscsit_do_crypto_hash_buf(conn->conn_tx_hash, cmd->sense_buffer, (cmd->se_cmd.scsi_sense_length + padding), 0, NULL, (u8 *)&cmd->data_crc); @@ -3262,7 +3264,7 @@ static int iscsit_send_response(struct iscsi_cmd *cmd, struct iscsi_conn *conn) if (conn->conn_ops->HeaderDigest) { u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, cmd->pdu, + iscsit_do_crypto_hash_buf(conn->conn_tx_hash, cmd->pdu, ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest); iov[0].iov_len += ISCSI_CRC_LEN; @@ -3332,7 +3334,7 @@ iscsit_send_task_mgt_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn) if (conn->conn_ops->HeaderDigest) { u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr, + iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr, ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest); cmd->iov_misc[0].iov_len += ISCSI_CRC_LEN; @@ -3601,7 +3603,7 @@ static int iscsit_send_text_rsp( if (conn->conn_ops->HeaderDigest) { u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr, + iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr, ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest); iov[0].iov_len += ISCSI_CRC_LEN; @@ -3611,7 +3613,7 @@ static int iscsit_send_text_rsp( } if (conn->conn_ops->DataDigest) { - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, + iscsit_do_crypto_hash_buf(conn->conn_tx_hash, cmd->buf_ptr, text_length, 0, NULL, (u8 *)&cmd->data_crc); @@ -3668,7 +3670,7 @@ static int iscsit_send_reject( if (conn->conn_ops->HeaderDigest) { u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr, + iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr, ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest); iov[0].iov_len += ISCSI_CRC_LEN; @@ -3678,7 +3680,7 @@ static int iscsit_send_reject( } if (conn->conn_ops->DataDigest) { - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, cmd->buf_ptr, + iscsit_do_crypto_hash_buf(conn->conn_tx_hash, cmd->buf_ptr, ISCSI_HDR_LEN, 0, NULL, (u8 *)&cmd->data_crc); iov[iov_count].iov_base = &cmd->data_crc; @@ -4145,7 +4147,7 @@ int iscsi_target_rx_thread(void *arg) goto transport_err; } - iscsit_do_crypto_hash_buf(&conn->conn_rx_hash, + iscsit_do_crypto_hash_buf(conn->conn_rx_hash, buffer, ISCSI_HDR_LEN, 0, NULL, (u8 *)&checksum); @@ -4359,10 +4361,14 @@ int iscsit_close_connection( */ iscsit_check_conn_usage_count(conn); - if (conn->conn_rx_hash.tfm) - crypto_free_hash(conn->conn_rx_hash.tfm); - if (conn->conn_tx_hash.tfm) - crypto_free_hash(conn->conn_tx_hash.tfm); + ahash_request_free(conn->conn_tx_hash); + if (conn->conn_rx_hash) { + struct crypto_ahash *tfm; + + tfm = crypto_ahash_reqtfm(conn->conn_rx_hash); + ahash_request_free(conn->conn_rx_hash); + crypto_free_ahash(tfm); + } free_cpumask_var(conn->conn_cpumask); diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index 47e249dcc..667406fcf 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -16,9 +16,9 @@ * GNU General Public License for more details. ******************************************************************************/ +#include <crypto/hash.h> #include <linux/kernel.h> #include <linux/string.h> -#include <linux/crypto.h> #include <linux/err.h> #include <linux/scatterlist.h> @@ -185,9 +185,8 @@ static int chap_server_compute_md5( unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH]; size_t compare_len; struct iscsi_chap *chap = conn->auth_protocol; - struct crypto_hash *tfm; - struct hash_desc desc; - struct scatterlist sg; + struct crypto_shash *tfm = NULL; + struct shash_desc *desc = NULL; int auth_ret = -1, ret, challenge_len; memset(identifier, 0, 10); @@ -245,52 +244,47 @@ static int chap_server_compute_md5( pr_debug("[server] Got CHAP_R=%s\n", chap_r); chap_string_to_hex(client_digest, chap_r, strlen(chap_r)); - tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); + tfm = crypto_alloc_shash("md5", 0, 0); if (IS_ERR(tfm)) { - pr_err("Unable to allocate struct crypto_hash\n"); + tfm = NULL; + pr_err("Unable to allocate struct crypto_shash\n"); goto out; } - desc.tfm = tfm; - desc.flags = 0; - ret = crypto_hash_init(&desc); - if (ret < 0) { - pr_err("crypto_hash_init() failed\n"); - crypto_free_hash(tfm); + desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL); + if (!desc) { + pr_err("Unable to allocate struct shash_desc\n"); goto out; } - sg_init_one(&sg, &chap->id, 1); - ret = crypto_hash_update(&desc, &sg, 1); + desc->tfm = tfm; + desc->flags = 0; + + ret = crypto_shash_init(desc); if (ret < 0) { - pr_err("crypto_hash_update() failed for id\n"); - crypto_free_hash(tfm); + pr_err("crypto_shash_init() failed\n"); goto out; } - sg_init_one(&sg, &auth->password, strlen(auth->password)); - ret = crypto_hash_update(&desc, &sg, strlen(auth->password)); + ret = crypto_shash_update(desc, &chap->id, 1); if (ret < 0) { - pr_err("crypto_hash_update() failed for password\n"); - crypto_free_hash(tfm); + pr_err("crypto_shash_update() failed for id\n"); goto out; } - sg_init_one(&sg, chap->challenge, CHAP_CHALLENGE_LENGTH); - ret = crypto_hash_update(&desc, &sg, CHAP_CHALLENGE_LENGTH); + ret = crypto_shash_update(desc, (char *)&auth->password, + strlen(auth->password)); if (ret < 0) { - pr_err("crypto_hash_update() failed for challenge\n"); - crypto_free_hash(tfm); + pr_err("crypto_shash_update() failed for password\n"); goto out; } - ret = crypto_hash_final(&desc, server_digest); + ret = crypto_shash_finup(desc, chap->challenge, + CHAP_CHALLENGE_LENGTH, server_digest); if (ret < 0) { - pr_err("crypto_hash_final() failed for server digest\n"); - crypto_free_hash(tfm); + pr_err("crypto_shash_finup() failed for challenge\n"); goto out; } - crypto_free_hash(tfm); chap_binaryhex_to_asciihex(response, server_digest, MD5_SIGNATURE_SIZE); pr_debug("[server] MD5 Server Digest: %s\n", response); @@ -306,9 +300,8 @@ static int chap_server_compute_md5( * authentication is not enabled. */ if (!auth->authenticate_target) { - kfree(challenge); - kfree(challenge_binhex); - return 0; + auth_ret = 0; + goto out; } /* * Get CHAP_I. @@ -372,58 +365,37 @@ static int chap_server_compute_md5( /* * Generate CHAP_N and CHAP_R for mutual authentication. */ - tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm)) { - pr_err("Unable to allocate struct crypto_hash\n"); - goto out; - } - desc.tfm = tfm; - desc.flags = 0; - - ret = crypto_hash_init(&desc); + ret = crypto_shash_init(desc); if (ret < 0) { - pr_err("crypto_hash_init() failed\n"); - crypto_free_hash(tfm); + pr_err("crypto_shash_init() failed\n"); goto out; } /* To handle both endiannesses */ id_as_uchar = id; - sg_init_one(&sg, &id_as_uchar, 1); - ret = crypto_hash_update(&desc, &sg, 1); + ret = crypto_shash_update(desc, &id_as_uchar, 1); if (ret < 0) { - pr_err("crypto_hash_update() failed for id\n"); - crypto_free_hash(tfm); + pr_err("crypto_shash_update() failed for id\n"); goto out; } - sg_init_one(&sg, auth->password_mutual, - strlen(auth->password_mutual)); - ret = crypto_hash_update(&desc, &sg, strlen(auth->password_mutual)); + ret = crypto_shash_update(desc, auth->password_mutual, + strlen(auth->password_mutual)); if (ret < 0) { - pr_err("crypto_hash_update() failed for" + pr_err("crypto_shash_update() failed for" " password_mutual\n"); - crypto_free_hash(tfm); goto out; } /* * Convert received challenge to binary hex. */ - sg_init_one(&sg, challenge_binhex, challenge_len); - ret = crypto_hash_update(&desc, &sg, challenge_len); + ret = crypto_shash_finup(desc, challenge_binhex, challenge_len, + digest); if (ret < 0) { - pr_err("crypto_hash_update() failed for ma challenge\n"); - crypto_free_hash(tfm); + pr_err("crypto_shash_finup() failed for ma challenge\n"); goto out; } - ret = crypto_hash_final(&desc, digest); - if (ret < 0) { - pr_err("crypto_hash_final() failed for ma digest\n"); - crypto_free_hash(tfm); - goto out; - } - crypto_free_hash(tfm); /* * Generate CHAP_N and CHAP_R. */ @@ -440,6 +412,8 @@ static int chap_server_compute_md5( pr_debug("[server] Sending CHAP_R=0x%s\n", response); auth_ret = 0; out: + kzfree(desc); + crypto_free_shash(tfm); kfree(challenge); kfree(challenge_binhex); return auth_ret; diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 2f821de63..97e5b69e0 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -771,41 +771,14 @@ static int lio_target_init_nodeacl(struct se_node_acl *se_nacl, { struct iscsi_node_acl *acl = container_of(se_nacl, struct iscsi_node_acl, se_node_acl); - struct config_group *stats_cg = &se_nacl->acl_fabric_stat_group; - - stats_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, - GFP_KERNEL); - if (!stats_cg->default_groups) { - pr_err("Unable to allocate memory for" - " stats_cg->default_groups\n"); - return -ENOMEM; - } - stats_cg->default_groups[0] = &acl->node_stat_grps.iscsi_sess_stats_group; - stats_cg->default_groups[1] = NULL; config_group_init_type_name(&acl->node_stat_grps.iscsi_sess_stats_group, "iscsi_sess_stats", &iscsi_stat_sess_cit); - + configfs_add_default_group(&acl->node_stat_grps.iscsi_sess_stats_group, + &se_nacl->acl_fabric_stat_group); return 0; } -static void lio_target_cleanup_nodeacl( struct se_node_acl *se_nacl) -{ - struct iscsi_node_acl *acl = container_of(se_nacl, - struct iscsi_node_acl, se_node_acl); - struct config_item *df_item; - struct config_group *stats_cg; - int i; - - stats_cg = &acl->se_node_acl.acl_fabric_stat_group; - for (i = 0; stats_cg->default_groups[i]; i++) { - df_item = &stats_cg->default_groups[i]->cg_item; - stats_cg->default_groups[i] = NULL; - config_item_put(df_item); - } - kfree(stats_cg->default_groups); -} - /* End items for lio_target_acl_cit */ /* Start items for lio_target_tpg_attrib_cit */ @@ -1260,64 +1233,52 @@ static struct se_wwn *lio_target_call_coreaddtiqn( struct config_group *group, const char *name) { - struct config_group *stats_cg; struct iscsi_tiqn *tiqn; tiqn = iscsit_add_tiqn((unsigned char *)name); if (IS_ERR(tiqn)) return ERR_CAST(tiqn); - /* - * Setup struct iscsi_wwn_stat_grps for se_wwn->fabric_stat_group. - */ - stats_cg = &tiqn->tiqn_wwn.fabric_stat_group; - - stats_cg->default_groups = kmalloc(sizeof(struct config_group *) * 6, - GFP_KERNEL); - if (!stats_cg->default_groups) { - pr_err("Unable to allocate memory for" - " stats_cg->default_groups\n"); - iscsit_del_tiqn(tiqn); - return ERR_PTR(-ENOMEM); - } - stats_cg->default_groups[0] = &tiqn->tiqn_stat_grps.iscsi_instance_group; - stats_cg->default_groups[1] = &tiqn->tiqn_stat_grps.iscsi_sess_err_group; - stats_cg->default_groups[2] = &tiqn->tiqn_stat_grps.iscsi_tgt_attr_group; - stats_cg->default_groups[3] = &tiqn->tiqn_stat_grps.iscsi_login_stats_group; - stats_cg->default_groups[4] = &tiqn->tiqn_stat_grps.iscsi_logout_stats_group; - stats_cg->default_groups[5] = NULL; + pr_debug("LIO_Target_ConfigFS: REGISTER -> %s\n", tiqn->tiqn); + pr_debug("LIO_Target_ConfigFS: REGISTER -> Allocated Node:" + " %s\n", name); + return &tiqn->tiqn_wwn; +} + +static void lio_target_add_wwn_groups(struct se_wwn *wwn) +{ + struct iscsi_tiqn *tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn); + config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_instance_group, "iscsi_instance", &iscsi_stat_instance_cit); + configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_instance_group, + &tiqn->tiqn_wwn.fabric_stat_group); + config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_sess_err_group, "iscsi_sess_err", &iscsi_stat_sess_err_cit); + configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_sess_err_group, + &tiqn->tiqn_wwn.fabric_stat_group); + config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_tgt_attr_group, "iscsi_tgt_attr", &iscsi_stat_tgt_attr_cit); + configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_tgt_attr_group, + &tiqn->tiqn_wwn.fabric_stat_group); + config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_login_stats_group, "iscsi_login_stats", &iscsi_stat_login_cit); + configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_login_stats_group, + &tiqn->tiqn_wwn.fabric_stat_group); + config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_logout_stats_group, "iscsi_logout_stats", &iscsi_stat_logout_cit); - - pr_debug("LIO_Target_ConfigFS: REGISTER -> %s\n", tiqn->tiqn); - pr_debug("LIO_Target_ConfigFS: REGISTER -> Allocated Node:" - " %s\n", name); - return &tiqn->tiqn_wwn; + configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_logout_stats_group, + &tiqn->tiqn_wwn.fabric_stat_group); } static void lio_target_call_coredeltiqn( struct se_wwn *wwn) { struct iscsi_tiqn *tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn); - struct config_item *df_item; - struct config_group *stats_cg; - int i; - - stats_cg = &tiqn->tiqn_wwn.fabric_stat_group; - for (i = 0; stats_cg->default_groups[i]; i++) { - df_item = &stats_cg->default_groups[i]->cg_item; - stats_cg->default_groups[i] = NULL; - config_item_put(df_item); - } - kfree(stats_cg->default_groups); pr_debug("LIO_Target_ConfigFS: DEREGISTER -> %s\n", tiqn->tiqn); @@ -1693,12 +1654,12 @@ const struct target_core_fabric_ops iscsi_ops = { .aborted_task = lio_aborted_task, .fabric_make_wwn = lio_target_call_coreaddtiqn, .fabric_drop_wwn = lio_target_call_coredeltiqn, + .add_wwn_groups = lio_target_add_wwn_groups, .fabric_make_tpg = lio_target_tiqn_addtpg, .fabric_drop_tpg = lio_target_tiqn_deltpg, .fabric_make_np = lio_target_call_addnptotpg, .fabric_drop_np = lio_target_call_delnpfromtpg, .fabric_init_nodeacl = lio_target_init_nodeacl, - .fabric_cleanup_nodeacl = lio_target_cleanup_nodeacl, .tfc_discovery_attrs = lio_target_discovery_auth_attrs, .tfc_wwn_attrs = lio_target_wwn_attrs, diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 96e78c823..8436d56c5 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -16,9 +16,9 @@ * GNU General Public License for more details. ******************************************************************************/ +#include <crypto/hash.h> #include <linux/string.h> #include <linux/kthread.h> -#include <linux/crypto.h> #include <linux/idr.h> #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> @@ -115,27 +115,36 @@ out_login: */ int iscsi_login_setup_crypto(struct iscsi_conn *conn) { + struct crypto_ahash *tfm; + /* * Setup slicing by CRC32C algorithm for RX and TX libcrypto contexts * which will default to crc32c_intel.ko for cpu_has_xmm4_2, or fallback * to software 1x8 byte slicing from crc32c.ko */ - conn->conn_rx_hash.flags = 0; - conn->conn_rx_hash.tfm = crypto_alloc_hash("crc32c", 0, - CRYPTO_ALG_ASYNC); - if (IS_ERR(conn->conn_rx_hash.tfm)) { - pr_err("crypto_alloc_hash() failed for conn_rx_tfm\n"); + tfm = crypto_alloc_ahash("crc32c", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) { + pr_err("crypto_alloc_ahash() failed\n"); return -ENOMEM; } - conn->conn_tx_hash.flags = 0; - conn->conn_tx_hash.tfm = crypto_alloc_hash("crc32c", 0, - CRYPTO_ALG_ASYNC); - if (IS_ERR(conn->conn_tx_hash.tfm)) { - pr_err("crypto_alloc_hash() failed for conn_tx_tfm\n"); - crypto_free_hash(conn->conn_rx_hash.tfm); + conn->conn_rx_hash = ahash_request_alloc(tfm, GFP_KERNEL); + if (!conn->conn_rx_hash) { + pr_err("ahash_request_alloc() failed for conn_rx_hash\n"); + crypto_free_ahash(tfm); + return -ENOMEM; + } + ahash_request_set_callback(conn->conn_rx_hash, 0, NULL, NULL); + + conn->conn_tx_hash = ahash_request_alloc(tfm, GFP_KERNEL); + if (!conn->conn_tx_hash) { + pr_err("ahash_request_alloc() failed for conn_tx_hash\n"); + ahash_request_free(conn->conn_rx_hash); + conn->conn_rx_hash = NULL; + crypto_free_ahash(tfm); return -ENOMEM; } + ahash_request_set_callback(conn->conn_tx_hash, 0, NULL, NULL); return 0; } @@ -1174,10 +1183,14 @@ old_sess_out: iscsit_dec_session_usage_count(conn->sess); } - if (!IS_ERR(conn->conn_rx_hash.tfm)) - crypto_free_hash(conn->conn_rx_hash.tfm); - if (!IS_ERR(conn->conn_tx_hash.tfm)) - crypto_free_hash(conn->conn_tx_hash.tfm); + ahash_request_free(conn->conn_tx_hash); + if (conn->conn_rx_hash) { + struct crypto_ahash *tfm; + + tfm = crypto_ahash_reqtfm(conn->conn_rx_hash); + ahash_request_free(conn->conn_rx_hash); + crypto_free_ahash(tfm); + } free_cpumask_var(conn->conn_cpumask); diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index d41a5c300..0ad5ac541 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -802,58 +802,48 @@ static struct configfs_attribute *tcm_loop_tpg_attrib_attrs[] = { /* Start items for tcm_loop_nexus_cit */ +static int tcm_loop_alloc_sess_cb(struct se_portal_group *se_tpg, + struct se_session *se_sess, void *p) +{ + struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, + struct tcm_loop_tpg, tl_se_tpg); + + tl_tpg->tl_nexus = p; + return 0; +} + static int tcm_loop_make_nexus( struct tcm_loop_tpg *tl_tpg, const char *name) { - struct se_portal_group *se_tpg; struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; struct tcm_loop_nexus *tl_nexus; - int ret = -ENOMEM; + int ret; if (tl_tpg->tl_nexus) { pr_debug("tl_tpg->tl_nexus already exists\n"); return -EEXIST; } - se_tpg = &tl_tpg->tl_se_tpg; tl_nexus = kzalloc(sizeof(struct tcm_loop_nexus), GFP_KERNEL); if (!tl_nexus) { pr_err("Unable to allocate struct tcm_loop_nexus\n"); return -ENOMEM; } - /* - * Initialize the struct se_session pointer - */ - tl_nexus->se_sess = transport_init_session( - TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS); + + tl_nexus->se_sess = target_alloc_session(&tl_tpg->tl_se_tpg, 0, 0, + TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS, + name, tl_nexus, tcm_loop_alloc_sess_cb); if (IS_ERR(tl_nexus->se_sess)) { ret = PTR_ERR(tl_nexus->se_sess); - goto out; - } - /* - * Since we are running in 'demo mode' this call with generate a - * struct se_node_acl for the tcm_loop struct se_portal_group with the SCSI - * Initiator port name of the passed configfs group 'name'. - */ - tl_nexus->se_sess->se_node_acl = core_tpg_check_initiator_node_acl( - se_tpg, (unsigned char *)name); - if (!tl_nexus->se_sess->se_node_acl) { - transport_free_session(tl_nexus->se_sess); - goto out; + kfree(tl_nexus); + return ret; } - /* Now, register the I_T Nexus as active. */ - transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl, - tl_nexus->se_sess, tl_nexus); - tl_tpg->tl_nexus = tl_nexus; + pr_debug("TCM_Loop_ConfigFS: Established I_T Nexus to emulated" " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba), name); return 0; - -out: - kfree(tl_nexus); - return ret; } static int tcm_loop_drop_nexus( diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 3072f1aca..c57e78849 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -196,45 +196,30 @@ static struct sbp_session *sbp_session_create( struct sbp_session *sess; int ret; char guid_str[17]; - struct se_node_acl *se_nacl; + + snprintf(guid_str, sizeof(guid_str), "%016llx", guid); sess = kmalloc(sizeof(*sess), GFP_KERNEL); if (!sess) { pr_err("failed to allocate session descriptor\n"); return ERR_PTR(-ENOMEM); } + spin_lock_init(&sess->lock); + INIT_LIST_HEAD(&sess->login_list); + INIT_DELAYED_WORK(&sess->maint_work, session_maintenance_work); + sess->guid = guid; - sess->se_sess = transport_init_session(TARGET_PROT_NORMAL); + sess->se_sess = target_alloc_session(&tpg->se_tpg, 128, + sizeof(struct sbp_target_request), + TARGET_PROT_NORMAL, guid_str, + sess, NULL); if (IS_ERR(sess->se_sess)) { pr_err("failed to init se_session\n"); - ret = PTR_ERR(sess->se_sess); kfree(sess); return ERR_PTR(ret); } - snprintf(guid_str, sizeof(guid_str), "%016llx", guid); - - se_nacl = core_tpg_check_initiator_node_acl(&tpg->se_tpg, guid_str); - if (!se_nacl) { - pr_warn("Node ACL not found for %s\n", guid_str); - - transport_free_session(sess->se_sess); - kfree(sess); - - return ERR_PTR(-EPERM); - } - - sess->se_sess->se_node_acl = se_nacl; - - spin_lock_init(&sess->lock); - INIT_LIST_HEAD(&sess->login_list); - INIT_DELAYED_WORK(&sess->maint_work, session_maintenance_work); - - sess->guid = guid; - - transport_register_session(&tpg->se_tpg, se_nacl, sess->se_sess, sess); - return sess; } @@ -908,7 +893,6 @@ static void tgt_agent_process_work(struct work_struct *work) STATUS_BLOCK_SBP_STATUS( SBP_STATUS_REQ_TYPE_NOTSUPP)); sbp_send_status(req); - sbp_free_request(req); return; case 3: /* Dummy ORB */ req->status.status |= cpu_to_be32( @@ -919,7 +903,6 @@ static void tgt_agent_process_work(struct work_struct *work) STATUS_BLOCK_SBP_STATUS( SBP_STATUS_DUMMY_ORB_COMPLETE)); sbp_send_status(req); - sbp_free_request(req); return; default: BUG(); @@ -938,6 +921,25 @@ static inline bool tgt_agent_check_active(struct sbp_target_agent *agent) return active; } +static struct sbp_target_request *sbp_mgt_get_req(struct sbp_session *sess, + struct fw_card *card, u64 next_orb) +{ + struct se_session *se_sess = sess->se_sess; + struct sbp_target_request *req; + int tag; + + tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC); + if (tag < 0) + return ERR_PTR(-ENOMEM); + + req = &((struct sbp_target_request *)se_sess->sess_cmd_map)[tag]; + memset(req, 0, sizeof(*req)); + req->se_cmd.map_tag = tag; + req->se_cmd.tag = next_orb; + + return req; +} + static void tgt_agent_fetch_work(struct work_struct *work) { struct sbp_target_agent *agent = @@ -949,8 +951,8 @@ static void tgt_agent_fetch_work(struct work_struct *work) u64 next_orb = agent->orb_pointer; while (next_orb && tgt_agent_check_active(agent)) { - req = kzalloc(sizeof(*req), GFP_KERNEL); - if (!req) { + req = sbp_mgt_get_req(sess, sess->card, next_orb); + if (IS_ERR(req)) { spin_lock_bh(&agent->lock); agent->state = AGENT_STATE_DEAD; spin_unlock_bh(&agent->lock); @@ -985,7 +987,6 @@ static void tgt_agent_fetch_work(struct work_struct *work) spin_unlock_bh(&agent->lock); sbp_send_status(req); - sbp_free_request(req); return; } @@ -1232,7 +1233,7 @@ static void sbp_handle_command(struct sbp_target_request *req) req->se_cmd.tag = req->orb_pointer; if (target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf, req->sense_buf, unpacked_lun, data_length, - TCM_SIMPLE_TAG, data_dir, 0)) + TCM_SIMPLE_TAG, data_dir, TARGET_SCF_ACK_KREF)) goto err; return; @@ -1244,7 +1245,6 @@ err: STATUS_BLOCK_LEN(1) | STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR)); sbp_send_status(req); - sbp_free_request(req); } /* @@ -1343,22 +1343,29 @@ static int sbp_rw_data(struct sbp_target_request *req) static int sbp_send_status(struct sbp_target_request *req) { - int ret, length; + int rc, ret = 0, length; struct sbp_login_descriptor *login = req->login; length = (((be32_to_cpu(req->status.status) >> 24) & 0x07) + 1) * 4; - ret = sbp_run_request_transaction(req, TCODE_WRITE_BLOCK_REQUEST, + rc = sbp_run_request_transaction(req, TCODE_WRITE_BLOCK_REQUEST, login->status_fifo_addr, &req->status, length); - if (ret != RCODE_COMPLETE) { - pr_debug("sbp_send_status: write failed: 0x%x\n", ret); - return -EIO; + if (rc != RCODE_COMPLETE) { + pr_debug("sbp_send_status: write failed: 0x%x\n", rc); + ret = -EIO; + goto put_ref; } pr_debug("sbp_send_status: status write complete for ORB: 0x%llx\n", req->orb_pointer); - - return 0; + /* + * Drop the extra ACK_KREF reference taken by target_submit_cmd() + * ahead of sbp_check_stop_free() -> transport_generic_free_cmd() + * final se_cmd->cmd_kref put. + */ +put_ref: + target_put_sess_cmd(&req->se_cmd); + return ret; } static void sbp_sense_mangle(struct sbp_target_request *req) @@ -1447,9 +1454,13 @@ static int sbp_send_sense(struct sbp_target_request *req) static void sbp_free_request(struct sbp_target_request *req) { + struct se_cmd *se_cmd = &req->se_cmd; + struct se_session *se_sess = se_cmd->se_sess; + kfree(req->pg_tbl); kfree(req->cmd_buf); - kfree(req); + + percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); } static void sbp_mgt_agent_process(struct work_struct *work) @@ -1609,7 +1620,6 @@ static void sbp_mgt_agent_rw(struct fw_card *card, rcode = RCODE_CONFLICT_ERROR; goto out; } - req = kzalloc(sizeof(*req), GFP_ATOMIC); if (!req) { rcode = RCODE_CONFLICT_ERROR; @@ -1815,8 +1825,7 @@ static int sbp_check_stop_free(struct se_cmd *se_cmd) struct sbp_target_request *req = container_of(se_cmd, struct sbp_target_request, se_cmd); - transport_generic_free_cmd(&req->se_cmd, 0); - return 1; + return transport_generic_free_cmd(&req->se_cmd, 0); } static int sbp_count_se_tpg_luns(struct se_portal_group *tpg) diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 713c63d96..d498533f0 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -194,13 +194,11 @@ static struct config_group *target_core_register_fabric( pr_debug("Target_Core_ConfigFS: REGISTER tfc_wwn_cit -> %p\n", &tf->tf_wwn_cit); - tf->tf_group.default_groups = tf->tf_default_groups; - tf->tf_group.default_groups[0] = &tf->tf_disc_group; - tf->tf_group.default_groups[1] = NULL; - config_group_init_type_name(&tf->tf_group, name, &tf->tf_wwn_cit); + config_group_init_type_name(&tf->tf_disc_group, "discovery_auth", &tf->tf_discovery_cit); + configfs_add_default_group(&tf->tf_disc_group, &tf->tf_group); pr_debug("Target_Core_ConfigFS: REGISTER -> Allocated Fabric:" " %s\n", tf->tf_group.cg_item.ci_name); @@ -216,9 +214,6 @@ static void target_core_deregister_fabric( { struct target_fabric_configfs *tf = container_of( to_config_group(item), struct target_fabric_configfs, tf_group); - struct config_group *tf_group; - struct config_item *df_item; - int i; pr_debug("Target_Core_ConfigFS: DEREGISTER -> Looking up %s in" " tf list\n", config_item_name(item)); @@ -230,12 +225,7 @@ static void target_core_deregister_fabric( pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing ci" " %s\n", config_item_name(item)); - tf_group = &tf->tf_group; - for (i = 0; tf_group->default_groups[i]; i++) { - df_item = &tf_group->default_groups[i]->cg_item; - tf_group->default_groups[i] = NULL; - config_item_put(df_item); - } + configfs_remove_default_groups(&tf->tf_group); config_item_put(item); } @@ -2151,7 +2141,6 @@ static void target_core_dev_release(struct config_item *item) struct se_device *dev = container_of(dev_cg, struct se_device, dev_group); - kfree(dev_cg->default_groups); target_free_device(dev); } @@ -2819,8 +2808,6 @@ static struct config_group *target_core_make_subdev( struct se_hba *hba = item_to_hba(hba_ci); struct target_backend *tb = hba->backend; struct se_device *dev; - struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL; - struct config_group *dev_stat_grp = NULL; int errno = -ENOMEM, ret; ret = mutex_lock_interruptible(&hba->hba_access_mutex); @@ -2831,73 +2818,52 @@ static struct config_group *target_core_make_subdev( if (!dev) goto out_unlock; - dev_cg = &dev->dev_group; - - dev_cg->default_groups = kmalloc(sizeof(struct config_group *) * 6, - GFP_KERNEL); - if (!dev_cg->default_groups) - goto out_free_device; + config_group_init_type_name(&dev->dev_group, name, &tb->tb_dev_cit); - config_group_init_type_name(dev_cg, name, &tb->tb_dev_cit); config_group_init_type_name(&dev->dev_attrib.da_group, "attrib", &tb->tb_dev_attrib_cit); + configfs_add_default_group(&dev->dev_attrib.da_group, &dev->dev_group); + config_group_init_type_name(&dev->dev_pr_group, "pr", &tb->tb_dev_pr_cit); + configfs_add_default_group(&dev->dev_pr_group, &dev->dev_group); + config_group_init_type_name(&dev->t10_wwn.t10_wwn_group, "wwn", &tb->tb_dev_wwn_cit); + configfs_add_default_group(&dev->t10_wwn.t10_wwn_group, + &dev->dev_group); + config_group_init_type_name(&dev->t10_alua.alua_tg_pt_gps_group, "alua", &tb->tb_dev_alua_tg_pt_gps_cit); + configfs_add_default_group(&dev->t10_alua.alua_tg_pt_gps_group, + &dev->dev_group); + config_group_init_type_name(&dev->dev_stat_grps.stat_group, "statistics", &tb->tb_dev_stat_cit); + configfs_add_default_group(&dev->dev_stat_grps.stat_group, + &dev->dev_group); - dev_cg->default_groups[0] = &dev->dev_attrib.da_group; - dev_cg->default_groups[1] = &dev->dev_pr_group; - dev_cg->default_groups[2] = &dev->t10_wwn.t10_wwn_group; - dev_cg->default_groups[3] = &dev->t10_alua.alua_tg_pt_gps_group; - dev_cg->default_groups[4] = &dev->dev_stat_grps.stat_group; - dev_cg->default_groups[5] = NULL; /* * Add core/$HBA/$DEV/alua/default_tg_pt_gp */ tg_pt_gp = core_alua_allocate_tg_pt_gp(dev, "default_tg_pt_gp", 1); if (!tg_pt_gp) - goto out_free_dev_cg_default_groups; + goto out_free_device; dev->t10_alua.default_tg_pt_gp = tg_pt_gp; - tg_pt_gp_cg = &dev->t10_alua.alua_tg_pt_gps_group; - tg_pt_gp_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, - GFP_KERNEL); - if (!tg_pt_gp_cg->default_groups) { - pr_err("Unable to allocate tg_pt_gp_cg->" - "default_groups\n"); - goto out_free_tg_pt_gp; - } - config_group_init_type_name(&tg_pt_gp->tg_pt_gp_group, "default_tg_pt_gp", &target_core_alua_tg_pt_gp_cit); - tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group; - tg_pt_gp_cg->default_groups[1] = NULL; + configfs_add_default_group(&tg_pt_gp->tg_pt_gp_group, + &dev->t10_alua.alua_tg_pt_gps_group); + /* * Add core/$HBA/$DEV/statistics/ default groups */ - dev_stat_grp = &dev->dev_stat_grps.stat_group; - dev_stat_grp->default_groups = kmalloc(sizeof(struct config_group *) * 4, - GFP_KERNEL); - if (!dev_stat_grp->default_groups) { - pr_err("Unable to allocate dev_stat_grp->default_groups\n"); - goto out_free_tg_pt_gp_cg_default_groups; - } target_stat_setup_dev_default_groups(dev); mutex_unlock(&hba->hba_access_mutex); - return dev_cg; + return &dev->dev_group; -out_free_tg_pt_gp_cg_default_groups: - kfree(tg_pt_gp_cg->default_groups); -out_free_tg_pt_gp: - core_alua_free_tg_pt_gp(tg_pt_gp); -out_free_dev_cg_default_groups: - kfree(dev_cg->default_groups); out_free_device: target_free_device(dev); out_unlock: @@ -2913,40 +2879,22 @@ static void target_core_drop_subdev( struct se_device *dev = container_of(dev_cg, struct se_device, dev_group); struct se_hba *hba; - struct config_item *df_item; - struct config_group *tg_pt_gp_cg, *dev_stat_grp; - int i; hba = item_to_hba(&dev->se_hba->hba_group.cg_item); mutex_lock(&hba->hba_access_mutex); - dev_stat_grp = &dev->dev_stat_grps.stat_group; - for (i = 0; dev_stat_grp->default_groups[i]; i++) { - df_item = &dev_stat_grp->default_groups[i]->cg_item; - dev_stat_grp->default_groups[i] = NULL; - config_item_put(df_item); - } - kfree(dev_stat_grp->default_groups); + configfs_remove_default_groups(&dev->dev_stat_grps.stat_group); + configfs_remove_default_groups(&dev->t10_alua.alua_tg_pt_gps_group); - tg_pt_gp_cg = &dev->t10_alua.alua_tg_pt_gps_group; - for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) { - df_item = &tg_pt_gp_cg->default_groups[i]->cg_item; - tg_pt_gp_cg->default_groups[i] = NULL; - config_item_put(df_item); - } - kfree(tg_pt_gp_cg->default_groups); /* * core_alua_free_tg_pt_gp() is called from ->default_tg_pt_gp * directly from target_core_alua_tg_pt_gp_release(). */ dev->t10_alua.default_tg_pt_gp = NULL; - for (i = 0; dev_cg->default_groups[i]; i++) { - df_item = &dev_cg->default_groups[i]->cg_item; - dev_cg->default_groups[i] = NULL; - config_item_put(df_item); - } + configfs_remove_default_groups(dev_cg); + /* * se_dev is released from target_core_dev_item_ops->release() */ @@ -3141,8 +3089,6 @@ void target_setup_backend_cits(struct target_backend *tb) static int __init target_core_init_configfs(void) { - struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL; - struct config_group *lu_gp_cg = NULL; struct configfs_subsystem *subsys = &target_core_fabrics; struct t10_alua_lu_gp *lu_gp; int ret; @@ -3161,51 +3107,24 @@ static int __init target_core_init_configfs(void) * Create $CONFIGFS/target/core default group for HBA <-> Storage Object * and ALUA Logical Unit Group and Target Port Group infrastructure. */ - target_cg = &subsys->su_group; - target_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, - GFP_KERNEL); - if (!target_cg->default_groups) { - pr_err("Unable to allocate target_cg->default_groups\n"); - ret = -ENOMEM; - goto out_global; - } + config_group_init_type_name(&target_core_hbagroup, "core", + &target_core_cit); + configfs_add_default_group(&target_core_hbagroup, &subsys->su_group); - config_group_init_type_name(&target_core_hbagroup, - "core", &target_core_cit); - target_cg->default_groups[0] = &target_core_hbagroup; - target_cg->default_groups[1] = NULL; /* * Create ALUA infrastructure under /sys/kernel/config/target/core/alua/ */ - hba_cg = &target_core_hbagroup; - hba_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, - GFP_KERNEL); - if (!hba_cg->default_groups) { - pr_err("Unable to allocate hba_cg->default_groups\n"); - ret = -ENOMEM; - goto out_global; - } - config_group_init_type_name(&alua_group, - "alua", &target_core_alua_cit); - hba_cg->default_groups[0] = &alua_group; - hba_cg->default_groups[1] = NULL; + config_group_init_type_name(&alua_group, "alua", &target_core_alua_cit); + configfs_add_default_group(&alua_group, &target_core_hbagroup); + /* * Add ALUA Logical Unit Group and Target Port Group ConfigFS * groups under /sys/kernel/config/target/core/alua/ */ - alua_cg = &alua_group; - alua_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, - GFP_KERNEL); - if (!alua_cg->default_groups) { - pr_err("Unable to allocate alua_cg->default_groups\n"); - ret = -ENOMEM; - goto out_global; - } + config_group_init_type_name(&alua_lu_gps_group, "lu_gps", + &target_core_alua_lu_gps_cit); + configfs_add_default_group(&alua_lu_gps_group, &alua_group); - config_group_init_type_name(&alua_lu_gps_group, - "lu_gps", &target_core_alua_lu_gps_cit); - alua_cg->default_groups[0] = &alua_lu_gps_group; - alua_cg->default_groups[1] = NULL; /* * Add core/alua/lu_gps/default_lu_gp */ @@ -3215,20 +3134,12 @@ static int __init target_core_init_configfs(void) goto out_global; } - lu_gp_cg = &alua_lu_gps_group; - lu_gp_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, - GFP_KERNEL); - if (!lu_gp_cg->default_groups) { - pr_err("Unable to allocate lu_gp_cg->default_groups\n"); - ret = -ENOMEM; - goto out_global; - } - config_group_init_type_name(&lu_gp->lu_gp_group, "default_lu_gp", &target_core_alua_lu_gp_cit); - lu_gp_cg->default_groups[0] = &lu_gp->lu_gp_group; - lu_gp_cg->default_groups[1] = NULL; + configfs_add_default_group(&lu_gp->lu_gp_group, &alua_lu_gps_group); + default_lu_gp = lu_gp; + /* * Register the target_core_mod subsystem with configfs. */ @@ -3267,55 +3178,21 @@ out_global: core_alua_free_lu_gp(default_lu_gp); default_lu_gp = NULL; } - if (lu_gp_cg) - kfree(lu_gp_cg->default_groups); - if (alua_cg) - kfree(alua_cg->default_groups); - if (hba_cg) - kfree(hba_cg->default_groups); - kfree(target_cg->default_groups); release_se_kmem_caches(); return ret; } static void __exit target_core_exit_configfs(void) { - struct config_group *hba_cg, *alua_cg, *lu_gp_cg; - struct config_item *item; - int i; + configfs_remove_default_groups(&alua_lu_gps_group); + configfs_remove_default_groups(&alua_group); + configfs_remove_default_groups(&target_core_hbagroup); - lu_gp_cg = &alua_lu_gps_group; - for (i = 0; lu_gp_cg->default_groups[i]; i++) { - item = &lu_gp_cg->default_groups[i]->cg_item; - lu_gp_cg->default_groups[i] = NULL; - config_item_put(item); - } - kfree(lu_gp_cg->default_groups); - lu_gp_cg->default_groups = NULL; - - alua_cg = &alua_group; - for (i = 0; alua_cg->default_groups[i]; i++) { - item = &alua_cg->default_groups[i]->cg_item; - alua_cg->default_groups[i] = NULL; - config_item_put(item); - } - kfree(alua_cg->default_groups); - alua_cg->default_groups = NULL; - - hba_cg = &target_core_hbagroup; - for (i = 0; hba_cg->default_groups[i]; i++) { - item = &hba_cg->default_groups[i]->cg_item; - hba_cg->default_groups[i] = NULL; - config_item_put(item); - } - kfree(hba_cg->default_groups); - hba_cg->default_groups = NULL; /* * We expect subsys->su_group.default_groups to be released * by configfs subsystem provider logic.. */ configfs_unregister_subsystem(&target_core_fabrics); - kfree(target_core_fabrics.su_group.default_groups); core_alua_free_lu_gp(default_lu_gp); default_lu_gp = NULL; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index da457e257..a4046ca6e 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -86,7 +86,7 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u64 unpacked_lun) se_cmd->lun_ref_active = true; if ((se_cmd->data_direction == DMA_TO_DEVICE) && - (deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)) { + deve->lun_access_ro) { pr_err("TARGET_CORE[%s]: Detected WRITE_PROTECTED LUN" " Access for 0x%08llx\n", se_cmd->se_tfo->get_fabric_name(), @@ -199,7 +199,7 @@ bool target_lun_is_rdonly(struct se_cmd *cmd) rcu_read_lock(); deve = target_nacl_find_deve(se_sess->se_node_acl, cmd->orig_fe_lun); - ret = (deve && deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY); + ret = deve && deve->lun_access_ro; rcu_read_unlock(); return ret; @@ -258,22 +258,15 @@ void core_free_device_list_for_node( void core_update_device_list_access( u64 mapped_lun, - u32 lun_access, + bool lun_access_ro, struct se_node_acl *nacl) { struct se_dev_entry *deve; mutex_lock(&nacl->lun_entry_mutex); deve = target_nacl_find_deve(nacl, mapped_lun); - if (deve) { - if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) { - deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY; - deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE; - } else { - deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE; - deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; - } - } + if (deve) + deve->lun_access_ro = lun_access_ro; mutex_unlock(&nacl->lun_entry_mutex); } @@ -319,7 +312,7 @@ int core_enable_device_list_for_node( struct se_lun *lun, struct se_lun_acl *lun_acl, u64 mapped_lun, - u32 lun_access, + bool lun_access_ro, struct se_node_acl *nacl, struct se_portal_group *tpg) { @@ -340,11 +333,7 @@ int core_enable_device_list_for_node( kref_init(&new->pr_kref); init_completion(&new->pr_comp); - if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) - new->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE; - else - new->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; - + new->lun_access_ro = lun_access_ro; new->creation_time = get_jiffies_64(); new->attach_count++; @@ -433,7 +422,7 @@ void core_disable_device_list_for_node( hlist_del_rcu(&orig->link); clear_bit(DEF_PR_REG_ACTIVE, &orig->deve_flags); - orig->lun_flags = 0; + orig->lun_access_ro = false; orig->creation_time = 0; orig->attach_count--; /* @@ -558,8 +547,7 @@ int core_dev_add_lun( { int rc; - rc = core_tpg_add_lun(tpg, lun, - TRANSPORT_LUNFLAGS_READ_WRITE, dev); + rc = core_tpg_add_lun(tpg, lun, false, dev); if (rc < 0) return rc; @@ -635,7 +623,7 @@ int core_dev_add_initiator_node_lun_acl( struct se_portal_group *tpg, struct se_lun_acl *lacl, struct se_lun *lun, - u32 lun_access) + bool lun_access_ro) { struct se_node_acl *nacl = lacl->se_lun_nacl; /* @@ -647,20 +635,19 @@ int core_dev_add_initiator_node_lun_acl( if (!nacl) return -EINVAL; - if ((lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) && - (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE)) - lun_access = TRANSPORT_LUNFLAGS_READ_ONLY; + if (lun->lun_access_ro) + lun_access_ro = true; lacl->se_lun = lun; if (core_enable_device_list_for_node(lun, lacl, lacl->mapped_lun, - lun_access, nacl, tpg) < 0) + lun_access_ro, nacl, tpg) < 0) return -EINVAL; pr_debug("%s_TPG[%hu]_LUN[%llu->%llu] - Added %s ACL for " " InitiatorNode: %s\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, lacl->mapped_lun, - (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) ? "RW" : "RO", + lun_access_ro ? "RO" : "RW", nacl->initiatorname); /* * Check to see if there are any existing persistent reservation APTPL diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index f916d18cc..31a096aa1 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -78,7 +78,7 @@ static int target_fabric_mappedlun_link( struct se_lun_acl, se_lun_group); struct se_portal_group *se_tpg; struct config_item *nacl_ci, *tpg_ci, *tpg_ci_s, *wwn_ci, *wwn_ci_s; - int lun_access; + bool lun_access_ro; if (lun->lun_link_magic != SE_LUN_LINK_MAGIC) { pr_err("Bad lun->lun_link_magic, not a valid lun_ci pointer:" @@ -115,19 +115,18 @@ static int target_fabric_mappedlun_link( } /* * If this struct se_node_acl was dynamically generated with - * tpg_1/attrib/generate_node_acls=1, use the existing deve->lun_flags, - * which be will write protected (READ-ONLY) when + * tpg_1/attrib/generate_node_acls=1, use the existing + * deve->lun_access_ro value, which will be true when * tpg_1/attrib/demo_mode_write_protect=1 */ rcu_read_lock(); deve = target_nacl_find_deve(lacl->se_lun_nacl, lacl->mapped_lun); if (deve) - lun_access = deve->lun_flags; + lun_access_ro = deve->lun_access_ro; else - lun_access = + lun_access_ro = (se_tpg->se_tpg_tfo->tpg_check_prod_mode_write_protect( - se_tpg)) ? TRANSPORT_LUNFLAGS_READ_ONLY : - TRANSPORT_LUNFLAGS_READ_WRITE; + se_tpg)) ? true : false; rcu_read_unlock(); /* * Determine the actual mapped LUN value user wants.. @@ -135,7 +134,7 @@ static int target_fabric_mappedlun_link( * This value is what the SCSI Initiator actually sees the * $FABRIC/$WWPN/$TPGT/lun/lun_* as on their SCSI Initiator Ports. */ - return core_dev_add_initiator_node_lun_acl(se_tpg, lacl, lun, lun_access); + return core_dev_add_initiator_node_lun_acl(se_tpg, lacl, lun, lun_access_ro); } static int target_fabric_mappedlun_unlink( @@ -167,8 +166,7 @@ static ssize_t target_fabric_mappedlun_write_protect_show( rcu_read_lock(); deve = target_nacl_find_deve(se_nacl, lacl->mapped_lun); if (deve) { - len = sprintf(page, "%d\n", - (deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) ? 1 : 0); + len = sprintf(page, "%d\n", deve->lun_access_ro); } rcu_read_unlock(); @@ -181,25 +179,23 @@ static ssize_t target_fabric_mappedlun_write_protect_store( struct se_lun_acl *lacl = item_to_lun_acl(item); struct se_node_acl *se_nacl = lacl->se_lun_nacl; struct se_portal_group *se_tpg = se_nacl->se_tpg; - unsigned long op; + unsigned long wp; int ret; - ret = kstrtoul(page, 0, &op); + ret = kstrtoul(page, 0, &wp); if (ret) return ret; - if ((op != 1) && (op != 0)) + if ((wp != 1) && (wp != 0)) return -EINVAL; - core_update_device_list_access(lacl->mapped_lun, (op) ? - TRANSPORT_LUNFLAGS_READ_ONLY : - TRANSPORT_LUNFLAGS_READ_WRITE, - lacl->se_lun_nacl); + /* wp=1 means lun_access_ro=true */ + core_update_device_list_access(lacl->mapped_lun, wp, lacl->se_lun_nacl); pr_debug("%s_ConfigFS: Changed Initiator ACL: %s" " Mapped LUN: %llu Write Protect bit to %s\n", se_tpg->se_tpg_tfo->get_fabric_name(), - se_nacl->initiatorname, lacl->mapped_lun, (op) ? "ON" : "OFF"); + se_nacl->initiatorname, lacl->mapped_lun, (wp) ? "ON" : "OFF"); return count; @@ -273,18 +269,10 @@ static struct config_group *target_fabric_make_mappedlun( struct se_portal_group *se_tpg = se_nacl->se_tpg; struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; struct se_lun_acl *lacl = NULL; - struct config_item *acl_ci; - struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL; char *buf; unsigned long long mapped_lun; int ret = 0; - acl_ci = &group->cg_item; - if (!acl_ci) { - pr_err("Unable to locatel acl_ci\n"); - return NULL; - } - buf = kzalloc(strlen(name) + 1, GFP_KERNEL); if (!buf) { pr_err("Unable to allocate memory for name buf\n"); @@ -315,37 +303,19 @@ static struct config_group *target_fabric_make_mappedlun( goto out; } - lacl_cg = &lacl->se_lun_group; - lacl_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, - GFP_KERNEL); - if (!lacl_cg->default_groups) { - pr_err("Unable to allocate lacl_cg->default_groups\n"); - ret = -ENOMEM; - goto out; - } - config_group_init_type_name(&lacl->se_lun_group, name, &tf->tf_tpg_mappedlun_cit); + config_group_init_type_name(&lacl->ml_stat_grps.stat_group, "statistics", &tf->tf_tpg_mappedlun_stat_cit); - lacl_cg->default_groups[0] = &lacl->ml_stat_grps.stat_group; - lacl_cg->default_groups[1] = NULL; - - ml_stat_grp = &lacl->ml_stat_grps.stat_group; - ml_stat_grp->default_groups = kmalloc(sizeof(struct config_group *) * 3, - GFP_KERNEL); - if (!ml_stat_grp->default_groups) { - pr_err("Unable to allocate ml_stat_grp->default_groups\n"); - ret = -ENOMEM; - goto out; - } + configfs_add_default_group(&lacl->ml_stat_grps.stat_group, + &lacl->se_lun_group); + target_stat_setup_mappedlun_default_groups(lacl); kfree(buf); return &lacl->se_lun_group; out: - if (lacl_cg) - kfree(lacl_cg->default_groups); kfree(lacl); kfree(buf); return ERR_PTR(ret); @@ -357,25 +327,9 @@ static void target_fabric_drop_mappedlun( { struct se_lun_acl *lacl = container_of(to_config_group(item), struct se_lun_acl, se_lun_group); - struct config_item *df_item; - struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL; - int i; - - ml_stat_grp = &lacl->ml_stat_grps.stat_group; - for (i = 0; ml_stat_grp->default_groups[i]; i++) { - df_item = &ml_stat_grp->default_groups[i]->cg_item; - ml_stat_grp->default_groups[i] = NULL; - config_item_put(df_item); - } - kfree(ml_stat_grp->default_groups); - lacl_cg = &lacl->se_lun_group; - for (i = 0; lacl_cg->default_groups[i]; i++) { - df_item = &lacl_cg->default_groups[i]->cg_item; - lacl_cg->default_groups[i] = NULL; - config_item_put(df_item); - } - kfree(lacl_cg->default_groups); + configfs_remove_default_groups(&lacl->ml_stat_grps.stat_group); + configfs_remove_default_groups(&lacl->se_lun_group); config_item_put(item); } @@ -384,10 +338,8 @@ static void target_fabric_nacl_base_release(struct config_item *item) { struct se_node_acl *se_nacl = container_of(to_config_group(item), struct se_node_acl, acl_group); - struct target_fabric_configfs *tf = se_nacl->se_tpg->se_tpg_wwn->wwn_tf; - if (tf->tf_ops->fabric_cleanup_nodeacl) - tf->tf_ops->fabric_cleanup_nodeacl(se_nacl); + configfs_remove_default_groups(&se_nacl->acl_fabric_stat_group); core_tpg_del_initiator_node_acl(se_nacl); } @@ -424,38 +376,42 @@ static struct config_group *target_fabric_make_nodeacl( struct se_portal_group, tpg_acl_group); struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; struct se_node_acl *se_nacl; - struct config_group *nacl_cg; se_nacl = core_tpg_add_initiator_node_acl(se_tpg, name); if (IS_ERR(se_nacl)) return ERR_CAST(se_nacl); - if (tf->tf_ops->fabric_init_nodeacl) { - int ret = tf->tf_ops->fabric_init_nodeacl(se_nacl, name); - if (ret) { - core_tpg_del_initiator_node_acl(se_nacl); - return ERR_PTR(ret); - } - } - - nacl_cg = &se_nacl->acl_group; - nacl_cg->default_groups = se_nacl->acl_default_groups; - nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group; - nacl_cg->default_groups[1] = &se_nacl->acl_auth_group; - nacl_cg->default_groups[2] = &se_nacl->acl_param_group; - nacl_cg->default_groups[3] = &se_nacl->acl_fabric_stat_group; - nacl_cg->default_groups[4] = NULL; - config_group_init_type_name(&se_nacl->acl_group, name, &tf->tf_tpg_nacl_base_cit); + config_group_init_type_name(&se_nacl->acl_attrib_group, "attrib", &tf->tf_tpg_nacl_attrib_cit); + configfs_add_default_group(&se_nacl->acl_attrib_group, + &se_nacl->acl_group); + config_group_init_type_name(&se_nacl->acl_auth_group, "auth", &tf->tf_tpg_nacl_auth_cit); + configfs_add_default_group(&se_nacl->acl_auth_group, + &se_nacl->acl_group); + config_group_init_type_name(&se_nacl->acl_param_group, "param", &tf->tf_tpg_nacl_param_cit); + configfs_add_default_group(&se_nacl->acl_param_group, + &se_nacl->acl_group); + config_group_init_type_name(&se_nacl->acl_fabric_stat_group, "fabric_statistics", &tf->tf_tpg_nacl_stat_cit); + configfs_add_default_group(&se_nacl->acl_fabric_stat_group, + &se_nacl->acl_group); + + if (tf->tf_ops->fabric_init_nodeacl) { + int ret = tf->tf_ops->fabric_init_nodeacl(se_nacl, name); + if (ret) { + configfs_remove_default_groups(&se_nacl->acl_fabric_stat_group); + core_tpg_del_initiator_node_acl(se_nacl); + return ERR_PTR(ret); + } + } return &se_nacl->acl_group; } @@ -466,16 +422,9 @@ static void target_fabric_drop_nodeacl( { struct se_node_acl *se_nacl = container_of(to_config_group(item), struct se_node_acl, acl_group); - struct config_item *df_item; - struct config_group *nacl_cg; - int i; - - nacl_cg = &se_nacl->acl_group; - for (i = 0; nacl_cg->default_groups[i]; i++) { - df_item = &nacl_cg->default_groups[i]->cg_item; - nacl_cg->default_groups[i] = NULL; - config_item_put(df_item); - } + + configfs_remove_default_groups(&se_nacl->acl_group); + /* * struct se_node_acl free is done in target_fabric_nacl_base_release() */ @@ -795,7 +744,6 @@ static struct config_group *target_fabric_make_lun( struct se_portal_group *se_tpg = container_of(group, struct se_portal_group, tpg_lun_group); struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; - struct config_group *lun_cg = NULL, *port_stat_grp = NULL; unsigned long long unpacked_lun; int errno; @@ -812,31 +760,14 @@ static struct config_group *target_fabric_make_lun( if (IS_ERR(lun)) return ERR_CAST(lun); - lun_cg = &lun->lun_group; - lun_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, - GFP_KERNEL); - if (!lun_cg->default_groups) { - pr_err("Unable to allocate lun_cg->default_groups\n"); - kfree(lun); - return ERR_PTR(-ENOMEM); - } - config_group_init_type_name(&lun->lun_group, name, &tf->tf_tpg_port_cit); + config_group_init_type_name(&lun->port_stat_grps.stat_group, "statistics", &tf->tf_tpg_port_stat_cit); - lun_cg->default_groups[0] = &lun->port_stat_grps.stat_group; - lun_cg->default_groups[1] = NULL; - - port_stat_grp = &lun->port_stat_grps.stat_group; - port_stat_grp->default_groups = kzalloc(sizeof(struct config_group *) * 4, - GFP_KERNEL); - if (!port_stat_grp->default_groups) { - pr_err("Unable to allocate port_stat_grp->default_groups\n"); - kfree(lun_cg->default_groups); - kfree(lun); - return ERR_PTR(-ENOMEM); - } + configfs_add_default_group(&lun->port_stat_grps.stat_group, + &lun->lun_group); + target_stat_setup_port_default_groups(lun); return &lun->lun_group; @@ -848,25 +779,9 @@ static void target_fabric_drop_lun( { struct se_lun *lun = container_of(to_config_group(item), struct se_lun, lun_group); - struct config_item *df_item; - struct config_group *lun_cg, *port_stat_grp; - int i; - - port_stat_grp = &lun->port_stat_grps.stat_group; - for (i = 0; port_stat_grp->default_groups[i]; i++) { - df_item = &port_stat_grp->default_groups[i]->cg_item; - port_stat_grp->default_groups[i] = NULL; - config_item_put(df_item); - } - kfree(port_stat_grp->default_groups); - lun_cg = &lun->lun_group; - for (i = 0; lun_cg->default_groups[i]; i++) { - df_item = &lun_cg->default_groups[i]->cg_item; - lun_cg->default_groups[i] = NULL; - config_item_put(df_item); - } - kfree(lun_cg->default_groups); + configfs_remove_default_groups(&lun->port_stat_grps.stat_group); + configfs_remove_default_groups(&lun->lun_group); config_item_put(item); } @@ -922,32 +837,39 @@ static struct config_group *target_fabric_make_tpg( se_tpg = tf->tf_ops->fabric_make_tpg(wwn, group, name); if (!se_tpg || IS_ERR(se_tpg)) return ERR_PTR(-EINVAL); - /* - * Setup default groups from pre-allocated se_tpg->tpg_default_groups - */ - se_tpg->tpg_group.default_groups = se_tpg->tpg_default_groups; - se_tpg->tpg_group.default_groups[0] = &se_tpg->tpg_lun_group; - se_tpg->tpg_group.default_groups[1] = &se_tpg->tpg_np_group; - se_tpg->tpg_group.default_groups[2] = &se_tpg->tpg_acl_group; - se_tpg->tpg_group.default_groups[3] = &se_tpg->tpg_attrib_group; - se_tpg->tpg_group.default_groups[4] = &se_tpg->tpg_auth_group; - se_tpg->tpg_group.default_groups[5] = &se_tpg->tpg_param_group; - se_tpg->tpg_group.default_groups[6] = NULL; config_group_init_type_name(&se_tpg->tpg_group, name, &tf->tf_tpg_base_cit); + config_group_init_type_name(&se_tpg->tpg_lun_group, "lun", &tf->tf_tpg_lun_cit); + configfs_add_default_group(&se_tpg->tpg_lun_group, + &se_tpg->tpg_group); + config_group_init_type_name(&se_tpg->tpg_np_group, "np", &tf->tf_tpg_np_cit); + configfs_add_default_group(&se_tpg->tpg_np_group, + &se_tpg->tpg_group); + config_group_init_type_name(&se_tpg->tpg_acl_group, "acls", &tf->tf_tpg_nacl_cit); + configfs_add_default_group(&se_tpg->tpg_acl_group, + &se_tpg->tpg_group); + config_group_init_type_name(&se_tpg->tpg_attrib_group, "attrib", &tf->tf_tpg_attrib_cit); + configfs_add_default_group(&se_tpg->tpg_attrib_group, + &se_tpg->tpg_group); + config_group_init_type_name(&se_tpg->tpg_auth_group, "auth", &tf->tf_tpg_auth_cit); + configfs_add_default_group(&se_tpg->tpg_auth_group, + &se_tpg->tpg_group); + config_group_init_type_name(&se_tpg->tpg_param_group, "param", &tf->tf_tpg_param_cit); + configfs_add_default_group(&se_tpg->tpg_param_group, + &se_tpg->tpg_group); return &se_tpg->tpg_group; } @@ -958,19 +880,8 @@ static void target_fabric_drop_tpg( { struct se_portal_group *se_tpg = container_of(to_config_group(item), struct se_portal_group, tpg_group); - struct config_group *tpg_cg = &se_tpg->tpg_group; - struct config_item *df_item; - int i; - /* - * Release default groups, but do not release tpg_cg->default_groups - * memory as it is statically allocated at se_tpg->tpg_default_groups. - */ - for (i = 0; tpg_cg->default_groups[i]; i++) { - df_item = &tpg_cg->default_groups[i]->cg_item; - tpg_cg->default_groups[i] = NULL; - config_item_put(df_item); - } + configfs_remove_default_groups(&se_tpg->tpg_group); config_item_put(item); } @@ -980,6 +891,7 @@ static void target_fabric_release_wwn(struct config_item *item) struct se_wwn, wwn_group); struct target_fabric_configfs *tf = wwn->wwn_tf; + configfs_remove_default_groups(&wwn->fabric_stat_group); tf->tf_ops->fabric_drop_wwn(wwn); } @@ -1026,17 +938,15 @@ static struct config_group *target_fabric_make_wwn( return ERR_PTR(-EINVAL); wwn->wwn_tf = tf; - /* - * Setup default groups from pre-allocated wwn->wwn_default_groups - */ - wwn->wwn_group.default_groups = wwn->wwn_default_groups; - wwn->wwn_group.default_groups[0] = &wwn->fabric_stat_group; - wwn->wwn_group.default_groups[1] = NULL; config_group_init_type_name(&wwn->wwn_group, name, &tf->tf_tpg_cit); + config_group_init_type_name(&wwn->fabric_stat_group, "fabric_statistics", &tf->tf_wwn_fabric_stats_cit); + configfs_add_default_group(&wwn->fabric_stat_group, &wwn->wwn_group); + if (tf->tf_ops->add_wwn_groups) + tf->tf_ops->add_wwn_groups(wwn); return &wwn->wwn_group; } @@ -1046,16 +956,8 @@ static void target_fabric_drop_wwn( { struct se_wwn *wwn = container_of(to_config_group(item), struct se_wwn, wwn_group); - struct config_item *df_item; - struct config_group *cg = &wwn->wwn_group; - int i; - - for (i = 0; cg->default_groups[i]; i++) { - df_item = &cg->default_groups[i]->cg_item; - cg->default_groups[i] = NULL; - config_item_put(df_item); - } + configfs_remove_default_groups(&wwn->wwn_group); config_item_put(item); } diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index abe4eb997..026a758e5 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -413,8 +413,39 @@ iblock_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) } static sense_reason_t +iblock_execute_write_same_direct(struct block_device *bdev, struct se_cmd *cmd) +{ + struct se_device *dev = cmd->se_dev; + struct scatterlist *sg = &cmd->t_data_sg[0]; + struct page *page = NULL; + int ret; + + if (sg->offset) { + page = alloc_page(GFP_KERNEL); + if (!page) + return TCM_OUT_OF_RESOURCES; + sg_copy_to_buffer(sg, cmd->t_data_nents, page_address(page), + dev->dev_attrib.block_size); + } + + ret = blkdev_issue_write_same(bdev, + target_to_linux_sector(dev, cmd->t_task_lba), + target_to_linux_sector(dev, + sbc_get_write_same_sectors(cmd)), + GFP_KERNEL, page ? page : sg_page(sg)); + if (page) + __free_page(page); + if (ret) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + + target_complete_cmd(cmd, GOOD); + return 0; +} + +static sense_reason_t iblock_execute_write_same(struct se_cmd *cmd) { + struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; struct iblock_req *ibr; struct scatterlist *sg; struct bio *bio; @@ -439,6 +470,9 @@ iblock_execute_write_same(struct se_cmd *cmd) return TCM_INVALID_CDB_FIELD; } + if (bdev_write_same(bdev)) + return iblock_execute_write_same_direct(bdev, cmd); + ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); if (!ibr) goto fail; diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index db4412fe6..86b4a8375 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -22,7 +22,6 @@ struct target_fabric_configfs { struct list_head tf_list; struct config_group tf_group; struct config_group tf_disc_group; - struct config_group *tf_default_groups[2]; const struct target_core_fabric_ops *tf_ops; struct config_item_type tf_discovery_cit; @@ -60,10 +59,10 @@ struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16); void target_pr_kref_release(struct kref *); void core_free_device_list_for_node(struct se_node_acl *, struct se_portal_group *); -void core_update_device_list_access(u64, u32, struct se_node_acl *); +void core_update_device_list_access(u64, bool, struct se_node_acl *); struct se_dev_entry *target_nacl_find_deve(struct se_node_acl *, u64); int core_enable_device_list_for_node(struct se_lun *, struct se_lun_acl *, - u64, u32, struct se_node_acl *, struct se_portal_group *); + u64, bool, struct se_node_acl *, struct se_portal_group *); void core_disable_device_list_for_node(struct se_lun *, struct se_dev_entry *, struct se_node_acl *, struct se_portal_group *); void core_clear_lun_from_tpg(struct se_lun *, struct se_portal_group *); @@ -73,7 +72,7 @@ void core_dev_del_lun(struct se_portal_group *, struct se_lun *); struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *, struct se_node_acl *, u64, int *); int core_dev_add_initiator_node_lun_acl(struct se_portal_group *, - struct se_lun_acl *, struct se_lun *lun, u32); + struct se_lun_acl *, struct se_lun *lun, bool); int core_dev_del_initiator_node_lun_acl(struct se_lun *, struct se_lun_acl *); void core_dev_free_initiator_node_lun_acl(struct se_portal_group *, @@ -119,7 +118,7 @@ void core_tpg_add_node_to_devs(struct se_node_acl *, struct se_portal_group *, void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *); struct se_lun *core_tpg_alloc_lun(struct se_portal_group *, u64); int core_tpg_add_lun(struct se_portal_group *, struct se_lun *, - u32, struct se_device *); + bool, struct se_device *); void core_tpg_remove_lun(struct se_portal_group *, struct se_lun *); struct se_node_acl *core_tpg_add_initiator_node_acl(struct se_portal_group *tpg, const char *initiatorname); diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 0aa47babd..2a91ed3ef 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -997,7 +997,6 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd) int length = 0; int ret; int i; - bool read_only = target_lun_is_rdonly(cmd);; memset(buf, 0, SE_MODE_PAGE_BUF); @@ -1008,7 +1007,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd) length = ten ? 3 : 2; /* DEVICE-SPECIFIC PARAMETER */ - if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || read_only) + if (cmd->se_lun->lun_access_ro || target_lun_is_rdonly(cmd)) spc_modesense_write_protect(&buf[length], type); /* diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index 81a6b3e07..1a39033d2 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c @@ -407,19 +407,20 @@ static struct config_item_type target_stat_scsi_lu_cit = { */ void target_stat_setup_dev_default_groups(struct se_device *dev) { - struct config_group *dev_stat_grp = &dev->dev_stat_grps.stat_group; - config_group_init_type_name(&dev->dev_stat_grps.scsi_dev_group, "scsi_dev", &target_stat_scsi_dev_cit); + configfs_add_default_group(&dev->dev_stat_grps.scsi_dev_group, + &dev->dev_stat_grps.stat_group); + config_group_init_type_name(&dev->dev_stat_grps.scsi_tgt_dev_group, "scsi_tgt_dev", &target_stat_scsi_tgt_dev_cit); + configfs_add_default_group(&dev->dev_stat_grps.scsi_tgt_dev_group, + &dev->dev_stat_grps.stat_group); + config_group_init_type_name(&dev->dev_stat_grps.scsi_lu_group, "scsi_lu", &target_stat_scsi_lu_cit); - - dev_stat_grp->default_groups[0] = &dev->dev_stat_grps.scsi_dev_group; - dev_stat_grp->default_groups[1] = &dev->dev_stat_grps.scsi_tgt_dev_group; - dev_stat_grp->default_groups[2] = &dev->dev_stat_grps.scsi_lu_group; - dev_stat_grp->default_groups[3] = NULL; + configfs_add_default_group(&dev->dev_stat_grps.scsi_lu_group, + &dev->dev_stat_grps.stat_group); } /* @@ -818,19 +819,20 @@ static struct config_item_type target_stat_scsi_transport_cit = { */ void target_stat_setup_port_default_groups(struct se_lun *lun) { - struct config_group *port_stat_grp = &lun->port_stat_grps.stat_group; - config_group_init_type_name(&lun->port_stat_grps.scsi_port_group, "scsi_port", &target_stat_scsi_port_cit); + configfs_add_default_group(&lun->port_stat_grps.scsi_port_group, + &lun->port_stat_grps.stat_group); + config_group_init_type_name(&lun->port_stat_grps.scsi_tgt_port_group, "scsi_tgt_port", &target_stat_scsi_tgt_port_cit); + configfs_add_default_group(&lun->port_stat_grps.scsi_tgt_port_group, + &lun->port_stat_grps.stat_group); + config_group_init_type_name(&lun->port_stat_grps.scsi_transport_group, "scsi_transport", &target_stat_scsi_transport_cit); - - port_stat_grp->default_groups[0] = &lun->port_stat_grps.scsi_port_group; - port_stat_grp->default_groups[1] = &lun->port_stat_grps.scsi_tgt_port_group; - port_stat_grp->default_groups[2] = &lun->port_stat_grps.scsi_transport_group; - port_stat_grp->default_groups[3] = NULL; + configfs_add_default_group(&lun->port_stat_grps.scsi_transport_group, + &lun->port_stat_grps.stat_group); } /* @@ -1351,14 +1353,13 @@ static struct config_item_type target_stat_scsi_att_intr_port_cit = { */ void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *lacl) { - struct config_group *ml_stat_grp = &lacl->ml_stat_grps.stat_group; - config_group_init_type_name(&lacl->ml_stat_grps.scsi_auth_intr_group, "scsi_auth_intr", &target_stat_scsi_auth_intr_cit); + configfs_add_default_group(&lacl->ml_stat_grps.scsi_auth_intr_group, + &lacl->ml_stat_grps.stat_group); + config_group_init_type_name(&lacl->ml_stat_grps.scsi_att_intr_port_group, "scsi_att_intr_port", &target_stat_scsi_att_intr_port_cit); - - ml_stat_grp->default_groups[0] = &lacl->ml_stat_grps.scsi_auth_intr_group; - ml_stat_grp->default_groups[1] = &lacl->ml_stat_grps.scsi_att_intr_port_group; - ml_stat_grp->default_groups[2] = NULL; + configfs_add_default_group(&lacl->ml_stat_grps.scsi_att_intr_port_group, + &lacl->ml_stat_grps.stat_group); } diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 3608b1b5e..ddf046080 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -121,7 +121,7 @@ void core_tpg_add_node_to_devs( struct se_portal_group *tpg, struct se_lun *lun_orig) { - u32 lun_access = 0; + bool lun_access_ro = true; struct se_lun *lun; struct se_device *dev; @@ -137,27 +137,26 @@ void core_tpg_add_node_to_devs( * demo_mode_write_protect is ON, or READ_ONLY; */ if (!tpg->se_tpg_tfo->tpg_check_demo_mode_write_protect(tpg)) { - lun_access = TRANSPORT_LUNFLAGS_READ_WRITE; + lun_access_ro = false; } else { /* * Allow only optical drives to issue R/W in default RO * demo mode. */ if (dev->transport->get_device_type(dev) == TYPE_DISK) - lun_access = TRANSPORT_LUNFLAGS_READ_ONLY; + lun_access_ro = true; else - lun_access = TRANSPORT_LUNFLAGS_READ_WRITE; + lun_access_ro = false; } pr_debug("TARGET_CORE[%s]->TPG[%u]_LUN[%llu] - Adding %s" " access for LUN in Demo Mode\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, - (lun_access == TRANSPORT_LUNFLAGS_READ_WRITE) ? - "READ-WRITE" : "READ-ONLY"); + lun_access_ro ? "READ-ONLY" : "READ-WRITE"); core_enable_device_list_for_node(lun, NULL, lun->unpacked_lun, - lun_access, acl, tpg); + lun_access_ro, acl, tpg); /* * Check to see if there are any existing persistent reservation * APTPL pre-registrations that need to be enabled for this dynamic @@ -522,7 +521,7 @@ int core_tpg_register( return PTR_ERR(se_tpg->tpg_virt_lun0); ret = core_tpg_add_lun(se_tpg, se_tpg->tpg_virt_lun0, - TRANSPORT_LUNFLAGS_READ_ONLY, g_lun0_dev); + true, g_lun0_dev); if (ret < 0) { kfree(se_tpg->tpg_virt_lun0); return ret; @@ -616,7 +615,7 @@ struct se_lun *core_tpg_alloc_lun( int core_tpg_add_lun( struct se_portal_group *tpg, struct se_lun *lun, - u32 lun_access, + bool lun_access_ro, struct se_device *dev) { int ret; @@ -644,9 +643,9 @@ int core_tpg_add_lun( spin_unlock(&dev->se_port_lock); if (dev->dev_flags & DF_READ_ONLY) - lun->lun_access = TRANSPORT_LUNFLAGS_READ_ONLY; + lun->lun_access_ro = true; else - lun->lun_access = lun_access; + lun->lun_access_ro = lun_access_ro; if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) hlist_add_head_rcu(&lun->link, &tpg->tpg_lun_hlist); mutex_unlock(&tpg->tpg_lun_mutex); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 43d8b42c0..ab2bf1297 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -281,6 +281,17 @@ struct se_session *transport_init_session_tags(unsigned int tag_num, struct se_session *se_sess; int rc; + if (tag_num != 0 && !tag_size) { + pr_err("init_session_tags called with percpu-ida tag_num:" + " %u, but zero tag_size\n", tag_num); + return ERR_PTR(-EINVAL); + } + if (!tag_num && tag_size) { + pr_err("init_session_tags called with percpu-ida tag_size:" + " %u, but zero tag_num\n", tag_size); + return ERR_PTR(-EINVAL); + } + se_sess = transport_init_session(sup_prot_ops); if (IS_ERR(se_sess)) return se_sess; @@ -374,6 +385,51 @@ void transport_register_session( } EXPORT_SYMBOL(transport_register_session); +struct se_session * +target_alloc_session(struct se_portal_group *tpg, + unsigned int tag_num, unsigned int tag_size, + enum target_prot_op prot_op, + const char *initiatorname, void *private, + int (*callback)(struct se_portal_group *, + struct se_session *, void *)) +{ + struct se_session *sess; + + /* + * If the fabric driver is using percpu-ida based pre allocation + * of I/O descriptor tags, go ahead and perform that setup now.. + */ + if (tag_num != 0) + sess = transport_init_session_tags(tag_num, tag_size, prot_op); + else + sess = transport_init_session(prot_op); + + if (IS_ERR(sess)) + return sess; + + sess->se_node_acl = core_tpg_check_initiator_node_acl(tpg, + (unsigned char *)initiatorname); + if (!sess->se_node_acl) { + transport_free_session(sess); + return ERR_PTR(-EACCES); + } + /* + * Go ahead and perform any remaining fabric setup that is + * required before transport_register_session(). + */ + if (callback != NULL) { + int rc = callback(tpg, sess, private); + if (rc) { + transport_free_session(sess); + return ERR_PTR(rc); + } + } + + transport_register_session(tpg, sess->se_node_acl, sess, private); + return sess; +} +EXPORT_SYMBOL(target_alloc_session); + static void target_release_session(struct kref *kref) { struct se_session *se_sess = container_of(kref, @@ -1941,6 +1997,9 @@ static void transport_complete_qf(struct se_cmd *cmd) switch (cmd->data_direction) { case DMA_FROM_DEVICE: + if (cmd->scsi_status) + goto queue_status; + trace_target_cmd_complete(cmd); ret = cmd->se_tfo->queue_data_in(cmd); break; @@ -1951,6 +2010,7 @@ static void transport_complete_qf(struct se_cmd *cmd) } /* Fall through for DMA_TO_DEVICE */ case DMA_NONE: +queue_status: trace_target_cmd_complete(cmd); ret = cmd->se_tfo->queue_status(cmd); break; @@ -2072,6 +2132,9 @@ static void target_complete_ok_work(struct work_struct *work) queue_rsp: switch (cmd->data_direction) { case DMA_FROM_DEVICE: + if (cmd->scsi_status) + goto queue_status; + atomic_long_add(cmd->data_length, &cmd->se_lun->lun_stats.tx_data_octets); /* @@ -2111,6 +2174,7 @@ queue_rsp: } /* Fall through for DMA_TO_DEVICE */ case DMA_NONE: +queue_status: trace_target_cmd_complete(cmd); ret = cmd->se_tfo->queue_status(cmd); if (ret == -EAGAIN || ret == -ENOMEM) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 94f5154ac..62bf4fe57 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -26,6 +26,7 @@ #include <linux/vmalloc.h> #include <linux/uio_driver.h> #include <linux/stringify.h> +#include <linux/bitops.h> #include <net/genetlink.h> #include <scsi/scsi_common.h> #include <scsi/scsi_proto.h> @@ -63,8 +64,11 @@ #define TCMU_TIME_OUT (30 * MSEC_PER_SEC) +#define DATA_BLOCK_BITS 256 +#define DATA_BLOCK_SIZE 4096 + #define CMDR_SIZE (16 * 4096) -#define DATA_SIZE (257 * 4096) +#define DATA_SIZE (DATA_BLOCK_BITS * DATA_BLOCK_SIZE) #define TCMU_RING_SIZE (CMDR_SIZE + DATA_SIZE) @@ -93,12 +97,11 @@ struct tcmu_dev { u32 cmdr_size; u32 cmdr_last_cleaned; /* Offset of data ring from start of mb */ + /* Must add data_off and mb_addr to get the address */ size_t data_off; size_t data_size; - /* Ring head + tail values. */ - /* Must add data_off and mb_addr to get the address */ - size_t data_head; - size_t data_tail; + + DECLARE_BITMAP(data_bitmap, DATA_BLOCK_BITS); wait_queue_head_t wait_cmdr; /* TODO should this be a mutex? */ @@ -122,9 +125,9 @@ struct tcmu_cmd { uint16_t cmd_id; - /* Can't use se_cmd->data_length when cleaning up expired cmds, because if + /* Can't use se_cmd when cleaning up expired cmds, because if cmd has been completed then accessing se_cmd is off limits */ - size_t data_length; + DECLARE_BITMAP(data_bitmap, DATA_BLOCK_BITS); unsigned long deadline; @@ -168,13 +171,6 @@ static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd) tcmu_cmd->se_cmd = se_cmd; tcmu_cmd->tcmu_dev = udev; - tcmu_cmd->data_length = se_cmd->data_length; - - if (se_cmd->se_cmd_flags & SCF_BIDI) { - BUG_ON(!(se_cmd->t_bidi_data_sg && se_cmd->t_bidi_data_nents)); - tcmu_cmd->data_length += se_cmd->t_bidi_data_sg->length; - } - tcmu_cmd->deadline = jiffies + msecs_to_jiffies(TCMU_TIME_OUT); idr_preload(GFP_KERNEL); @@ -231,105 +227,126 @@ static inline size_t head_to_end(size_t head, size_t size) return size - head; } +static inline void new_iov(struct iovec **iov, int *iov_cnt, + struct tcmu_dev *udev) +{ + struct iovec *iovec; + + if (*iov_cnt != 0) + (*iov)++; + (*iov_cnt)++; + + iovec = *iov; + memset(iovec, 0, sizeof(struct iovec)); +} + #define UPDATE_HEAD(head, used, size) smp_store_release(&head, ((head % size) + used) % size) +/* offset is relative to mb_addr */ +static inline size_t get_block_offset(struct tcmu_dev *dev, + int block, int remaining) +{ + return dev->data_off + block * DATA_BLOCK_SIZE + + DATA_BLOCK_SIZE - remaining; +} + +static inline size_t iov_tail(struct tcmu_dev *udev, struct iovec *iov) +{ + return (size_t)iov->iov_base + iov->iov_len; +} + static void alloc_and_scatter_data_area(struct tcmu_dev *udev, struct scatterlist *data_sg, unsigned int data_nents, struct iovec **iov, int *iov_cnt, bool copy_data) { - int i; + int i, block; + int block_remaining = 0; void *from, *to; - size_t copy_bytes; + size_t copy_bytes, to_offset; struct scatterlist *sg; for_each_sg(data_sg, sg, data_nents, i) { - copy_bytes = min_t(size_t, sg->length, - head_to_end(udev->data_head, udev->data_size)); + int sg_remaining = sg->length; from = kmap_atomic(sg_page(sg)) + sg->offset; - to = (void *) udev->mb_addr + udev->data_off + udev->data_head; - - if (copy_data) { - memcpy(to, from, copy_bytes); - tcmu_flush_dcache_range(to, copy_bytes); - } - - /* Even iov_base is relative to mb_addr */ - (*iov)->iov_len = copy_bytes; - (*iov)->iov_base = (void __user *) udev->data_off + - udev->data_head; - (*iov_cnt)++; - (*iov)++; - - UPDATE_HEAD(udev->data_head, copy_bytes, udev->data_size); - - /* Uh oh, we wrapped the buffer. Must split sg across 2 iovs. */ - if (sg->length != copy_bytes) { - void *from_skip = from + copy_bytes; - - copy_bytes = sg->length - copy_bytes; - - (*iov)->iov_len = copy_bytes; - (*iov)->iov_base = (void __user *) udev->data_off + - udev->data_head; - + while (sg_remaining > 0) { + if (block_remaining == 0) { + block = find_first_zero_bit(udev->data_bitmap, + DATA_BLOCK_BITS); + block_remaining = DATA_BLOCK_SIZE; + set_bit(block, udev->data_bitmap); + } + copy_bytes = min_t(size_t, sg_remaining, + block_remaining); + to_offset = get_block_offset(udev, block, + block_remaining); + to = (void *)udev->mb_addr + to_offset; + if (*iov_cnt != 0 && + to_offset == iov_tail(udev, *iov)) { + (*iov)->iov_len += copy_bytes; + } else { + new_iov(iov, iov_cnt, udev); + (*iov)->iov_base = (void __user *) to_offset; + (*iov)->iov_len = copy_bytes; + } if (copy_data) { - to = (void *) udev->mb_addr + - udev->data_off + udev->data_head; - memcpy(to, from_skip, copy_bytes); + memcpy(to, from + sg->length - sg_remaining, + copy_bytes); tcmu_flush_dcache_range(to, copy_bytes); } - - (*iov_cnt)++; - (*iov)++; - - UPDATE_HEAD(udev->data_head, - copy_bytes, udev->data_size); + sg_remaining -= copy_bytes; + block_remaining -= copy_bytes; } - kunmap_atomic(from - sg->offset); } } -static void gather_and_free_data_area(struct tcmu_dev *udev, - struct scatterlist *data_sg, unsigned int data_nents) +static void free_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd) { - int i; + bitmap_xor(udev->data_bitmap, udev->data_bitmap, cmd->data_bitmap, + DATA_BLOCK_BITS); +} + +static void gather_data_area(struct tcmu_dev *udev, unsigned long *cmd_bitmap, + struct scatterlist *data_sg, unsigned int data_nents) +{ + int i, block; + int block_remaining = 0; void *from, *to; - size_t copy_bytes; + size_t copy_bytes, from_offset; struct scatterlist *sg; - /* It'd be easier to look at entry's iovec again, but UAM */ for_each_sg(data_sg, sg, data_nents, i) { - copy_bytes = min_t(size_t, sg->length, - head_to_end(udev->data_tail, udev->data_size)); - + int sg_remaining = sg->length; to = kmap_atomic(sg_page(sg)) + sg->offset; - WARN_ON(sg->length + sg->offset > PAGE_SIZE); - from = (void *) udev->mb_addr + - udev->data_off + udev->data_tail; - tcmu_flush_dcache_range(from, copy_bytes); - memcpy(to, from, copy_bytes); - - UPDATE_HEAD(udev->data_tail, copy_bytes, udev->data_size); - - /* Uh oh, wrapped the data buffer for this sg's data */ - if (sg->length != copy_bytes) { - void *to_skip = to + copy_bytes; - - from = (void *) udev->mb_addr + - udev->data_off + udev->data_tail; - WARN_ON(udev->data_tail); - copy_bytes = sg->length - copy_bytes; + while (sg_remaining > 0) { + if (block_remaining == 0) { + block = find_first_bit(cmd_bitmap, + DATA_BLOCK_BITS); + block_remaining = DATA_BLOCK_SIZE; + clear_bit(block, cmd_bitmap); + } + copy_bytes = min_t(size_t, sg_remaining, + block_remaining); + from_offset = get_block_offset(udev, block, + block_remaining); + from = (void *) udev->mb_addr + from_offset; tcmu_flush_dcache_range(from, copy_bytes); - memcpy(to_skip, from, copy_bytes); + memcpy(to + sg->length - sg_remaining, from, + copy_bytes); - UPDATE_HEAD(udev->data_tail, - copy_bytes, udev->data_size); + sg_remaining -= copy_bytes; + block_remaining -= copy_bytes; } kunmap_atomic(to - sg->offset); } } +static inline size_t spc_bitmap_free(unsigned long *bitmap) +{ + return DATA_BLOCK_SIZE * (DATA_BLOCK_BITS - + bitmap_weight(bitmap, DATA_BLOCK_BITS)); +} + /* * We can't queue a command until we have space available on the cmd ring *and* * space available on the data ring. @@ -339,9 +356,8 @@ static void gather_and_free_data_area(struct tcmu_dev *udev, static bool is_ring_space_avail(struct tcmu_dev *udev, size_t cmd_size, size_t data_needed) { struct tcmu_mailbox *mb = udev->mb_addr; - size_t space; + size_t space, cmd_needed; u32 cmd_head; - size_t cmd_needed; tcmu_flush_dcache_range(mb, sizeof(*mb)); @@ -363,10 +379,10 @@ static bool is_ring_space_avail(struct tcmu_dev *udev, size_t cmd_size, size_t d return false; } - space = spc_free(udev->data_head, udev->data_tail, udev->data_size); + space = spc_bitmap_free(udev->data_bitmap); if (space < data_needed) { - pr_debug("no data space: %zu %zu %zu\n", udev->data_head, - udev->data_tail, udev->data_size); + pr_debug("no data space: only %zu available, but ask for %zu\n", + space, data_needed); return false; } @@ -385,6 +401,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) uint32_t cmd_head; uint64_t cdb_off; bool copy_to_data_area; + size_t data_length; + DECLARE_BITMAP(old_bitmap, DATA_BLOCK_BITS); if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags)) return -EINVAL; @@ -393,12 +411,12 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) * Must be a certain minimum size for response sense info, but * also may be larger if the iov array is large. * - * iovs = sgl_nents+1, for end-of-ring case, plus another 1 - * b/c size == offsetof one-past-element. + * We prepare way too many iovs for potential uses here, because it's + * expensive to tell how many regions are freed in the bitmap */ base_command_size = max(offsetof(struct tcmu_cmd_entry, - req.iov[se_cmd->t_bidi_data_nents + - se_cmd->t_data_nents + 2]), + req.iov[se_cmd->t_bidi_data_nents + + se_cmd->t_data_nents]), sizeof(struct tcmu_cmd_entry)); command_size = base_command_size + round_up(scsi_command_size(se_cmd->t_task_cdb), TCMU_OP_ALIGN_SIZE); @@ -409,13 +427,18 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) mb = udev->mb_addr; cmd_head = mb->cmd_head % udev->cmdr_size; /* UAM */ + data_length = se_cmd->data_length; + if (se_cmd->se_cmd_flags & SCF_BIDI) { + BUG_ON(!(se_cmd->t_bidi_data_sg && se_cmd->t_bidi_data_nents)); + data_length += se_cmd->t_bidi_data_sg->length; + } if ((command_size > (udev->cmdr_size / 2)) - || tcmu_cmd->data_length > (udev->data_size - 1)) + || data_length > udev->data_size) pr_warn("TCMU: Request of size %zu/%zu may be too big for %u/%zu " - "cmd/data ring buffers\n", command_size, tcmu_cmd->data_length, + "cmd/data ring buffers\n", command_size, data_length, udev->cmdr_size, udev->data_size); - while (!is_ring_space_avail(udev, command_size, tcmu_cmd->data_length)) { + while (!is_ring_space_avail(udev, command_size, data_length)) { int ret; DEFINE_WAIT(__wait); @@ -462,6 +485,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) entry->hdr.kflags = 0; entry->hdr.uflags = 0; + bitmap_copy(old_bitmap, udev->data_bitmap, DATA_BLOCK_BITS); + /* * Fix up iovecs, and handle if allocation in data ring wrapped. */ @@ -480,6 +505,10 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) se_cmd->t_bidi_data_nents, &iov, &iov_cnt, false); entry->req.iov_bidi_cnt = iov_cnt; + /* cmd's data_bitmap is what changed in process */ + bitmap_xor(tcmu_cmd->data_bitmap, old_bitmap, udev->data_bitmap, + DATA_BLOCK_BITS); + /* All offsets relative to mb_addr, not start of entry! */ cdb_off = CMDR_OFF + cmd_head + base_command_size; memcpy((void *) mb + cdb_off, se_cmd->t_task_cdb, scsi_command_size(se_cmd->t_task_cdb)); @@ -530,35 +559,42 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * struct tcmu_dev *udev = cmd->tcmu_dev; if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) { - /* cmd has been completed already from timeout, just reclaim data - ring space */ - UPDATE_HEAD(udev->data_tail, cmd->data_length, udev->data_size); + /* + * cmd has been completed already from timeout, just reclaim + * data ring space and free cmd + */ + free_data_area(udev, cmd); + + kmem_cache_free(tcmu_cmd_cache, cmd); return; } if (entry->hdr.uflags & TCMU_UFLAG_UNKNOWN_OP) { - UPDATE_HEAD(udev->data_tail, cmd->data_length, udev->data_size); + free_data_area(udev, cmd); pr_warn("TCMU: Userspace set UNKNOWN_OP flag on se_cmd %p\n", cmd->se_cmd); entry->rsp.scsi_status = SAM_STAT_CHECK_CONDITION; } else if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) { memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer, se_cmd->scsi_sense_length); - - UPDATE_HEAD(udev->data_tail, cmd->data_length, udev->data_size); + free_data_area(udev, cmd); } else if (se_cmd->se_cmd_flags & SCF_BIDI) { - /* Discard data_out buffer */ - UPDATE_HEAD(udev->data_tail, - (size_t)se_cmd->t_data_sg->length, udev->data_size); + DECLARE_BITMAP(bitmap, DATA_BLOCK_BITS); - /* Get Data-In buffer */ - gather_and_free_data_area(udev, + /* Get Data-In buffer before clean up */ + bitmap_copy(bitmap, cmd->data_bitmap, DATA_BLOCK_BITS); + gather_data_area(udev, bitmap, se_cmd->t_bidi_data_sg, se_cmd->t_bidi_data_nents); + free_data_area(udev, cmd); } else if (se_cmd->data_direction == DMA_FROM_DEVICE) { - gather_and_free_data_area(udev, + DECLARE_BITMAP(bitmap, DATA_BLOCK_BITS); + + bitmap_copy(bitmap, cmd->data_bitmap, DATA_BLOCK_BITS); + gather_data_area(udev, bitmap, se_cmd->t_data_sg, se_cmd->t_data_nents); + free_data_area(udev, cmd); } else if (se_cmd->data_direction == DMA_TO_DEVICE) { - UPDATE_HEAD(udev->data_tail, cmd->data_length, udev->data_size); + free_data_area(udev, cmd); } else if (se_cmd->data_direction != DMA_NONE) { pr_warn("TCMU: data direction was %d!\n", se_cmd->data_direction); @@ -894,11 +930,13 @@ static int tcmu_configure_device(struct se_device *dev) mb = udev->mb_addr; mb->version = TCMU_MAILBOX_VERSION; + mb->flags = TCMU_MAILBOX_FLAG_CAP_OOOC; mb->cmdr_off = CMDR_OFF; mb->cmdr_size = udev->cmdr_size; WARN_ON(!PAGE_ALIGNED(udev->data_off)); WARN_ON(udev->data_size % PAGE_SIZE); + WARN_ON(udev->data_size % DATA_BLOCK_SIZE); info->version = __stringify(TCMU_MAILBOX_VERSION); @@ -942,12 +980,12 @@ err_vzalloc: return ret; } -static int tcmu_check_pending_cmd(int id, void *p, void *data) +static int tcmu_check_and_free_pending_cmd(struct tcmu_cmd *cmd) { - struct tcmu_cmd *cmd = p; - - if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) + if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) { + kmem_cache_free(tcmu_cmd_cache, cmd); return 0; + } return -EINVAL; } @@ -962,6 +1000,8 @@ static void tcmu_dev_call_rcu(struct rcu_head *p) static void tcmu_free_device(struct se_device *dev) { struct tcmu_dev *udev = TCMU_DEV(dev); + struct tcmu_cmd *cmd; + bool all_expired = true; int i; del_timer_sync(&udev->timeout); @@ -970,10 +1010,13 @@ static void tcmu_free_device(struct se_device *dev) /* Upper layer should drain all requests before calling this */ spin_lock_irq(&udev->commands_lock); - i = idr_for_each(&udev->commands, tcmu_check_pending_cmd, NULL); + idr_for_each_entry(&udev->commands, cmd, i) { + if (tcmu_check_and_free_pending_cmd(cmd) != 0) + all_expired = false; + } idr_destroy(&udev->commands); spin_unlock_irq(&udev->commands_lock); - WARN_ON(i); + WARN_ON(!all_expired); /* Device was configured */ if (udev->uio_info.uio_dev) { diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 064d6dfb5..216e18cc9 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -107,8 +107,7 @@ void ft_release_cmd(struct se_cmd *se_cmd) int ft_check_stop_free(struct se_cmd *se_cmd) { - transport_generic_free_cmd(se_cmd, 0); - return 1; + return transport_generic_free_cmd(se_cmd, 0); } /* @@ -179,6 +178,12 @@ int ft_queue_status(struct se_cmd *se_cmd) return -ENOMEM; } lport->tt.exch_done(cmd->seq); + /* + * Drop the extra ACK_KREF reference taken by target_submit_cmd() + * ahead of ft_check_stop_free() -> transport_generic_free_cmd() + * final se_cmd->cmd_kref put. + */ + target_put_sess_cmd(&cmd->se_cmd); return 0; } @@ -387,7 +392,7 @@ static void ft_send_tm(struct ft_cmd *cmd) /* FIXME: Add referenced task tag for ABORT_TASK */ rc = target_submit_tmr(&cmd->se_cmd, cmd->sess->se_sess, &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), - cmd, tm_func, GFP_KERNEL, 0, 0); + cmd, tm_func, GFP_KERNEL, 0, TARGET_SCF_ACK_KREF); if (rc < 0) ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED); } @@ -422,6 +427,12 @@ void ft_queue_tm_resp(struct se_cmd *se_cmd) pr_debug("tmr fn %d resp %d fcp code %d\n", tmr->function, tmr->response, code); ft_send_resp_code(cmd, code); + /* + * Drop the extra ACK_KREF reference taken by target_submit_tmr() + * ahead of ft_check_stop_free() -> transport_generic_free_cmd() + * final se_cmd->cmd_kref put. + */ + target_put_sess_cmd(&cmd->se_cmd); } void ft_aborted_task(struct se_cmd *se_cmd) @@ -560,7 +571,8 @@ static void ft_send_work(struct work_struct *work) */ if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb, &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun), - ntohl(fcp->fc_dl), task_attr, data_dir, 0)) + ntohl(fcp->fc_dl), task_attr, data_dir, + TARGET_SCF_ACK_KREF)) goto err; pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl); diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index e19f4c58c..d0c3e1894 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -186,6 +186,20 @@ out: return NULL; } +static int ft_sess_alloc_cb(struct se_portal_group *se_tpg, + struct se_session *se_sess, void *p) +{ + struct ft_sess *sess = p; + struct ft_tport *tport = sess->tport; + struct hlist_head *head = &tport->hash[ft_sess_hash(sess->port_id)]; + + pr_debug("port_id %x sess %p\n", sess->port_id, sess); + hlist_add_head_rcu(&sess->hash, head); + tport->sess_count++; + + return 0; +} + /* * Allocate session and enter it in the hash for the local port. * Caller holds ft_lport_lock. @@ -194,7 +208,6 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id, struct fc_rport_priv *rdata) { struct se_portal_group *se_tpg = &tport->tpg->se_tpg; - struct se_node_acl *se_acl; struct ft_sess *sess; struct hlist_head *head; unsigned char initiatorname[TRANSPORT_IQN_LEN]; @@ -210,31 +223,18 @@ static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id, if (!sess) return NULL; - sess->se_sess = transport_init_session_tags(TCM_FC_DEFAULT_TAGS, - sizeof(struct ft_cmd), - TARGET_PROT_NORMAL); - if (IS_ERR(sess->se_sess)) { - kfree(sess); - return NULL; - } + kref_init(&sess->kref); /* ref for table entry */ + sess->tport = tport; + sess->port_id = port_id; - se_acl = core_tpg_get_initiator_node_acl(se_tpg, &initiatorname[0]); - if (!se_acl) { - transport_free_session(sess->se_sess); + sess->se_sess = target_alloc_session(se_tpg, TCM_FC_DEFAULT_TAGS, + sizeof(struct ft_cmd), + TARGET_PROT_NORMAL, &initiatorname[0], + sess, ft_sess_alloc_cb); + if (IS_ERR(sess->se_sess)) { kfree(sess); return NULL; } - sess->se_sess->se_node_acl = se_acl; - sess->tport = tport; - sess->port_id = port_id; - kref_init(&sess->kref); /* ref for table entry */ - hlist_add_head_rcu(&sess->hash, head); - tport->sess_count++; - - pr_debug("port_id %x sess %p\n", port_id, sess); - - transport_register_session(&tport->tpg->se_tpg, se_acl, - sess->se_sess, sess); return sess; } |