Skip to content

Commit ee291e6

Browse files
Andy GroverNicholas Bellinger
Andy Grover
authored and
Nicholas Bellinger
committed
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 <[email protected]> Cc: <[email protected]> #3.1+ Signed-off-by: Nicholas Bellinger <[email protected]>
1 parent 76736db commit ee291e6

File tree

1 file changed

+21
-13
lines changed

1 file changed

+21
-13
lines changed

drivers/target/iscsi/iscsi_target.c

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
static LIST_HEAD(g_tiqn_list);
5353
static LIST_HEAD(g_np_list);
5454
static DEFINE_SPINLOCK(tiqn_lock);
55-
static DEFINE_SPINLOCK(np_lock);
55+
static DEFINE_MUTEX(np_lock);
5656

5757
static struct idr tiqn_idr;
5858
struct idr sess_idr;
@@ -307,18 +307,20 @@ bool iscsit_check_np_match(
307307
return false;
308308
}
309309

310+
/*
311+
* Called with mutex np_lock held
312+
*/
310313
static struct iscsi_np *iscsit_get_np(
311314
struct __kernel_sockaddr_storage *sockaddr,
312315
int network_transport)
313316
{
314317
struct iscsi_np *np;
315318
bool match;
316319

317-
spin_lock_bh(&np_lock);
318320
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);
320322
if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
321-
spin_unlock(&np->np_thread_lock);
323+
spin_unlock_bh(&np->np_thread_lock);
322324
continue;
323325
}
324326

@@ -330,13 +332,11 @@ static struct iscsi_np *iscsit_get_np(
330332
* while iscsi_tpg_add_network_portal() is called.
331333
*/
332334
np->np_exports++;
333-
spin_unlock(&np->np_thread_lock);
334-
spin_unlock_bh(&np_lock);
335+
spin_unlock_bh(&np->np_thread_lock);
335336
return np;
336337
}
337-
spin_unlock(&np->np_thread_lock);
338+
spin_unlock_bh(&np->np_thread_lock);
338339
}
339-
spin_unlock_bh(&np_lock);
340340

341341
return NULL;
342342
}
@@ -350,16 +350,22 @@ struct iscsi_np *iscsit_add_np(
350350
struct sockaddr_in6 *sock_in6;
351351
struct iscsi_np *np;
352352
int ret;
353+
354+
mutex_lock(&np_lock);
355+
353356
/*
354357
* Locate the existing struct iscsi_np if already active..
355358
*/
356359
np = iscsit_get_np(sockaddr, network_transport);
357-
if (np)
360+
if (np) {
361+
mutex_unlock(&np_lock);
358362
return np;
363+
}
359364

360365
np = kzalloc(sizeof(struct iscsi_np), GFP_KERNEL);
361366
if (!np) {
362367
pr_err("Unable to allocate memory for struct iscsi_np\n");
368+
mutex_unlock(&np_lock);
363369
return ERR_PTR(-ENOMEM);
364370
}
365371

@@ -382,6 +388,7 @@ struct iscsi_np *iscsit_add_np(
382388
ret = iscsi_target_setup_login_socket(np, sockaddr);
383389
if (ret != 0) {
384390
kfree(np);
391+
mutex_unlock(&np_lock);
385392
return ERR_PTR(ret);
386393
}
387394

@@ -390,6 +397,7 @@ struct iscsi_np *iscsit_add_np(
390397
pr_err("Unable to create kthread: iscsi_np\n");
391398
ret = PTR_ERR(np->np_thread);
392399
kfree(np);
400+
mutex_unlock(&np_lock);
393401
return ERR_PTR(ret);
394402
}
395403
/*
@@ -400,10 +408,10 @@ struct iscsi_np *iscsit_add_np(
400408
* point because iscsi_np has not been added to g_np_list yet.
401409
*/
402410
np->np_exports = 1;
411+
np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
403412

404-
spin_lock_bh(&np_lock);
405413
list_add_tail(&np->np_list, &g_np_list);
406-
spin_unlock_bh(&np_lock);
414+
mutex_unlock(&np_lock);
407415

408416
pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n",
409417
np->np_ip, np->np_port, np->np_transport->name);
@@ -469,9 +477,9 @@ int iscsit_del_np(struct iscsi_np *np)
469477

470478
np->np_transport->iscsit_free_np(np);
471479

472-
spin_lock_bh(&np_lock);
480+
mutex_lock(&np_lock);
473481
list_del(&np->np_list);
474-
spin_unlock_bh(&np_lock);
482+
mutex_unlock(&np_lock);
475483

476484
pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n",
477485
np->np_ip, np->np_port, np->np_transport->name);

0 commit comments

Comments
 (0)