aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosef Bacik <josef@toxicpanda.com>2017-04-06 17:02:01 -0400
committerJens Axboe <axboe@fb.com>2017-04-17 11:58:42 -0400
commitb7aa3d39385dc2d95899f9e379623fef446a2acd (patch)
treeff0ff044ec1668138af9082d24305de7149b3628
parente46c7287b1c27683a8e30ca825fb98e2b97f1099 (diff)
nbd: add a reconfigure netlink command
We want to be able to reconnect dead connections to existing block devices, so add a reconfigure netlink command. We will also allow users to change their timeout on the fly, but everything else will require a disconnect and reconnect. You won't be able to add more connections either, simply replace dead connections with new more lively connections. Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r--drivers/block/nbd.c141
-rw-r--r--include/uapi/linux/nbd-netlink.h1
2 files changed, 142 insertions, 0 deletions
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index efd2eba37c69..394ea891d909 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -785,6 +785,59 @@ static int nbd_add_socket(struct nbd_device *nbd, unsigned long arg,
785 return 0; 785 return 0;
786} 786}
787 787
788static int nbd_reconnect_socket(struct nbd_device *nbd, unsigned long arg)
789{
790 struct nbd_config *config = nbd->config;
791 struct socket *sock, *old;
792 struct recv_thread_args *args;
793 int i;
794 int err;
795
796 sock = sockfd_lookup(arg, &err);
797 if (!sock)
798 return err;
799
800 args = kzalloc(sizeof(*args), GFP_KERNEL);
801 if (!args) {
802 sockfd_put(sock);
803 return -ENOMEM;
804 }
805
806 for (i = 0; i < config->num_connections; i++) {
807 struct nbd_sock *nsock = config->socks[i];
808
809 if (!nsock->dead)
810 continue;
811
812 mutex_lock(&nsock->tx_lock);
813 if (!nsock->dead) {
814 mutex_unlock(&nsock->tx_lock);
815 continue;
816 }
817 sk_set_memalloc(sock->sk);
818 atomic_inc(&config->recv_threads);
819 refcount_inc(&nbd->config_refs);
820 old = nsock->sock;
821 nsock->fallback_index = -1;
822 nsock->sock = sock;
823 nsock->dead = false;
824 INIT_WORK(&args->work, recv_work);
825 args->index = i;
826 args->nbd = nbd;
827 mutex_unlock(&nsock->tx_lock);
828 sockfd_put(old);
829
830 /* We take the tx_mutex in an error path in the recv_work, so we
831 * need to queue_work outside of the tx_mutex.
832 */
833 queue_work(recv_workqueue, &args->work);
834 return 0;
835 }
836 sockfd_put(sock);
837 kfree(args);
838 return -ENOSPC;
839}
840
788/* Reset all properties of an NBD device */ 841/* Reset all properties of an NBD device */
789static void nbd_reset(struct nbd_device *nbd) 842static void nbd_reset(struct nbd_device *nbd)
790{ 843{
@@ -1528,6 +1581,89 @@ static int nbd_genl_disconnect(struct sk_buff *skb, struct genl_info *info)
1528 return 0; 1581 return 0;
1529} 1582}
1530 1583
1584static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
1585{
1586 struct nbd_device *nbd = NULL;
1587 struct nbd_config *config;
1588 int index;
1589 int ret = -EINVAL;
1590
1591 if (!netlink_capable(skb, CAP_SYS_ADMIN))
1592 return -EPERM;
1593
1594 if (!info->attrs[NBD_ATTR_INDEX]) {
1595 printk(KERN_ERR "nbd: must specify a device to reconfigure\n");
1596 return -EINVAL;
1597 }
1598 index = nla_get_u32(info->attrs[NBD_ATTR_INDEX]);
1599 mutex_lock(&nbd_index_mutex);
1600 nbd = idr_find(&nbd_index_idr, index);
1601 mutex_unlock(&nbd_index_mutex);
1602 if (!nbd) {
1603 printk(KERN_ERR "nbd: couldn't find a device at index %d\n",
1604 index);
1605 return -EINVAL;
1606 }
1607
1608 if (!refcount_inc_not_zero(&nbd->config_refs)) {
1609 dev_err(nbd_to_dev(nbd),
1610 "not configured, cannot reconfigure\n");
1611 return -EINVAL;
1612 }
1613
1614 mutex_lock(&nbd->config_lock);
1615 config = nbd->config;
1616 if (!test_bit(NBD_BOUND, &config->runtime_flags) ||
1617 !nbd->task_recv) {
1618 dev_err(nbd_to_dev(nbd),
1619 "not configured, cannot reconfigure\n");
1620 goto out;
1621 }
1622
1623 if (info->attrs[NBD_ATTR_TIMEOUT]) {
1624 u64 timeout = nla_get_u64(info->attrs[NBD_ATTR_TIMEOUT]);
1625 nbd->tag_set.timeout = timeout * HZ;
1626 blk_queue_rq_timeout(nbd->disk->queue, timeout * HZ);
1627 }
1628
1629 if (info->attrs[NBD_ATTR_SOCKETS]) {
1630 struct nlattr *attr;
1631 int rem, fd;
1632
1633 nla_for_each_nested(attr, info->attrs[NBD_ATTR_SOCKETS],
1634 rem) {
1635 struct nlattr *socks[NBD_SOCK_MAX+1];
1636
1637 if (nla_type(attr) != NBD_SOCK_ITEM) {
1638 printk(KERN_ERR "nbd: socks must be embedded in a SOCK_ITEM attr\n");
1639 ret = -EINVAL;
1640 goto out;
1641 }
1642 ret = nla_parse_nested(socks, NBD_SOCK_MAX, attr,
1643 nbd_sock_policy);
1644 if (ret != 0) {
1645 printk(KERN_ERR "nbd: error processing sock list\n");
1646 ret = -EINVAL;
1647 goto out;
1648 }
1649 if (!socks[NBD_SOCK_FD])
1650 continue;
1651 fd = (int)nla_get_u32(socks[NBD_SOCK_FD]);
1652 ret = nbd_reconnect_socket(nbd, fd);
1653 if (ret) {
1654 if (ret == -ENOSPC)
1655 ret = 0;
1656 goto out;
1657 }
1658 dev_info(nbd_to_dev(nbd), "reconnected socket\n");
1659 }
1660 }
1661out:
1662 mutex_unlock(&nbd->config_lock);
1663 nbd_config_put(nbd);
1664 return ret;
1665}
1666
1531static const struct genl_ops nbd_connect_genl_ops[] = { 1667static const struct genl_ops nbd_connect_genl_ops[] = {
1532 { 1668 {
1533 .cmd = NBD_CMD_CONNECT, 1669 .cmd = NBD_CMD_CONNECT,
@@ -1539,6 +1675,11 @@ static const struct genl_ops nbd_connect_genl_ops[] = {
1539 .policy = nbd_attr_policy, 1675 .policy = nbd_attr_policy,
1540 .doit = nbd_genl_disconnect, 1676 .doit = nbd_genl_disconnect,
1541 }, 1677 },
1678 {
1679 .cmd = NBD_CMD_RECONFIGURE,
1680 .policy = nbd_attr_policy,
1681 .doit = nbd_genl_reconfigure,
1682 },
1542}; 1683};
1543 1684
1544static struct genl_family nbd_genl_family __ro_after_init = { 1685static struct genl_family nbd_genl_family __ro_after_init = {
diff --git a/include/uapi/linux/nbd-netlink.h b/include/uapi/linux/nbd-netlink.h
index fd0f4e45f03e..f932f96a7c2f 100644
--- a/include/uapi/linux/nbd-netlink.h
+++ b/include/uapi/linux/nbd-netlink.h
@@ -62,6 +62,7 @@ enum {
62 NBD_CMD_UNSPEC, 62 NBD_CMD_UNSPEC,
63 NBD_CMD_CONNECT, 63 NBD_CMD_CONNECT,
64 NBD_CMD_DISCONNECT, 64 NBD_CMD_DISCONNECT,
65 NBD_CMD_RECONFIGURE,
65 __NBD_CMD_MAX, 66 __NBD_CMD_MAX,
66}; 67};
67#define NBD_CMD_MAX (__NBD_CMD_MAX - 1) 68#define NBD_CMD_MAX (__NBD_CMD_MAX - 1)