@@ -99,10 +99,12 @@ struct nbd_device {
99
99
100
100
int index ;
101
101
refcount_t config_refs ;
102
+ refcount_t refs ;
102
103
struct nbd_config * config ;
103
104
struct mutex config_lock ;
104
105
struct gendisk * disk ;
105
106
107
+ struct list_head list ;
106
108
struct task_struct * task_recv ;
107
109
struct task_struct * task_setup ;
108
110
};
@@ -165,6 +167,28 @@ static struct device_attribute pid_attr = {
165
167
.show = pid_show ,
166
168
};
167
169
170
+ static void nbd_dev_remove (struct nbd_device * nbd )
171
+ {
172
+ struct gendisk * disk = nbd -> disk ;
173
+ if (disk ) {
174
+ del_gendisk (disk );
175
+ blk_cleanup_queue (disk -> queue );
176
+ blk_mq_free_tag_set (& nbd -> tag_set );
177
+ put_disk (disk );
178
+ }
179
+ kfree (nbd );
180
+ }
181
+
182
+ static void nbd_put (struct nbd_device * nbd )
183
+ {
184
+ if (refcount_dec_and_mutex_lock (& nbd -> refs ,
185
+ & nbd_index_mutex )) {
186
+ idr_remove (& nbd_index_idr , nbd -> index );
187
+ mutex_unlock (& nbd_index_mutex );
188
+ nbd_dev_remove (nbd );
189
+ }
190
+ }
191
+
168
192
static int nbd_disconnected (struct nbd_config * config )
169
193
{
170
194
return test_bit (NBD_DISCONNECTED , & config -> runtime_flags ) ||
@@ -1005,6 +1029,7 @@ static void nbd_config_put(struct nbd_device *nbd)
1005
1029
}
1006
1030
nbd_reset (nbd );
1007
1031
mutex_unlock (& nbd -> config_lock );
1032
+ nbd_put (nbd );
1008
1033
module_put (THIS_MODULE );
1009
1034
}
1010
1035
}
@@ -1199,6 +1224,10 @@ static int nbd_open(struct block_device *bdev, fmode_t mode)
1199
1224
ret = - ENXIO ;
1200
1225
goto out ;
1201
1226
}
1227
+ if (!refcount_inc_not_zero (& nbd -> refs )) {
1228
+ ret = - ENXIO ;
1229
+ goto out ;
1230
+ }
1202
1231
if (!refcount_inc_not_zero (& nbd -> config_refs )) {
1203
1232
struct nbd_config * config ;
1204
1233
@@ -1214,6 +1243,7 @@ static int nbd_open(struct block_device *bdev, fmode_t mode)
1214
1243
goto out ;
1215
1244
}
1216
1245
refcount_set (& nbd -> config_refs , 1 );
1246
+ refcount_inc (& nbd -> refs );
1217
1247
mutex_unlock (& nbd -> config_lock );
1218
1248
}
1219
1249
out :
@@ -1225,6 +1255,7 @@ static void nbd_release(struct gendisk *disk, fmode_t mode)
1225
1255
{
1226
1256
struct nbd_device * nbd = disk -> private_data ;
1227
1257
nbd_config_put (nbd );
1258
+ nbd_put (nbd );
1228
1259
}
1229
1260
1230
1261
static const struct block_device_operations nbd_fops =
@@ -1378,18 +1409,6 @@ static const struct blk_mq_ops nbd_mq_ops = {
1378
1409
.timeout = nbd_xmit_timeout ,
1379
1410
};
1380
1411
1381
- static void nbd_dev_remove (struct nbd_device * nbd )
1382
- {
1383
- struct gendisk * disk = nbd -> disk ;
1384
- if (disk ) {
1385
- del_gendisk (disk );
1386
- blk_cleanup_queue (disk -> queue );
1387
- blk_mq_free_tag_set (& nbd -> tag_set );
1388
- put_disk (disk );
1389
- }
1390
- kfree (nbd );
1391
- }
1392
-
1393
1412
static int nbd_dev_add (int index )
1394
1413
{
1395
1414
struct nbd_device * nbd ;
@@ -1452,6 +1471,8 @@ static int nbd_dev_add(int index)
1452
1471
1453
1472
mutex_init (& nbd -> config_lock );
1454
1473
refcount_set (& nbd -> config_refs , 0 );
1474
+ refcount_set (& nbd -> refs , 1 );
1475
+ INIT_LIST_HEAD (& nbd -> list );
1455
1476
disk -> major = NBD_MAJOR ;
1456
1477
disk -> first_minor = index << part_shift ;
1457
1478
disk -> fops = & nbd_fops ;
@@ -1549,28 +1570,40 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info)
1549
1570
} else {
1550
1571
nbd = idr_find (& nbd_index_idr , index );
1551
1572
}
1552
- mutex_unlock (& nbd_index_mutex );
1553
1573
if (!nbd ) {
1554
1574
printk (KERN_ERR "nbd: couldn't find device at index %d\n" ,
1555
1575
index );
1576
+ mutex_unlock (& nbd_index_mutex );
1577
+ return - EINVAL ;
1578
+ }
1579
+ if (!refcount_inc_not_zero (& nbd -> refs )) {
1580
+ mutex_unlock (& nbd_index_mutex );
1581
+ if (index == -1 )
1582
+ goto again ;
1583
+ printk (KERN_ERR "nbd: device at index %d is going down\n" ,
1584
+ index );
1556
1585
return - EINVAL ;
1557
1586
}
1587
+ mutex_unlock (& nbd_index_mutex );
1558
1588
1559
1589
mutex_lock (& nbd -> config_lock );
1560
1590
if (refcount_read (& nbd -> config_refs )) {
1561
1591
mutex_unlock (& nbd -> config_lock );
1592
+ nbd_put (nbd );
1562
1593
if (index == -1 )
1563
1594
goto again ;
1564
1595
printk (KERN_ERR "nbd: nbd%d already in use\n" , index );
1565
1596
return - EBUSY ;
1566
1597
}
1567
1598
if (WARN_ON (nbd -> config )) {
1568
1599
mutex_unlock (& nbd -> config_lock );
1600
+ nbd_put (nbd );
1569
1601
return - EINVAL ;
1570
1602
}
1571
1603
config = nbd -> config = nbd_alloc_config ();
1572
1604
if (!nbd -> config ) {
1573
1605
mutex_unlock (& nbd -> config_lock );
1606
+ nbd_put (nbd );
1574
1607
printk (KERN_ERR "nbd: couldn't allocate config\n" );
1575
1608
return - ENOMEM ;
1576
1609
}
@@ -1655,21 +1688,31 @@ static int nbd_genl_disconnect(struct sk_buff *skb, struct genl_info *info)
1655
1688
index = nla_get_u32 (info -> attrs [NBD_ATTR_INDEX ]);
1656
1689
mutex_lock (& nbd_index_mutex );
1657
1690
nbd = idr_find (& nbd_index_idr , index );
1658
- mutex_unlock (& nbd_index_mutex );
1659
1691
if (!nbd ) {
1692
+ mutex_unlock (& nbd_index_mutex );
1660
1693
printk (KERN_ERR "nbd: couldn't find device at index %d\n" ,
1661
1694
index );
1662
1695
return - EINVAL ;
1663
1696
}
1664
- if (!refcount_inc_not_zero (& nbd -> config_refs ))
1697
+ if (!refcount_inc_not_zero (& nbd -> refs )) {
1698
+ mutex_unlock (& nbd_index_mutex );
1699
+ printk (KERN_ERR "nbd: device at index %d is going down\n" ,
1700
+ index );
1701
+ return - EINVAL ;
1702
+ }
1703
+ mutex_unlock (& nbd_index_mutex );
1704
+ if (!refcount_inc_not_zero (& nbd -> config_refs )) {
1705
+ nbd_put (nbd );
1665
1706
return 0 ;
1707
+ }
1666
1708
mutex_lock (& nbd -> config_lock );
1667
1709
nbd_disconnect (nbd );
1668
1710
mutex_unlock (& nbd -> config_lock );
1669
1711
if (test_and_clear_bit (NBD_HAS_CONFIG_REF ,
1670
1712
& nbd -> config -> runtime_flags ))
1671
1713
nbd_config_put (nbd );
1672
1714
nbd_config_put (nbd );
1715
+ nbd_put (nbd );
1673
1716
return 0 ;
1674
1717
}
1675
1718
@@ -1690,16 +1733,24 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
1690
1733
index = nla_get_u32 (info -> attrs [NBD_ATTR_INDEX ]);
1691
1734
mutex_lock (& nbd_index_mutex );
1692
1735
nbd = idr_find (& nbd_index_idr , index );
1693
- mutex_unlock (& nbd_index_mutex );
1694
1736
if (!nbd ) {
1737
+ mutex_unlock (& nbd_index_mutex );
1695
1738
printk (KERN_ERR "nbd: couldn't find a device at index %d\n" ,
1696
1739
index );
1697
1740
return - EINVAL ;
1698
1741
}
1742
+ if (!refcount_inc_not_zero (& nbd -> refs )) {
1743
+ mutex_unlock (& nbd_index_mutex );
1744
+ printk (KERN_ERR "nbd: device at index %d is going down\n" ,
1745
+ index );
1746
+ return - EINVAL ;
1747
+ }
1748
+ mutex_unlock (& nbd_index_mutex );
1699
1749
1700
1750
if (!refcount_inc_not_zero (& nbd -> config_refs )) {
1701
1751
dev_err (nbd_to_dev (nbd ),
1702
1752
"not configured, cannot reconfigure\n" );
1753
+ nbd_put (nbd );
1703
1754
return - EINVAL ;
1704
1755
}
1705
1756
@@ -1758,6 +1809,7 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
1758
1809
out :
1759
1810
mutex_unlock (& nbd -> config_lock );
1760
1811
nbd_config_put (nbd );
1812
+ nbd_put (nbd );
1761
1813
return ret ;
1762
1814
}
1763
1815
@@ -2003,16 +2055,32 @@ static int __init nbd_init(void)
2003
2055
2004
2056
static int nbd_exit_cb (int id , void * ptr , void * data )
2005
2057
{
2058
+ struct list_head * list = (struct list_head * )data ;
2006
2059
struct nbd_device * nbd = ptr ;
2007
- nbd_dev_remove (nbd );
2060
+
2061
+ refcount_inc (& nbd -> refs );
2062
+ list_add_tail (& nbd -> list , list );
2008
2063
return 0 ;
2009
2064
}
2010
2065
2011
2066
static void __exit nbd_cleanup (void )
2012
2067
{
2068
+ struct nbd_device * nbd ;
2069
+ LIST_HEAD (del_list );
2070
+
2013
2071
nbd_dbg_close ();
2014
2072
2015
- idr_for_each (& nbd_index_idr , & nbd_exit_cb , NULL );
2073
+ mutex_lock (& nbd_index_mutex );
2074
+ idr_for_each (& nbd_index_idr , & nbd_exit_cb , & del_list );
2075
+ mutex_unlock (& nbd_index_mutex );
2076
+
2077
+ list_for_each_entry (nbd , & del_list , list ) {
2078
+ if (refcount_read (& nbd -> refs ) != 2 )
2079
+ printk (KERN_ERR "nbd: possibly leaking a device\n" );
2080
+ nbd_put (nbd );
2081
+ nbd_put (nbd );
2082
+ }
2083
+
2016
2084
idr_destroy (& nbd_index_idr );
2017
2085
genl_unregister_family (& nbd_genl_family );
2018
2086
destroy_workqueue (recv_workqueue );
0 commit comments