Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nbd: Add the nbd NBD_DISCONNECT_ON_CLOSE config flag.

If NBD_DISCONNECT_ON_CLOSE is set on a device, then the driver will
issue a disconnect from nbd_release if the device has no remaining
bdev->bd_openers.

Fix ret val so reconfigure with only setting the flag succeeds.

Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Doron Roberts-Kedes <doronrk@fb.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Doron Roberts-Kedes and committed by
Jens Axboe
08ba91ee ce042c18

+37 -8
+34 -8
drivers/block/nbd.c
··· 76 76 #define NBD_HAS_CONFIG_REF 4 77 77 #define NBD_BOUND 5 78 78 #define NBD_DESTROY_ON_DISCONNECT 6 79 + #define NBD_DISCONNECT_ON_CLOSE 7 79 80 80 81 struct nbd_config { 81 82 u32 flags; ··· 139 138 static void nbd_connect_reply(struct genl_info *info, int index); 140 139 static int nbd_genl_status(struct sk_buff *skb, struct genl_info *info); 141 140 static void nbd_dead_link_work(struct work_struct *work); 141 + static void nbd_disconnect_and_put(struct nbd_device *nbd); 142 142 143 143 static inline struct device *nbd_to_dev(struct nbd_device *nbd) 144 144 { ··· 1307 1305 static void nbd_release(struct gendisk *disk, fmode_t mode) 1308 1306 { 1309 1307 struct nbd_device *nbd = disk->private_data; 1308 + struct block_device *bdev = bdget_disk(disk, 0); 1309 + 1310 + if (test_bit(NBD_DISCONNECT_ON_CLOSE, &nbd->config->runtime_flags) && 1311 + bdev->bd_openers == 0) 1312 + nbd_disconnect_and_put(nbd); 1313 + 1310 1314 nbd_config_put(nbd); 1311 1315 nbd_put(nbd); 1312 1316 } ··· 1713 1705 &config->runtime_flags); 1714 1706 put_dev = true; 1715 1707 } 1708 + if (flags & NBD_CFLAG_DISCONNECT_ON_CLOSE) { 1709 + set_bit(NBD_DISCONNECT_ON_CLOSE, 1710 + &config->runtime_flags); 1711 + } 1716 1712 } 1717 1713 1718 1714 if (info->attrs[NBD_ATTR_SOCKETS]) { ··· 1761 1749 return ret; 1762 1750 } 1763 1751 1752 + static void nbd_disconnect_and_put(struct nbd_device *nbd) 1753 + { 1754 + mutex_lock(&nbd->config_lock); 1755 + nbd_disconnect(nbd); 1756 + nbd_clear_sock(nbd); 1757 + mutex_unlock(&nbd->config_lock); 1758 + if (test_and_clear_bit(NBD_HAS_CONFIG_REF, 1759 + &nbd->config->runtime_flags)) 1760 + nbd_config_put(nbd); 1761 + } 1762 + 1764 1763 static int nbd_genl_disconnect(struct sk_buff *skb, struct genl_info *info) 1765 1764 { 1766 1765 struct nbd_device *nbd; ··· 1804 1781 nbd_put(nbd); 1805 1782 return 0; 1806 1783 } 1807 - mutex_lock(&nbd->config_lock); 1808 - nbd_disconnect(nbd); 1809 - nbd_clear_sock(nbd); 1810 - mutex_unlock(&nbd->config_lock); 1811 - if (test_and_clear_bit(NBD_HAS_CONFIG_REF, 1812 - &nbd->config->runtime_flags)) 1813 - nbd_config_put(nbd); 1784 + nbd_disconnect_and_put(nbd); 1814 1785 nbd_config_put(nbd); 1815 1786 nbd_put(nbd); 1816 1787 return 0; ··· 1815 1798 struct nbd_device *nbd = NULL; 1816 1799 struct nbd_config *config; 1817 1800 int index; 1818 - int ret = -EINVAL; 1801 + int ret = 0; 1819 1802 bool put_dev = false; 1820 1803 1821 1804 if (!netlink_capable(skb, CAP_SYS_ADMIN)) ··· 1855 1838 !nbd->task_recv) { 1856 1839 dev_err(nbd_to_dev(nbd), 1857 1840 "not configured, cannot reconfigure\n"); 1841 + ret = -EINVAL; 1858 1842 goto out; 1859 1843 } 1860 1844 ··· 1879 1861 if (test_and_clear_bit(NBD_DESTROY_ON_DISCONNECT, 1880 1862 &config->runtime_flags)) 1881 1863 refcount_inc(&nbd->refs); 1864 + } 1865 + 1866 + if (flags & NBD_CFLAG_DISCONNECT_ON_CLOSE) { 1867 + set_bit(NBD_DISCONNECT_ON_CLOSE, 1868 + &config->runtime_flags); 1869 + } else { 1870 + clear_bit(NBD_DISCONNECT_ON_CLOSE, 1871 + &config->runtime_flags); 1882 1872 } 1883 1873 } 1884 1874
+3
include/uapi/linux/nbd.h
··· 53 53 /* These are client behavior specific flags. */ 54 54 #define NBD_CFLAG_DESTROY_ON_DISCONNECT (1 << 0) /* delete the nbd device on 55 55 disconnect. */ 56 + #define NBD_CFLAG_DISCONNECT_ON_CLOSE (1 << 1) /* disconnect the nbd device on 57 + * close by last opener. 58 + */ 56 59 57 60 /* userspace doesn't need the nbd_device structure */ 58 61