aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosef Bacik <josef@toxicpanda.com>2017-04-06 17:02:05 -0400
committerJens Axboe <axboe@fb.com>2017-04-17 11:58:42 -0400
commit47d902b90a32a42a3d33aef3a02170fc6f70aa23 (patch)
tree194a8be4a065ee133d1ea3f035eb11ffe2ba0af7
parent560bc4b39952ed77cdb0000992e9415b0ee89edb (diff)
nbd: add a status netlink command
Allow users to query the status of existing nbd devices. Right now this only returns whether or not the device is connected, but could be extended in the future to include more information. Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r--drivers/block/nbd.c108
-rw-r--r--include/uapi/linux/nbd-netlink.h25
2 files changed, 133 insertions, 0 deletions
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index c5f866bcfea6..cb45d799bc5c 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -45,6 +45,7 @@
45 45
46static DEFINE_IDR(nbd_index_idr); 46static DEFINE_IDR(nbd_index_idr);
47static DEFINE_MUTEX(nbd_index_mutex); 47static DEFINE_MUTEX(nbd_index_mutex);
48static int nbd_total_devices = 0;
48 49
49struct nbd_sock { 50struct nbd_sock {
50 struct socket *sock; 51 struct socket *sock;
@@ -130,6 +131,7 @@ static int nbd_dev_dbg_init(struct nbd_device *nbd);
130static void nbd_dev_dbg_close(struct nbd_device *nbd); 131static void nbd_dev_dbg_close(struct nbd_device *nbd);
131static void nbd_config_put(struct nbd_device *nbd); 132static void nbd_config_put(struct nbd_device *nbd);
132static void nbd_connect_reply(struct genl_info *info, int index); 133static void nbd_connect_reply(struct genl_info *info, int index);
134static int nbd_genl_status(struct sk_buff *skb, struct genl_info *info);
133static void nbd_dead_link_work(struct work_struct *work); 135static void nbd_dead_link_work(struct work_struct *work);
134 136
135static inline struct device *nbd_to_dev(struct nbd_device *nbd) 137static inline struct device *nbd_to_dev(struct nbd_device *nbd)
@@ -1457,6 +1459,7 @@ static int nbd_dev_add(int index)
1457 sprintf(disk->disk_name, "nbd%d", index); 1459 sprintf(disk->disk_name, "nbd%d", index);
1458 nbd_reset(nbd); 1460 nbd_reset(nbd);
1459 add_disk(disk); 1461 add_disk(disk);
1462 nbd_total_devices++;
1460 return index; 1463 return index;
1461 1464
1462out_free_tags: 1465out_free_tags:
@@ -1493,12 +1496,22 @@ static struct nla_policy nbd_attr_policy[NBD_ATTR_MAX + 1] = {
1493 [NBD_ATTR_CLIENT_FLAGS] = { .type = NLA_U64 }, 1496 [NBD_ATTR_CLIENT_FLAGS] = { .type = NLA_U64 },
1494 [NBD_ATTR_SOCKETS] = { .type = NLA_NESTED}, 1497 [NBD_ATTR_SOCKETS] = { .type = NLA_NESTED},
1495 [NBD_ATTR_DEAD_CONN_TIMEOUT] = { .type = NLA_U64 }, 1498 [NBD_ATTR_DEAD_CONN_TIMEOUT] = { .type = NLA_U64 },
1499 [NBD_ATTR_DEVICE_LIST] = { .type = NLA_NESTED},
1496}; 1500};
1497 1501
1498static struct nla_policy nbd_sock_policy[NBD_SOCK_MAX + 1] = { 1502static struct nla_policy nbd_sock_policy[NBD_SOCK_MAX + 1] = {
1499 [NBD_SOCK_FD] = { .type = NLA_U32 }, 1503 [NBD_SOCK_FD] = { .type = NLA_U32 },
1500}; 1504};
1501 1505
1506/* We don't use this right now since we don't parse the incoming list, but we
1507 * still want it here so userspace knows what to expect.
1508 */
1509static struct nla_policy __attribute__((unused))
1510nbd_device_policy[NBD_DEVICE_ATTR_MAX + 1] = {
1511 [NBD_DEVICE_INDEX] = { .type = NLA_U32 },
1512 [NBD_DEVICE_CONNECTED] = { .type = NLA_U8 },
1513};
1514
1502static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info) 1515static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info)
1503{ 1516{
1504 struct nbd_device *nbd = NULL; 1517 struct nbd_device *nbd = NULL;
@@ -1764,6 +1777,11 @@ static const struct genl_ops nbd_connect_genl_ops[] = {
1764 .policy = nbd_attr_policy, 1777 .policy = nbd_attr_policy,
1765 .doit = nbd_genl_reconfigure, 1778 .doit = nbd_genl_reconfigure,
1766 }, 1779 },
1780 {
1781 .cmd = NBD_CMD_STATUS,
1782 .policy = nbd_attr_policy,
1783 .doit = nbd_genl_status,
1784 },
1767}; 1785};
1768 1786
1769static const struct genl_multicast_group nbd_mcast_grps[] = { 1787static const struct genl_multicast_group nbd_mcast_grps[] = {
@@ -1782,6 +1800,96 @@ static struct genl_family nbd_genl_family __ro_after_init = {
1782 .n_mcgrps = ARRAY_SIZE(nbd_mcast_grps), 1800 .n_mcgrps = ARRAY_SIZE(nbd_mcast_grps),
1783}; 1801};
1784 1802
1803static int populate_nbd_status(struct nbd_device *nbd, struct sk_buff *reply)
1804{
1805 struct nlattr *dev_opt;
1806 u8 connected = 0;
1807 int ret;
1808
1809 /* This is a little racey, but for status it's ok. The
1810 * reason we don't take a ref here is because we can't
1811 * take a ref in the index == -1 case as we would need
1812 * to put under the nbd_index_mutex, which could
1813 * deadlock if we are configured to remove ourselves
1814 * once we're disconnected.
1815 */
1816 if (refcount_read(&nbd->config_refs))
1817 connected = 1;
1818 dev_opt = nla_nest_start(reply, NBD_DEVICE_ITEM);
1819 if (!dev_opt)
1820 return -EMSGSIZE;
1821 ret = nla_put_u32(reply, NBD_DEVICE_INDEX, nbd->index);
1822 if (ret)
1823 return -EMSGSIZE;
1824 ret = nla_put_u8(reply, NBD_DEVICE_CONNECTED,
1825 connected);
1826 if (ret)
1827 return -EMSGSIZE;
1828 nla_nest_end(reply, dev_opt);
1829 return 0;
1830}
1831
1832static int status_cb(int id, void *ptr, void *data)
1833{
1834 struct nbd_device *nbd = ptr;
1835 return populate_nbd_status(nbd, (struct sk_buff *)data);
1836}
1837
1838static int nbd_genl_status(struct sk_buff *skb, struct genl_info *info)
1839{
1840 struct nlattr *dev_list;
1841 struct sk_buff *reply;
1842 void *reply_head;
1843 size_t msg_size;
1844 int index = -1;
1845 int ret = -ENOMEM;
1846
1847 if (info->attrs[NBD_ATTR_INDEX])
1848 index = nla_get_u32(info->attrs[NBD_ATTR_INDEX]);
1849
1850 mutex_lock(&nbd_index_mutex);
1851
1852 msg_size = nla_total_size(nla_attr_size(sizeof(u32)) +
1853 nla_attr_size(sizeof(u8)));
1854 msg_size *= (index == -1) ? nbd_total_devices : 1;
1855
1856 reply = genlmsg_new(msg_size, GFP_KERNEL);
1857 if (!reply)
1858 goto out;
1859 reply_head = genlmsg_put_reply(reply, info, &nbd_genl_family, 0,
1860 NBD_CMD_STATUS);
1861 if (!reply_head) {
1862 nlmsg_free(reply);
1863 goto out;
1864 }
1865
1866 dev_list = nla_nest_start(reply, NBD_ATTR_DEVICE_LIST);
1867 if (index == -1) {
1868 ret = idr_for_each(&nbd_index_idr, &status_cb, reply);
1869 if (ret) {
1870 nlmsg_free(reply);
1871 goto out;
1872 }
1873 } else {
1874 struct nbd_device *nbd;
1875 nbd = idr_find(&nbd_index_idr, index);
1876 if (nbd) {
1877 ret = populate_nbd_status(nbd, reply);
1878 if (ret) {
1879 nlmsg_free(reply);
1880 goto out;
1881 }
1882 }
1883 }
1884 nla_nest_end(reply, dev_list);
1885 genlmsg_end(reply, reply_head);
1886 genlmsg_reply(reply, info);
1887 ret = 0;
1888out:
1889 mutex_unlock(&nbd_index_mutex);
1890 return ret;
1891}
1892
1785static void nbd_connect_reply(struct genl_info *info, int index) 1893static void nbd_connect_reply(struct genl_info *info, int index)
1786{ 1894{
1787 struct sk_buff *skb; 1895 struct sk_buff *skb;
diff --git a/include/uapi/linux/nbd-netlink.h b/include/uapi/linux/nbd-netlink.h
index c2209c75626c..6f7ca3d63a65 100644
--- a/include/uapi/linux/nbd-netlink.h
+++ b/include/uapi/linux/nbd-netlink.h
@@ -33,11 +33,35 @@ enum {
33 NBD_ATTR_CLIENT_FLAGS, 33 NBD_ATTR_CLIENT_FLAGS,
34 NBD_ATTR_SOCKETS, 34 NBD_ATTR_SOCKETS,
35 NBD_ATTR_DEAD_CONN_TIMEOUT, 35 NBD_ATTR_DEAD_CONN_TIMEOUT,
36 NBD_ATTR_DEVICE_LIST,
36 __NBD_ATTR_MAX, 37 __NBD_ATTR_MAX,
37}; 38};
38#define NBD_ATTR_MAX (__NBD_ATTR_MAX - 1) 39#define NBD_ATTR_MAX (__NBD_ATTR_MAX - 1)
39 40
40/* 41/*
42 * This is the format for multiple devices with NBD_ATTR_DEVICE_LIST
43 *
44 * [NBD_ATTR_DEVICE_LIST]
45 * [NBD_DEVICE_ITEM]
46 * [NBD_DEVICE_INDEX]
47 * [NBD_DEVICE_CONNECTED]
48 */
49enum {
50 NBD_DEVICE_ITEM_UNSPEC,
51 NBD_DEVICE_ITEM,
52 __NBD_DEVICE_ITEM_MAX,
53};
54#define NBD_DEVICE_ITEM_MAX (__NBD_DEVICE_ITEM_MAX - 1)
55
56enum {
57 NBD_DEVICE_UNSPEC,
58 NBD_DEVICE_INDEX,
59 NBD_DEVICE_CONNECTED,
60 __NBD_DEVICE_MAX,
61};
62#define NBD_DEVICE_ATTR_MAX (__NBD_DEVICE_MAX - 1)
63
64/*
41 * This is the format for multiple sockets with NBD_ATTR_SOCKETS 65 * This is the format for multiple sockets with NBD_ATTR_SOCKETS
42 * 66 *
43 * [NBD_ATTR_SOCKETS] 67 * [NBD_ATTR_SOCKETS]
@@ -66,6 +90,7 @@ enum {
66 NBD_CMD_DISCONNECT, 90 NBD_CMD_DISCONNECT,
67 NBD_CMD_RECONFIGURE, 91 NBD_CMD_RECONFIGURE,
68 NBD_CMD_LINK_DEAD, 92 NBD_CMD_LINK_DEAD,
93 NBD_CMD_STATUS,
69 __NBD_CMD_MAX, 94 __NBD_CMD_MAX,
70}; 95};
71#define NBD_CMD_MAX (__NBD_CMD_MAX - 1) 96#define NBD_CMD_MAX (__NBD_CMD_MAX - 1)