diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2015-05-10 22:31:10 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2015-06-01 03:24:33 -0400 |
commit | 6bb826121be244a5a3c8bd8b7d45c47df18810b7 (patch) | |
tree | 7a75624e4801567a4133bc5b373ed67dd1db1cbb /drivers/target/sbp | |
parent | 9fcb57f39c0cde70bcccdc1d998d3060297e911c (diff) |
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 <hare@suse.de>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Sagi Grimberg <sagig@mellanox.com>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Chris Boot <bootc@bootc.net>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/sbp')
-rw-r--r-- | drivers/target/sbp/sbp_target.c | 97 | ||||
-rw-r--r-- | 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( | |||
108 | } | 108 | } |
109 | 109 | ||
110 | static struct sbp_login_descriptor *sbp_login_find_by_lun( | 110 | static struct sbp_login_descriptor *sbp_login_find_by_lun( |
111 | struct sbp_session *session, struct se_lun *lun) | 111 | struct sbp_session *session, u32 unpacked_lun) |
112 | { | 112 | { |
113 | struct sbp_login_descriptor *login, *found = NULL; | 113 | struct sbp_login_descriptor *login, *found = NULL; |
114 | 114 | ||
115 | spin_lock_bh(&session->lock); | 115 | spin_lock_bh(&session->lock); |
116 | list_for_each_entry(login, &session->login_list, link) { | 116 | list_for_each_entry(login, &session->login_list, link) { |
117 | if (login->lun == lun) | 117 | if (login->login_lun == unpacked_lun) |
118 | found = login; | 118 | found = login; |
119 | } | 119 | } |
120 | spin_unlock_bh(&session->lock); | 120 | spin_unlock_bh(&session->lock); |
@@ -124,7 +124,7 @@ static struct sbp_login_descriptor *sbp_login_find_by_lun( | |||
124 | 124 | ||
125 | static int sbp_login_count_all_by_lun( | 125 | static int sbp_login_count_all_by_lun( |
126 | struct sbp_tpg *tpg, | 126 | struct sbp_tpg *tpg, |
127 | struct se_lun *lun, | 127 | u32 unpacked_lun, |
128 | int exclusive) | 128 | int exclusive) |
129 | { | 129 | { |
130 | struct se_session *se_sess; | 130 | struct se_session *se_sess; |
@@ -138,7 +138,7 @@ static int sbp_login_count_all_by_lun( | |||
138 | 138 | ||
139 | spin_lock_bh(&sess->lock); | 139 | spin_lock_bh(&sess->lock); |
140 | list_for_each_entry(login, &sess->login_list, link) { | 140 | list_for_each_entry(login, &sess->login_list, link) { |
141 | if (login->lun != lun) | 141 | if (login->login_lun != unpacked_lun) |
142 | continue; | 142 | continue; |
143 | 143 | ||
144 | if (!exclusive || login->exclusive) | 144 | if (!exclusive || login->exclusive) |
@@ -174,23 +174,23 @@ static struct sbp_login_descriptor *sbp_login_find_by_id( | |||
174 | return found; | 174 | return found; |
175 | } | 175 | } |
176 | 176 | ||
177 | static struct se_lun *sbp_get_lun_from_tpg(struct sbp_tpg *tpg, int lun) | 177 | static u32 sbp_get_lun_from_tpg(struct sbp_tpg *tpg, u32 login_lun, int *err) |
178 | { | 178 | { |
179 | struct se_portal_group *se_tpg = &tpg->se_tpg; | 179 | struct se_portal_group *se_tpg = &tpg->se_tpg; |
180 | struct se_lun *se_lun; | 180 | struct se_lun *se_lun; |
181 | 181 | ||
182 | if (lun >= TRANSPORT_MAX_LUNS_PER_TPG) | 182 | rcu_read_lock(); |
183 | return ERR_PTR(-EINVAL); | 183 | hlist_for_each_entry_rcu(se_lun, &se_tpg->tpg_lun_hlist, link) { |
184 | 184 | if (se_lun->unpacked_lun == login_lun) { | |
185 | spin_lock(&se_tpg->tpg_lun_lock); | 185 | rcu_read_unlock(); |
186 | se_lun = se_tpg->tpg_lun_list[lun]; | 186 | *err = 0; |
187 | 187 | return login_lun; | |
188 | if (se_lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) | 188 | } |
189 | se_lun = ERR_PTR(-ENODEV); | 189 | } |
190 | 190 | rcu_read_unlock(); | |
191 | spin_unlock(&se_tpg->tpg_lun_lock); | ||
192 | 191 | ||
193 | return se_lun; | 192 | *err = -ENODEV; |
193 | return login_lun; | ||
194 | } | 194 | } |
195 | 195 | ||
196 | static struct sbp_session *sbp_session_create( | 196 | static struct sbp_session *sbp_session_create( |
@@ -294,17 +294,16 @@ static void sbp_management_request_login( | |||
294 | { | 294 | { |
295 | struct sbp_tport *tport = agent->tport; | 295 | struct sbp_tport *tport = agent->tport; |
296 | struct sbp_tpg *tpg = tport->tpg; | 296 | struct sbp_tpg *tpg = tport->tpg; |
297 | struct se_lun *se_lun; | ||
298 | int ret; | ||
299 | u64 guid; | ||
300 | struct sbp_session *sess; | 297 | struct sbp_session *sess; |
301 | struct sbp_login_descriptor *login; | 298 | struct sbp_login_descriptor *login; |
302 | struct sbp_login_response_block *response; | 299 | struct sbp_login_response_block *response; |
303 | int login_response_len; | 300 | u64 guid; |
301 | u32 unpacked_lun; | ||
302 | int login_response_len, ret; | ||
304 | 303 | ||
305 | se_lun = sbp_get_lun_from_tpg(tpg, | 304 | unpacked_lun = sbp_get_lun_from_tpg(tpg, |
306 | LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc))); | 305 | LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc)), &ret); |
307 | if (IS_ERR(se_lun)) { | 306 | if (ret) { |
308 | pr_notice("login to unknown LUN: %d\n", | 307 | pr_notice("login to unknown LUN: %d\n", |
309 | LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc))); | 308 | LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc))); |
310 | 309 | ||
@@ -325,11 +324,11 @@ static void sbp_management_request_login( | |||
325 | } | 324 | } |
326 | 325 | ||
327 | pr_notice("mgt_agent LOGIN to LUN %d from %016llx\n", | 326 | pr_notice("mgt_agent LOGIN to LUN %d from %016llx\n", |
328 | se_lun->unpacked_lun, guid); | 327 | unpacked_lun, guid); |
329 | 328 | ||
330 | sess = sbp_session_find_by_guid(tpg, guid); | 329 | sess = sbp_session_find_by_guid(tpg, guid); |
331 | if (sess) { | 330 | if (sess) { |
332 | login = sbp_login_find_by_lun(sess, se_lun); | 331 | login = sbp_login_find_by_lun(sess, unpacked_lun); |
333 | if (login) { | 332 | if (login) { |
334 | pr_notice("initiator already logged-in\n"); | 333 | pr_notice("initiator already logged-in\n"); |
335 | 334 | ||
@@ -357,7 +356,7 @@ static void sbp_management_request_login( | |||
357 | * reject with access_denied if any logins present | 356 | * reject with access_denied if any logins present |
358 | */ | 357 | */ |
359 | if (LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)) && | 358 | if (LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)) && |
360 | sbp_login_count_all_by_lun(tpg, se_lun, 0)) { | 359 | sbp_login_count_all_by_lun(tpg, unpacked_lun, 0)) { |
361 | pr_warn("refusing exclusive login with other active logins\n"); | 360 | pr_warn("refusing exclusive login with other active logins\n"); |
362 | 361 | ||
363 | req->status.status = cpu_to_be32( | 362 | req->status.status = cpu_to_be32( |
@@ -370,7 +369,7 @@ static void sbp_management_request_login( | |||
370 | * check exclusive bit in any existing login descriptor | 369 | * check exclusive bit in any existing login descriptor |
371 | * reject with access_denied if any exclusive logins present | 370 | * reject with access_denied if any exclusive logins present |
372 | */ | 371 | */ |
373 | if (sbp_login_count_all_by_lun(tpg, se_lun, 1)) { | 372 | if (sbp_login_count_all_by_lun(tpg, unpacked_lun, 1)) { |
374 | pr_warn("refusing login while another exclusive login present\n"); | 373 | pr_warn("refusing login while another exclusive login present\n"); |
375 | 374 | ||
376 | req->status.status = cpu_to_be32( | 375 | req->status.status = cpu_to_be32( |
@@ -383,7 +382,7 @@ static void sbp_management_request_login( | |||
383 | * check we haven't exceeded the number of allowed logins | 382 | * check we haven't exceeded the number of allowed logins |
384 | * reject with resources_unavailable if we have | 383 | * reject with resources_unavailable if we have |
385 | */ | 384 | */ |
386 | if (sbp_login_count_all_by_lun(tpg, se_lun, 0) >= | 385 | if (sbp_login_count_all_by_lun(tpg, unpacked_lun, 0) >= |
387 | tport->max_logins_per_lun) { | 386 | tport->max_logins_per_lun) { |
388 | pr_warn("max number of logins reached\n"); | 387 | pr_warn("max number of logins reached\n"); |
389 | 388 | ||
@@ -439,7 +438,7 @@ static void sbp_management_request_login( | |||
439 | } | 438 | } |
440 | 439 | ||
441 | login->sess = sess; | 440 | login->sess = sess; |
442 | login->lun = se_lun; | 441 | login->login_lun = unpacked_lun; |
443 | login->status_fifo_addr = sbp2_pointer_to_addr(&req->orb.status_fifo); | 442 | login->status_fifo_addr = sbp2_pointer_to_addr(&req->orb.status_fifo); |
444 | login->exclusive = LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)); | 443 | login->exclusive = LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)); |
445 | login->login_id = atomic_inc_return(&login_id); | 444 | login->login_id = atomic_inc_return(&login_id); |
@@ -601,7 +600,7 @@ static void sbp_management_request_logout( | |||
601 | } | 600 | } |
602 | 601 | ||
603 | pr_info("mgt_agent LOGOUT from LUN %d session %d\n", | 602 | pr_info("mgt_agent LOGOUT from LUN %d session %d\n", |
604 | login->lun->unpacked_lun, login->login_id); | 603 | login->login_lun, login->login_id); |
605 | 604 | ||
606 | if (req->node_addr != login->sess->node_id) { | 605 | if (req->node_addr != login->sess->node_id) { |
607 | pr_warn("logout from different node ID\n"); | 606 | pr_warn("logout from different node ID\n"); |
@@ -1227,7 +1226,7 @@ static void sbp_handle_command(struct sbp_target_request *req) | |||
1227 | goto err; | 1226 | goto err; |
1228 | } | 1227 | } |
1229 | 1228 | ||
1230 | unpacked_lun = req->login->lun->unpacked_lun; | 1229 | unpacked_lun = req->login->login_lun; |
1231 | sbp_calc_data_length_direction(req, &data_length, &data_dir); | 1230 | sbp_calc_data_length_direction(req, &data_length, &data_dir); |
1232 | 1231 | ||
1233 | pr_debug("sbp_handle_command ORB:0x%llx unpacked_lun:%d data_len:%d data_dir:%d\n", | 1232 | 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) | |||
1826 | 1825 | ||
1827 | static int sbp_count_se_tpg_luns(struct se_portal_group *tpg) | 1826 | static int sbp_count_se_tpg_luns(struct se_portal_group *tpg) |
1828 | { | 1827 | { |
1829 | int i, count = 0; | 1828 | struct se_lun *lun; |
1830 | 1829 | int count = 0; | |
1831 | spin_lock(&tpg->tpg_lun_lock); | ||
1832 | for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { | ||
1833 | struct se_lun *se_lun = tpg->tpg_lun_list[i]; | ||
1834 | |||
1835 | if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE) | ||
1836 | continue; | ||
1837 | 1830 | ||
1831 | rcu_read_lock(); | ||
1832 | hlist_for_each_entry_rcu(lun, &tpg->tpg_lun_hlist, link) | ||
1838 | count++; | 1833 | count++; |
1839 | } | 1834 | rcu_read_unlock(); |
1840 | spin_unlock(&tpg->tpg_lun_lock); | ||
1841 | 1835 | ||
1842 | return count; | 1836 | return count; |
1843 | } | 1837 | } |
1844 | 1838 | ||
1845 | static int sbp_update_unit_directory(struct sbp_tport *tport) | 1839 | static int sbp_update_unit_directory(struct sbp_tport *tport) |
1846 | { | 1840 | { |
1847 | int num_luns, num_entries, idx = 0, mgt_agt_addr, ret, i; | 1841 | struct se_lun *lun; |
1842 | int num_luns, num_entries, idx = 0, mgt_agt_addr, ret; | ||
1848 | u32 *data; | 1843 | u32 *data; |
1849 | 1844 | ||
1850 | if (tport->unit_directory.data) { | 1845 | if (tport->unit_directory.data) { |
@@ -1906,28 +1901,20 @@ static int sbp_update_unit_directory(struct sbp_tport *tport) | |||
1906 | /* unit unique ID (leaf is just after LUNs) */ | 1901 | /* unit unique ID (leaf is just after LUNs) */ |
1907 | data[idx++] = 0x8d000000 | (num_luns + 1); | 1902 | data[idx++] = 0x8d000000 | (num_luns + 1); |
1908 | 1903 | ||
1909 | spin_lock(&tport->tpg->se_tpg.tpg_lun_lock); | 1904 | rcu_read_lock(); |
1910 | for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { | 1905 | hlist_for_each_entry_rcu(lun, &tport->tpg->se_tpg.tpg_lun_hlist, link) { |
1911 | struct se_lun *se_lun = tport->tpg->se_tpg.tpg_lun_list[i]; | ||
1912 | struct se_device *dev; | 1906 | struct se_device *dev; |
1913 | int type; | 1907 | int type; |
1914 | 1908 | ||
1915 | if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE) | 1909 | dev = lun->lun_se_dev; |
1916 | continue; | ||
1917 | |||
1918 | spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock); | ||
1919 | |||
1920 | dev = se_lun->lun_se_dev; | ||
1921 | type = dev->transport->get_device_type(dev); | 1910 | type = dev->transport->get_device_type(dev); |
1922 | 1911 | ||
1923 | /* logical_unit_number */ | 1912 | /* logical_unit_number */ |
1924 | data[idx++] = 0x14000000 | | 1913 | data[idx++] = 0x14000000 | |
1925 | ((type << 16) & 0x1f0000) | | 1914 | ((type << 16) & 0x1f0000) | |
1926 | (se_lun->unpacked_lun & 0xffff); | 1915 | (lun->unpacked_lun & 0xffff); |
1927 | |||
1928 | spin_lock(&tport->tpg->se_tpg.tpg_lun_lock); | ||
1929 | } | 1916 | } |
1930 | spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock); | 1917 | rcu_read_unlock(); |
1931 | 1918 | ||
1932 | /* unit unique ID leaf */ | 1919 | /* unit unique ID leaf */ |
1933 | data[idx++] = 2 << 16; | 1920 | 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 { | |||
125 | struct sbp_session *sess; | 125 | struct sbp_session *sess; |
126 | struct list_head link; | 126 | struct list_head link; |
127 | 127 | ||
128 | struct se_lun *lun; | 128 | u32 login_lun; |
129 | 129 | ||
130 | u64 status_fifo_addr; | 130 | u64 status_fifo_addr; |
131 | int exclusive; | 131 | int exclusive; |