nbd: add a flag to destroy an nbd device on disconnect
authorJosef Bacik <josef@toxicpanda.com>
Thu, 6 Apr 2017 21:02:07 +0000 (17:02 -0400)
committerJens Axboe <axboe@fb.com>
Mon, 17 Apr 2017 15:58:42 +0000 (09:58 -0600)
For ease of management it would be nice for users to specify that the
device node for a nbd device is destroyed once it is disconnected and
there are no more users.  Add a client flag and enable this operation to
happen.

Signed-off-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
drivers/block/nbd.c
include/uapi/linux/nbd.h

index 4237e7286e99c9bbb1d814f3ae9e952ebf1a30f5..b78f23ce2395e66521624d06741d8e647156d8eb 100644 (file)
@@ -74,6 +74,7 @@ struct link_dead_args {
 #define NBD_HAS_PID_FILE               3
 #define NBD_HAS_CONFIG_REF             4
 #define NBD_BOUND                      5
+#define NBD_DESTROY_ON_DISCONNECT      6
 
 struct nbd_config {
        u32 flags;
@@ -174,6 +175,7 @@ static void nbd_dev_remove(struct nbd_device *nbd)
                del_gendisk(disk);
                blk_cleanup_queue(disk->queue);
                blk_mq_free_tag_set(&nbd->tag_set);
+               disk->private_data = NULL;
                put_disk(disk);
        }
        kfree(nbd);
@@ -1028,6 +1030,7 @@ static void nbd_config_put(struct nbd_device *nbd)
                        kfree(config->socks);
                }
                nbd_reset(nbd);
+
                mutex_unlock(&nbd->config_lock);
                nbd_put(nbd);
                module_put(THIS_MODULE);
@@ -1539,6 +1542,7 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info)
        struct nbd_config *config;
        int index = -1;
        int ret;
+       bool put_dev = false;
 
        if (!netlink_capable(skb, CAP_SYS_ADMIN))
                return -EPERM;
@@ -1633,6 +1637,15 @@ again:
        if (info->attrs[NBD_ATTR_SERVER_FLAGS])
                config->flags =
                        nla_get_u64(info->attrs[NBD_ATTR_SERVER_FLAGS]);
+       if (info->attrs[NBD_ATTR_CLIENT_FLAGS]) {
+               u64 flags = nla_get_u64(info->attrs[NBD_ATTR_CLIENT_FLAGS]);
+               if (flags & NBD_CFLAG_DESTROY_ON_DISCONNECT) {
+                       set_bit(NBD_DESTROY_ON_DISCONNECT,
+                               &config->runtime_flags);
+                       put_dev = true;
+               }
+       }
+
        if (info->attrs[NBD_ATTR_SOCKETS]) {
                struct nlattr *attr;
                int rem, fd;
@@ -1670,6 +1683,8 @@ out:
                nbd_connect_reply(info, nbd->index);
        }
        nbd_config_put(nbd);
+       if (put_dev)
+               nbd_put(nbd);
        return ret;
 }
 
@@ -1722,6 +1737,7 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
        struct nbd_config *config;
        int index;
        int ret = -EINVAL;
+       bool put_dev = false;
 
        if (!netlink_capable(skb, CAP_SYS_ADMIN))
                return -EPERM;
@@ -1773,6 +1789,18 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
                        nla_get_u64(info->attrs[NBD_ATTR_DEAD_CONN_TIMEOUT]);
                config->dead_conn_timeout *= HZ;
        }
+       if (info->attrs[NBD_ATTR_CLIENT_FLAGS]) {
+               u64 flags = nla_get_u64(info->attrs[NBD_ATTR_CLIENT_FLAGS]);
+               if (flags & NBD_CFLAG_DESTROY_ON_DISCONNECT) {
+                       if (!test_and_set_bit(NBD_DESTROY_ON_DISCONNECT,
+                                             &config->runtime_flags))
+                               put_dev = true;
+               } else {
+                       if (test_and_clear_bit(NBD_DESTROY_ON_DISCONNECT,
+                                              &config->runtime_flags))
+                               refcount_inc(&nbd->refs);
+               }
+       }
 
        if (info->attrs[NBD_ATTR_SOCKETS]) {
                struct nlattr *attr;
@@ -1810,6 +1838,8 @@ out:
        mutex_unlock(&nbd->config_lock);
        nbd_config_put(nbd);
        nbd_put(nbd);
+       if (put_dev)
+               nbd_put(nbd);
        return ret;
 }
 
index c91c642ea9003ed3ec5ba1be70b9899af3847948..155e33f819134a3aecdccf3c139974ef0c54c68c 100644 (file)
@@ -37,7 +37,7 @@ enum {
        NBD_CMD_TRIM = 4
 };
 
-/* values for flags field */
+/* values for flags field, these are server interaction specific. */
 #define NBD_FLAG_HAS_FLAGS     (1 << 0) /* nbd-server supports flags */
 #define NBD_FLAG_READ_ONLY     (1 << 1) /* device is read-only */
 #define NBD_FLAG_SEND_FLUSH    (1 << 2) /* can flush writeback cache */
@@ -45,6 +45,10 @@ enum {
 #define NBD_FLAG_SEND_TRIM     (1 << 5) /* send trim/discard */
 #define NBD_FLAG_CAN_MULTI_CONN        (1 << 8)        /* Server supports multiple connections per export. */
 
+/* These are client behavior specific flags. */
+#define NBD_CFLAG_DESTROY_ON_DISCONNECT        (1 << 0) /* delete the nbd device on
+                                                   disconnect. */
+
 /* userspace doesn't need the nbd_device structure */
 
 /* These are sent over the network in the request/reply magic fields */