aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosef Bacik <josef@toxicpanda.com>2017-04-06 17:02:06 -0400
committerJens Axboe <axboe@fb.com>2017-04-17 11:58:42 -0400
commitc6a4759ea0c9a7e7661f34f6943dafb1c6ae1b1c (patch)
treea2a16f24b4ddf730ab97e385d6f8cd32163a39c1
parent47d902b90a32a42a3d33aef3a02170fc6f70aa23 (diff)
nbd: add device refcounting
In order to support deleting the device on disconnect we need to refcount the actual nbd_device struct. So add the refcounting framework and change how we free the normal devices at rmmod time so we can catch reference leaks. Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r--drivers/block/nbd.c104
1 files changed, 86 insertions, 18 deletions
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index cb45d799bc5c..4237e7286e99 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -99,10 +99,12 @@ struct nbd_device {
99 99
100 int index; 100 int index;
101 refcount_t config_refs; 101 refcount_t config_refs;
102 refcount_t refs;
102 struct nbd_config *config; 103 struct nbd_config *config;
103 struct mutex config_lock; 104 struct mutex config_lock;
104 struct gendisk *disk; 105 struct gendisk *disk;
105 106
107 struct list_head list;
106 struct task_struct *task_recv; 108 struct task_struct *task_recv;
107 struct task_struct *task_setup; 109 struct task_struct *task_setup;
108}; 110};
@@ -165,6 +167,28 @@ static struct device_attribute pid_attr = {
165 .show = pid_show, 167 .show = pid_show,
166}; 168};
167 169
170static 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
182static 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
168static int nbd_disconnected(struct nbd_config *config) 192static int nbd_disconnected(struct nbd_config *config)
169{ 193{
170 return test_bit(NBD_DISCONNECTED, &config->runtime_flags) || 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 nbd_reset(nbd); 1030 nbd_reset(nbd);
1007 mutex_unlock(&nbd->config_lock); 1031 mutex_unlock(&nbd->config_lock);
1032 nbd_put(nbd);
1008 module_put(THIS_MODULE); 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 ret = -ENXIO; 1224 ret = -ENXIO;
1200 goto out; 1225 goto out;
1201 } 1226 }
1227 if (!refcount_inc_not_zero(&nbd->refs)) {
1228 ret = -ENXIO;
1229 goto out;
1230 }
1202 if (!refcount_inc_not_zero(&nbd->config_refs)) { 1231 if (!refcount_inc_not_zero(&nbd->config_refs)) {
1203 struct nbd_config *config; 1232 struct nbd_config *config;
1204 1233
@@ -1214,6 +1243,7 @@ static int nbd_open(struct block_device *bdev, fmode_t mode)
1214 goto out; 1243 goto out;
1215 } 1244 }
1216 refcount_set(&nbd->config_refs, 1); 1245 refcount_set(&nbd->config_refs, 1);
1246 refcount_inc(&nbd->refs);
1217 mutex_unlock(&nbd->config_lock); 1247 mutex_unlock(&nbd->config_lock);
1218 } 1248 }
1219out: 1249out:
@@ -1225,6 +1255,7 @@ static void nbd_release(struct gendisk *disk, fmode_t mode)
1225{ 1255{
1226 struct nbd_device *nbd = disk->private_data; 1256 struct nbd_device *nbd = disk->private_data;
1227 nbd_config_put(nbd); 1257 nbd_config_put(nbd);
1258 nbd_put(nbd);
1228} 1259}
1229 1260
1230static const struct block_device_operations nbd_fops = 1261static const struct block_device_operations nbd_fops =
@@ -1378,18 +1409,6 @@ static const struct blk_mq_ops nbd_mq_ops = {
1378 .timeout = nbd_xmit_timeout, 1409 .timeout = nbd_xmit_timeout,
1379}; 1410};
1380 1411
1381static 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
1393static int nbd_dev_add(int index) 1412static int nbd_dev_add(int index)
1394{ 1413{
1395 struct nbd_device *nbd; 1414 struct nbd_device *nbd;
@@ -1452,6 +1471,8 @@ static int nbd_dev_add(int index)
1452 1471
1453 mutex_init(&nbd->config_lock); 1472 mutex_init(&nbd->config_lock);
1454 refcount_set(&nbd->config_refs, 0); 1473 refcount_set(&nbd->config_refs, 0);
1474 refcount_set(&nbd->refs, 1);
1475 INIT_LIST_HEAD(&nbd->list);
1455 disk->major = NBD_MAJOR; 1476 disk->major = NBD_MAJOR;
1456 disk->first_minor = index << part_shift; 1477 disk->first_minor = index << part_shift;
1457 disk->fops = &nbd_fops; 1478 disk->fops = &nbd_fops;
@@ -1549,16 +1570,26 @@ again:
1549 } else { 1570 } else {
1550 nbd = idr_find(&nbd_index_idr, index); 1571 nbd = idr_find(&nbd_index_idr, index);
1551 } 1572 }
1552 mutex_unlock(&nbd_index_mutex);
1553 if (!nbd) { 1573 if (!nbd) {
1554 printk(KERN_ERR "nbd: couldn't find device at index %d\n", 1574 printk(KERN_ERR "nbd: couldn't find device at index %d\n",
1555 index); 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 return -EINVAL; 1585 return -EINVAL;
1557 } 1586 }
1587 mutex_unlock(&nbd_index_mutex);
1558 1588
1559 mutex_lock(&nbd->config_lock); 1589 mutex_lock(&nbd->config_lock);
1560 if (refcount_read(&nbd->config_refs)) { 1590 if (refcount_read(&nbd->config_refs)) {
1561 mutex_unlock(&nbd->config_lock); 1591 mutex_unlock(&nbd->config_lock);
1592 nbd_put(nbd);
1562 if (index == -1) 1593 if (index == -1)
1563 goto again; 1594 goto again;
1564 printk(KERN_ERR "nbd: nbd%d already in use\n", index); 1595 printk(KERN_ERR "nbd: nbd%d already in use\n", index);
@@ -1566,11 +1597,13 @@ again:
1566 } 1597 }
1567 if (WARN_ON(nbd->config)) { 1598 if (WARN_ON(nbd->config)) {
1568 mutex_unlock(&nbd->config_lock); 1599 mutex_unlock(&nbd->config_lock);
1600 nbd_put(nbd);
1569 return -EINVAL; 1601 return -EINVAL;
1570 } 1602 }
1571 config = nbd->config = nbd_alloc_config(); 1603 config = nbd->config = nbd_alloc_config();
1572 if (!nbd->config) { 1604 if (!nbd->config) {
1573 mutex_unlock(&nbd->config_lock); 1605 mutex_unlock(&nbd->config_lock);
1606 nbd_put(nbd);
1574 printk(KERN_ERR "nbd: couldn't allocate config\n"); 1607 printk(KERN_ERR "nbd: couldn't allocate config\n");
1575 return -ENOMEM; 1608 return -ENOMEM;
1576 } 1609 }
@@ -1655,14 +1688,23 @@ static int nbd_genl_disconnect(struct sk_buff *skb, struct genl_info *info)
1655 index = nla_get_u32(info->attrs[NBD_ATTR_INDEX]); 1688 index = nla_get_u32(info->attrs[NBD_ATTR_INDEX]);
1656 mutex_lock(&nbd_index_mutex); 1689 mutex_lock(&nbd_index_mutex);
1657 nbd = idr_find(&nbd_index_idr, index); 1690 nbd = idr_find(&nbd_index_idr, index);
1658 mutex_unlock(&nbd_index_mutex);
1659 if (!nbd) { 1691 if (!nbd) {
1692 mutex_unlock(&nbd_index_mutex);
1660 printk(KERN_ERR "nbd: couldn't find device at index %d\n", 1693 printk(KERN_ERR "nbd: couldn't find device at index %d\n",
1661 index); 1694 index);
1662 return -EINVAL; 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 return 0; 1706 return 0;
1707 }
1666 mutex_lock(&nbd->config_lock); 1708 mutex_lock(&nbd->config_lock);
1667 nbd_disconnect(nbd); 1709 nbd_disconnect(nbd);
1668 mutex_unlock(&nbd->config_lock); 1710 mutex_unlock(&nbd->config_lock);
@@ -1670,6 +1712,7 @@ static int nbd_genl_disconnect(struct sk_buff *skb, struct genl_info *info)
1670 &nbd->config->runtime_flags)) 1712 &nbd->config->runtime_flags))
1671 nbd_config_put(nbd); 1713 nbd_config_put(nbd);
1672 nbd_config_put(nbd); 1714 nbd_config_put(nbd);
1715 nbd_put(nbd);
1673 return 0; 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 index = nla_get_u32(info->attrs[NBD_ATTR_INDEX]); 1733 index = nla_get_u32(info->attrs[NBD_ATTR_INDEX]);
1691 mutex_lock(&nbd_index_mutex); 1734 mutex_lock(&nbd_index_mutex);
1692 nbd = idr_find(&nbd_index_idr, index); 1735 nbd = idr_find(&nbd_index_idr, index);
1693 mutex_unlock(&nbd_index_mutex);
1694 if (!nbd) { 1736 if (!nbd) {
1737 mutex_unlock(&nbd_index_mutex);
1695 printk(KERN_ERR "nbd: couldn't find a device at index %d\n", 1738 printk(KERN_ERR "nbd: couldn't find a device at index %d\n",
1696 index); 1739 index);
1697 return -EINVAL; 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 if (!refcount_inc_not_zero(&nbd->config_refs)) { 1750 if (!refcount_inc_not_zero(&nbd->config_refs)) {
1701 dev_err(nbd_to_dev(nbd), 1751 dev_err(nbd_to_dev(nbd),
1702 "not configured, cannot reconfigure\n"); 1752 "not configured, cannot reconfigure\n");
1753 nbd_put(nbd);
1703 return -EINVAL; 1754 return -EINVAL;
1704 } 1755 }
1705 1756
@@ -1758,6 +1809,7 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
1758out: 1809out:
1759 mutex_unlock(&nbd->config_lock); 1810 mutex_unlock(&nbd->config_lock);
1760 nbd_config_put(nbd); 1811 nbd_config_put(nbd);
1812 nbd_put(nbd);
1761 return ret; 1813 return ret;
1762} 1814}
1763 1815
@@ -2003,16 +2055,32 @@ static int __init nbd_init(void)
2003 2055
2004static int nbd_exit_cb(int id, void *ptr, void *data) 2056static int nbd_exit_cb(int id, void *ptr, void *data)
2005{ 2057{
2058 struct list_head *list = (struct list_head *)data;
2006 struct nbd_device *nbd = ptr; 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 return 0; 2063 return 0;
2009} 2064}
2010 2065
2011static void __exit nbd_cleanup(void) 2066static void __exit nbd_cleanup(void)
2012{ 2067{
2068 struct nbd_device *nbd;
2069 LIST_HEAD(del_list);
2070
2013 nbd_dbg_close(); 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 idr_destroy(&nbd_index_idr); 2084 idr_destroy(&nbd_index_idr);
2017 genl_unregister_family(&nbd_genl_family); 2085 genl_unregister_family(&nbd_genl_family);
2018 destroy_workqueue(recv_workqueue); 2086 destroy_workqueue(recv_workqueue);