From 6bb826121be244a5a3c8bd8b7d45c47df18810b7 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 10 May 2015 19:31:10 -0700 Subject: [PATCH 10/12] target: Convert se_portal_group->tpg_lun_list[] to RCU hlist This patch converts the fixed size se_portal_group->tpg_lun_list[] to use modern RCU with hlist_head in order to support an arbitary number of se_lun ports per target endpoint. It includes dropping core_tpg_alloc_lun() from core_dev_add_lun(), and calling it directly from target_fabric_make_lun() to allocate a new se_lun. And add a new target_fabric_port_release() configfs item callback to invoke kfree_rcu() to release memory during se_lun->lun_group shutdown. Also now that se_node_acl->lun_entry_hlist is using RCU, convert existing tpg_lun_lock to struct mutex so core_tpg_add_node_to_devs() can perform RCU updater logic without releasing ->tpg_lun_mutex. Also, drop core_tpg_clear_object_luns() and it's single consumer in iscsi-target, which is duplicating TPG LUN shutdown logic and is current code results in a NOP. Finally, sbp-target and xen-scsiback fabric driver conversions are included, which are required due to the non-standard way they use ->tpg_lun_hlist. Reviewed-by: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Cc: Paul E. McKenney Cc: Chris Boot Signed-off-by: Nicholas Bellinger [[ stefanr: only sbp part included here ]] --- drivers/target/sbp/sbp_target.c | 97 ++++++++++++++++++----------------------- drivers/target/sbp/sbp_target.h | 2 +- 2 files changed, 43 insertions(+), 56 deletions(-) diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 5d7755edc668..47fb12fbaf47 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -108,13 +108,13 @@ static struct sbp_session *sbp_session_find_by_guid( } static struct sbp_login_descriptor *sbp_login_find_by_lun( - struct sbp_session *session, struct se_lun *lun) + struct sbp_session *session, u32 unpacked_lun) { struct sbp_login_descriptor *login, *found = NULL; spin_lock_bh(&session->lock); list_for_each_entry(login, &session->login_list, link) { - if (login->lun == lun) + if (login->login_lun == unpacked_lun) found = login; } spin_unlock_bh(&session->lock); @@ -124,7 +124,7 @@ static struct sbp_login_descriptor *sbp_login_find_by_lun( static int sbp_login_count_all_by_lun( struct sbp_tpg *tpg, - struct se_lun *lun, + u32 unpacked_lun, int exclusive) { struct se_session *se_sess; @@ -138,7 +138,7 @@ static int sbp_login_count_all_by_lun( spin_lock_bh(&sess->lock); list_for_each_entry(login, &sess->login_list, link) { - if (login->lun != lun) + if (login->login_lun != unpacked_lun) continue; if (!exclusive || login->exclusive) @@ -174,23 +174,23 @@ static struct sbp_login_descriptor *sbp_login_find_by_id( return found; } -static struct se_lun *sbp_get_lun_from_tpg(struct sbp_tpg *tpg, int lun) +static u32 sbp_get_lun_from_tpg(struct sbp_tpg *tpg, u32 login_lun, int *err) { struct se_portal_group *se_tpg = &tpg->se_tpg; struct se_lun *se_lun; - if (lun >= TRANSPORT_MAX_LUNS_PER_TPG) - return ERR_PTR(-EINVAL); - - spin_lock(&se_tpg->tpg_lun_lock); - se_lun = se_tpg->tpg_lun_list[lun]; - - if (se_lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) - se_lun = ERR_PTR(-ENODEV); - - spin_unlock(&se_tpg->tpg_lun_lock); + rcu_read_lock(); + hlist_for_each_entry_rcu(se_lun, &se_tpg->tpg_lun_hlist, link) { + if (se_lun->unpacked_lun == login_lun) { + rcu_read_unlock(); + *err = 0; + return login_lun; + } + } + rcu_read_unlock(); - return se_lun; + *err = -ENODEV; + return login_lun; } static struct sbp_session *sbp_session_create( @@ -294,17 +294,16 @@ static void sbp_management_request_login( { struct sbp_tport *tport = agent->tport; struct sbp_tpg *tpg = tport->tpg; - struct se_lun *se_lun; - int ret; - u64 guid; struct sbp_session *sess; struct sbp_login_descriptor *login; struct sbp_login_response_block *response; - int login_response_len; + u64 guid; + u32 unpacked_lun; + int login_response_len, ret; - se_lun = sbp_get_lun_from_tpg(tpg, - LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc))); - if (IS_ERR(se_lun)) { + unpacked_lun = sbp_get_lun_from_tpg(tpg, + LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc)), &ret); + if (ret) { pr_notice("login to unknown LUN: %d\n", LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc))); @@ -325,11 +324,11 @@ static void sbp_management_request_login( } pr_notice("mgt_agent LOGIN to LUN %d from %016llx\n", - se_lun->unpacked_lun, guid); + unpacked_lun, guid); sess = sbp_session_find_by_guid(tpg, guid); if (sess) { - login = sbp_login_find_by_lun(sess, se_lun); + login = sbp_login_find_by_lun(sess, unpacked_lun); if (login) { pr_notice("initiator already logged-in\n"); @@ -357,7 +356,7 @@ static void sbp_management_request_login( * reject with access_denied if any logins present */ if (LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)) && - sbp_login_count_all_by_lun(tpg, se_lun, 0)) { + sbp_login_count_all_by_lun(tpg, unpacked_lun, 0)) { pr_warn("refusing exclusive login with other active logins\n"); req->status.status = cpu_to_be32( @@ -370,7 +369,7 @@ static void sbp_management_request_login( * check exclusive bit in any existing login descriptor * reject with access_denied if any exclusive logins present */ - if (sbp_login_count_all_by_lun(tpg, se_lun, 1)) { + if (sbp_login_count_all_by_lun(tpg, unpacked_lun, 1)) { pr_warn("refusing login while another exclusive login present\n"); req->status.status = cpu_to_be32( @@ -383,7 +382,7 @@ static void sbp_management_request_login( * check we haven't exceeded the number of allowed logins * reject with resources_unavailable if we have */ - if (sbp_login_count_all_by_lun(tpg, se_lun, 0) >= + if (sbp_login_count_all_by_lun(tpg, unpacked_lun, 0) >= tport->max_logins_per_lun) { pr_warn("max number of logins reached\n"); @@ -439,7 +438,7 @@ static void sbp_management_request_login( } login->sess = sess; - login->lun = se_lun; + login->login_lun = unpacked_lun; login->status_fifo_addr = sbp2_pointer_to_addr(&req->orb.status_fifo); login->exclusive = LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)); login->login_id = atomic_inc_return(&login_id); @@ -601,7 +600,7 @@ static void sbp_management_request_logout( } pr_info("mgt_agent LOGOUT from LUN %d session %d\n", - login->lun->unpacked_lun, login->login_id); + login->login_lun, login->login_id); if (req->node_addr != login->sess->node_id) { pr_warn("logout from different node ID\n"); @@ -1227,7 +1226,7 @@ static void sbp_handle_command(struct sbp_target_request *req) goto err; } - unpacked_lun = req->login->lun->unpacked_lun; + unpacked_lun = req->login->login_lun; sbp_calc_data_length_direction(req, &data_length, &data_dir); pr_debug("sbp_handle_command ORB:0x%llx unpacked_lun:%d data_len:%d data_dir:%d\n", @@ -1826,25 +1825,21 @@ static int sbp_check_stop_free(struct se_cmd *se_cmd) static int sbp_count_se_tpg_luns(struct se_portal_group *tpg) { - int i, count = 0; - - spin_lock(&tpg->tpg_lun_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - struct se_lun *se_lun = tpg->tpg_lun_list[i]; - - if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE) - continue; + struct se_lun *lun; + int count = 0; + rcu_read_lock(); + hlist_for_each_entry_rcu(lun, &tpg->tpg_lun_hlist, link) count++; - } - spin_unlock(&tpg->tpg_lun_lock); + rcu_read_unlock(); return count; } static int sbp_update_unit_directory(struct sbp_tport *tport) { - int num_luns, num_entries, idx = 0, mgt_agt_addr, ret, i; + struct se_lun *lun; + int num_luns, num_entries, idx = 0, mgt_agt_addr, ret; u32 *data; if (tport->unit_directory.data) { @@ -1906,28 +1901,20 @@ static int sbp_update_unit_directory(struct sbp_tport *tport) /* unit unique ID (leaf is just after LUNs) */ data[idx++] = 0x8d000000 | (num_luns + 1); - spin_lock(&tport->tpg->se_tpg.tpg_lun_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - struct se_lun *se_lun = tport->tpg->se_tpg.tpg_lun_list[i]; + rcu_read_lock(); + hlist_for_each_entry_rcu(lun, &tport->tpg->se_tpg.tpg_lun_hlist, link) { struct se_device *dev; int type; - if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE) - continue; - - spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock); - - dev = se_lun->lun_se_dev; + dev = lun->lun_se_dev; type = dev->transport->get_device_type(dev); /* logical_unit_number */ data[idx++] = 0x14000000 | ((type << 16) & 0x1f0000) | - (se_lun->unpacked_lun & 0xffff); - - spin_lock(&tport->tpg->se_tpg.tpg_lun_lock); + (lun->unpacked_lun & 0xffff); } - spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock); + rcu_read_unlock(); /* unit unique ID leaf */ data[idx++] = 2 << 16; diff --git a/drivers/target/sbp/sbp_target.h b/drivers/target/sbp/sbp_target.h index e1b0b84f7379..73bcb1208832 100644 --- a/drivers/target/sbp/sbp_target.h +++ b/drivers/target/sbp/sbp_target.h @@ -125,7 +125,7 @@ struct sbp_login_descriptor { struct sbp_session *sess; struct list_head link; - struct se_lun *lun; + u32 login_lun; u64 status_fifo_addr; int exclusive; -- 2.3.6