aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Grover <agrover@redhat.com>2014-01-24 19:18:54 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-02-06 14:08:17 -0500
commit85c3c54bf969f0fd9ba59ee3f6e9849b53428412 (patch)
treeaebb442573f42166a6948200d417e82d05182518
parent26996fcd25dda2f6d34d1888d26585cd519f6af5 (diff)
target/iscsi: Fix network portal creation race
commit ee291e63293146db64668e8d65eb35c97e8324f4 upstream. When creating network portals rapidly, such as when restoring a configuration, LIO's code to reuse existing portals can return a false negative if the thread hasn't run yet and set np_thread_state to ISCSI_NP_THREAD_ACTIVE. This causes an error in the network stack when attempting to bind to the same address/port. This patch sets NP_THREAD_ACTIVE before the np is placed on g_np_list, so even if the thread hasn't run yet, iscsit_get_np will return the existing np. Also, convert np_lock -> np_mutex + hold across adding new net portal to g_np_list to prevent a race where two threads may attempt to create the same network portal, resulting in one of them failing. (nab: Add missing mutex_unlocks in iscsit_add_np failure paths) (DanC: Fix incorrect spin_unlock -> spin_unlock_bh) Signed-off-by: Andy Grover <agrover@redhat.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/target/iscsi/iscsi_target.c34
1 files changed, 21 insertions, 13 deletions
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index b71a69750607..5b07fd156bd7 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -54,7 +54,7 @@
54static LIST_HEAD(g_tiqn_list); 54static LIST_HEAD(g_tiqn_list);
55static LIST_HEAD(g_np_list); 55static LIST_HEAD(g_np_list);
56static DEFINE_SPINLOCK(tiqn_lock); 56static DEFINE_SPINLOCK(tiqn_lock);
57static DEFINE_SPINLOCK(np_lock); 57static DEFINE_MUTEX(np_lock);
58 58
59static struct idr tiqn_idr; 59static struct idr tiqn_idr;
60struct idr sess_idr; 60struct idr sess_idr;
@@ -303,6 +303,9 @@ bool iscsit_check_np_match(
303 return false; 303 return false;
304} 304}
305 305
306/*
307 * Called with mutex np_lock held
308 */
306static struct iscsi_np *iscsit_get_np( 309static struct iscsi_np *iscsit_get_np(
307 struct __kernel_sockaddr_storage *sockaddr, 310 struct __kernel_sockaddr_storage *sockaddr,
308 int network_transport) 311 int network_transport)
@@ -310,11 +313,10 @@ static struct iscsi_np *iscsit_get_np(
310 struct iscsi_np *np; 313 struct iscsi_np *np;
311 bool match; 314 bool match;
312 315
313 spin_lock_bh(&np_lock);
314 list_for_each_entry(np, &g_np_list, np_list) { 316 list_for_each_entry(np, &g_np_list, np_list) {
315 spin_lock(&np->np_thread_lock); 317 spin_lock_bh(&np->np_thread_lock);
316 if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) { 318 if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
317 spin_unlock(&np->np_thread_lock); 319 spin_unlock_bh(&np->np_thread_lock);
318 continue; 320 continue;
319 } 321 }
320 322
@@ -326,13 +328,11 @@ static struct iscsi_np *iscsit_get_np(
326 * while iscsi_tpg_add_network_portal() is called. 328 * while iscsi_tpg_add_network_portal() is called.
327 */ 329 */
328 np->np_exports++; 330 np->np_exports++;
329 spin_unlock(&np->np_thread_lock); 331 spin_unlock_bh(&np->np_thread_lock);
330 spin_unlock_bh(&np_lock);
331 return np; 332 return np;
332 } 333 }
333 spin_unlock(&np->np_thread_lock); 334 spin_unlock_bh(&np->np_thread_lock);
334 } 335 }
335 spin_unlock_bh(&np_lock);
336 336
337 return NULL; 337 return NULL;
338} 338}
@@ -346,16 +346,22 @@ struct iscsi_np *iscsit_add_np(
346 struct sockaddr_in6 *sock_in6; 346 struct sockaddr_in6 *sock_in6;
347 struct iscsi_np *np; 347 struct iscsi_np *np;
348 int ret; 348 int ret;
349
350 mutex_lock(&np_lock);
351
349 /* 352 /*
350 * Locate the existing struct iscsi_np if already active.. 353 * Locate the existing struct iscsi_np if already active..
351 */ 354 */
352 np = iscsit_get_np(sockaddr, network_transport); 355 np = iscsit_get_np(sockaddr, network_transport);
353 if (np) 356 if (np) {
357 mutex_unlock(&np_lock);
354 return np; 358 return np;
359 }
355 360
356 np = kzalloc(sizeof(struct iscsi_np), GFP_KERNEL); 361 np = kzalloc(sizeof(struct iscsi_np), GFP_KERNEL);
357 if (!np) { 362 if (!np) {
358 pr_err("Unable to allocate memory for struct iscsi_np\n"); 363 pr_err("Unable to allocate memory for struct iscsi_np\n");
364 mutex_unlock(&np_lock);
359 return ERR_PTR(-ENOMEM); 365 return ERR_PTR(-ENOMEM);
360 } 366 }
361 367
@@ -378,6 +384,7 @@ struct iscsi_np *iscsit_add_np(
378 ret = iscsi_target_setup_login_socket(np, sockaddr); 384 ret = iscsi_target_setup_login_socket(np, sockaddr);
379 if (ret != 0) { 385 if (ret != 0) {
380 kfree(np); 386 kfree(np);
387 mutex_unlock(&np_lock);
381 return ERR_PTR(ret); 388 return ERR_PTR(ret);
382 } 389 }
383 390
@@ -386,6 +393,7 @@ struct iscsi_np *iscsit_add_np(
386 pr_err("Unable to create kthread: iscsi_np\n"); 393 pr_err("Unable to create kthread: iscsi_np\n");
387 ret = PTR_ERR(np->np_thread); 394 ret = PTR_ERR(np->np_thread);
388 kfree(np); 395 kfree(np);
396 mutex_unlock(&np_lock);
389 return ERR_PTR(ret); 397 return ERR_PTR(ret);
390 } 398 }
391 /* 399 /*
@@ -396,10 +404,10 @@ struct iscsi_np *iscsit_add_np(
396 * point because iscsi_np has not been added to g_np_list yet. 404 * point because iscsi_np has not been added to g_np_list yet.
397 */ 405 */
398 np->np_exports = 1; 406 np->np_exports = 1;
407 np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
399 408
400 spin_lock_bh(&np_lock);
401 list_add_tail(&np->np_list, &g_np_list); 409 list_add_tail(&np->np_list, &g_np_list);
402 spin_unlock_bh(&np_lock); 410 mutex_unlock(&np_lock);
403 411
404 pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n", 412 pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n",
405 np->np_ip, np->np_port, np->np_transport->name); 413 np->np_ip, np->np_port, np->np_transport->name);
@@ -469,9 +477,9 @@ int iscsit_del_np(struct iscsi_np *np)
469 477
470 np->np_transport->iscsit_free_np(np); 478 np->np_transport->iscsit_free_np(np);
471 479
472 spin_lock_bh(&np_lock); 480 mutex_lock(&np_lock);
473 list_del(&np->np_list); 481 list_del(&np->np_list);
474 spin_unlock_bh(&np_lock); 482 mutex_unlock(&np_lock);
475 483
476 pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n", 484 pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n",
477 np->np_ip, np->np_port, np->np_transport->name); 485 np->np_ip, np->np_port, np->np_transport->name);