aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Grover <agrover@redhat.com>2014-01-24 19:18:54 -0500
committerNicholas Bellinger <nab@linux-iscsi.org>2014-01-30 06:57:59 -0500
commitee291e63293146db64668e8d65eb35c97e8324f4 (patch)
tree181aa6e882c51aa5ccfe0d116a51a3552e2055f8
parent76736db3e291246fbce9db856706af3454b0b078 (diff)
target/iscsi: Fix network portal creation race
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> Cc: <stable@vger.kernel.org> #3.1+ Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.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 2a52752a9937..a99637e9e820 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -52,7 +52,7 @@
52static LIST_HEAD(g_tiqn_list); 52static LIST_HEAD(g_tiqn_list);
53static LIST_HEAD(g_np_list); 53static LIST_HEAD(g_np_list);
54static DEFINE_SPINLOCK(tiqn_lock); 54static DEFINE_SPINLOCK(tiqn_lock);
55static DEFINE_SPINLOCK(np_lock); 55static DEFINE_MUTEX(np_lock);
56 56
57static struct idr tiqn_idr; 57static struct idr tiqn_idr;
58struct idr sess_idr; 58struct idr sess_idr;
@@ -307,6 +307,9 @@ bool iscsit_check_np_match(
307 return false; 307 return false;
308} 308}
309 309
310/*
311 * Called with mutex np_lock held
312 */
310static struct iscsi_np *iscsit_get_np( 313static struct iscsi_np *iscsit_get_np(
311 struct __kernel_sockaddr_storage *sockaddr, 314 struct __kernel_sockaddr_storage *sockaddr,
312 int network_transport) 315 int network_transport)
@@ -314,11 +317,10 @@ static struct iscsi_np *iscsit_get_np(
314 struct iscsi_np *np; 317 struct iscsi_np *np;
315 bool match; 318 bool match;
316 319
317 spin_lock_bh(&np_lock);
318 list_for_each_entry(np, &g_np_list, np_list) { 320 list_for_each_entry(np, &g_np_list, np_list) {
319 spin_lock(&np->np_thread_lock); 321 spin_lock_bh(&np->np_thread_lock);
320 if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) { 322 if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
321 spin_unlock(&np->np_thread_lock); 323 spin_unlock_bh(&np->np_thread_lock);
322 continue; 324 continue;
323 } 325 }
324 326
@@ -330,13 +332,11 @@ static struct iscsi_np *iscsit_get_np(
330 * while iscsi_tpg_add_network_portal() is called. 332 * while iscsi_tpg_add_network_portal() is called.
331 */ 333 */
332 np->np_exports++; 334 np->np_exports++;
333 spin_unlock(&np->np_thread_lock); 335 spin_unlock_bh(&np->np_thread_lock);
334 spin_unlock_bh(&np_lock);
335 return np; 336 return np;
336 } 337 }
337 spin_unlock(&np->np_thread_lock); 338 spin_unlock_bh(&np->np_thread_lock);
338 } 339 }
339 spin_unlock_bh(&np_lock);
340 340
341 return NULL; 341 return NULL;
342} 342}
@@ -350,16 +350,22 @@ struct iscsi_np *iscsit_add_np(
350 struct sockaddr_in6 *sock_in6; 350 struct sockaddr_in6 *sock_in6;
351 struct iscsi_np *np; 351 struct iscsi_np *np;
352 int ret; 352 int ret;
353
354 mutex_lock(&np_lock);
355
353 /* 356 /*
354 * Locate the existing struct iscsi_np if already active.. 357 * Locate the existing struct iscsi_np if already active..
355 */ 358 */
356 np = iscsit_get_np(sockaddr, network_transport); 359 np = iscsit_get_np(sockaddr, network_transport);
357 if (np) 360 if (np) {
361 mutex_unlock(&np_lock);
358 return np; 362 return np;
363 }
359 364
360 np = kzalloc(sizeof(struct iscsi_np), GFP_KERNEL); 365 np = kzalloc(sizeof(struct iscsi_np), GFP_KERNEL);
361 if (!np) { 366 if (!np) {
362 pr_err("Unable to allocate memory for struct iscsi_np\n"); 367 pr_err("Unable to allocate memory for struct iscsi_np\n");
368 mutex_unlock(&np_lock);
363 return ERR_PTR(-ENOMEM); 369 return ERR_PTR(-ENOMEM);
364 } 370 }
365 371
@@ -382,6 +388,7 @@ struct iscsi_np *iscsit_add_np(
382 ret = iscsi_target_setup_login_socket(np, sockaddr); 388 ret = iscsi_target_setup_login_socket(np, sockaddr);
383 if (ret != 0) { 389 if (ret != 0) {
384 kfree(np); 390 kfree(np);
391 mutex_unlock(&np_lock);
385 return ERR_PTR(ret); 392 return ERR_PTR(ret);
386 } 393 }
387 394
@@ -390,6 +397,7 @@ struct iscsi_np *iscsit_add_np(
390 pr_err("Unable to create kthread: iscsi_np\n"); 397 pr_err("Unable to create kthread: iscsi_np\n");
391 ret = PTR_ERR(np->np_thread); 398 ret = PTR_ERR(np->np_thread);
392 kfree(np); 399 kfree(np);
400 mutex_unlock(&np_lock);
393 return ERR_PTR(ret); 401 return ERR_PTR(ret);
394 } 402 }
395 /* 403 /*
@@ -400,10 +408,10 @@ struct iscsi_np *iscsit_add_np(
400 * point because iscsi_np has not been added to g_np_list yet. 408 * point because iscsi_np has not been added to g_np_list yet.
401 */ 409 */
402 np->np_exports = 1; 410 np->np_exports = 1;
411 np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
403 412
404 spin_lock_bh(&np_lock);
405 list_add_tail(&np->np_list, &g_np_list); 413 list_add_tail(&np->np_list, &g_np_list);
406 spin_unlock_bh(&np_lock); 414 mutex_unlock(&np_lock);
407 415
408 pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n", 416 pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n",
409 np->np_ip, np->np_port, np->np_transport->name); 417 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);