Merge tag 'arm-drivers-5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / drivers / block / nbd.c
index 614d82e..b7d6637 100644 (file)
@@ -79,6 +79,7 @@ struct link_dead_args {
 #define NBD_RT_HAS_CONFIG_REF          4
 #define NBD_RT_BOUND                   5
 #define NBD_RT_DISCONNECT_ON_CLOSE     6
+#define NBD_RT_HAS_BACKEND_FILE                7
 
 #define NBD_DESTROY_ON_DISCONNECT      0
 #define NBD_DISCONNECT_REQUESTED       1
@@ -119,6 +120,8 @@ struct nbd_device {
 
        struct completion *destroy_complete;
        unsigned long flags;
+
+       char *backend;
 };
 
 #define NBD_CMD_REQUEUED       1
@@ -216,6 +219,20 @@ static const struct device_attribute pid_attr = {
        .show = pid_show,
 };
 
+static ssize_t backend_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct gendisk *disk = dev_to_disk(dev);
+       struct nbd_device *nbd = (struct nbd_device *)disk->private_data;
+
+       return sprintf(buf, "%s\n", nbd->backend ?: "");
+}
+
+static const struct device_attribute backend_attr = {
+       .attr = { .name = "backend", .mode = 0444},
+       .show = backend_show,
+};
+
 static void nbd_dev_remove(struct nbd_device *nbd)
 {
        struct gendisk *disk = nbd->disk;
@@ -1211,6 +1228,12 @@ static void nbd_config_put(struct nbd_device *nbd)
                                       &config->runtime_flags))
                        device_remove_file(disk_to_dev(nbd->disk), &pid_attr);
                nbd->task_recv = NULL;
+               if (test_and_clear_bit(NBD_RT_HAS_BACKEND_FILE,
+                                      &config->runtime_flags)) {
+                       device_remove_file(disk_to_dev(nbd->disk), &backend_attr);
+                       kfree(nbd->backend);
+                       nbd->backend = NULL;
+               }
                nbd_clear_sock(nbd);
                if (config->num_connections) {
                        int i;
@@ -1270,7 +1293,7 @@ static int nbd_start_device(struct nbd_device *nbd)
 
        error = device_create_file(disk_to_dev(nbd->disk), &pid_attr);
        if (error) {
-               dev_err(disk_to_dev(nbd->disk), "device_create_file failed!\n");
+               dev_err(disk_to_dev(nbd->disk), "device_create_file failed for pid!\n");
                return error;
        }
        set_bit(NBD_RT_HAS_PID_FILE, &config->runtime_flags);
@@ -1657,6 +1680,7 @@ static int nbd_dev_add(int index)
                BLK_MQ_F_BLOCKING;
        nbd->tag_set.driver_data = nbd;
        nbd->destroy_complete = NULL;
+       nbd->backend = NULL;
 
        err = blk_mq_alloc_tag_set(&nbd->tag_set);
        if (err)
@@ -1743,6 +1767,7 @@ static const struct nla_policy nbd_attr_policy[NBD_ATTR_MAX + 1] = {
        [NBD_ATTR_SOCKETS]              =       { .type = NLA_NESTED},
        [NBD_ATTR_DEAD_CONN_TIMEOUT]    =       { .type = NLA_U64 },
        [NBD_ATTR_DEVICE_LIST]          =       { .type = NLA_NESTED},
+       [NBD_ATTR_BACKEND_IDENTIFIER]   =       { .type = NLA_STRING},
 };
 
 static const struct nla_policy nbd_sock_policy[NBD_SOCK_MAX + 1] = {
@@ -1945,6 +1970,23 @@ again:
                }
        }
        ret = nbd_start_device(nbd);
+       if (ret)
+               goto out;
+       if (info->attrs[NBD_ATTR_BACKEND_IDENTIFIER]) {
+               nbd->backend = nla_strdup(info->attrs[NBD_ATTR_BACKEND_IDENTIFIER],
+                                         GFP_KERNEL);
+               if (!nbd->backend) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+       }
+       ret = device_create_file(disk_to_dev(nbd->disk), &backend_attr);
+       if (ret) {
+               dev_err(disk_to_dev(nbd->disk),
+                       "device_create_file failed for backend!\n");
+               goto out;
+       }
+       set_bit(NBD_RT_HAS_BACKEND_FILE, &config->runtime_flags);
 out:
        mutex_unlock(&nbd->config_lock);
        if (!ret) {
@@ -2037,6 +2079,22 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
                       index);
                return -EINVAL;
        }
+       if (nbd->backend) {
+               if (info->attrs[NBD_ATTR_BACKEND_IDENTIFIER]) {
+                       if (nla_strcmp(info->attrs[NBD_ATTR_BACKEND_IDENTIFIER],
+                                      nbd->backend)) {
+                               mutex_unlock(&nbd_index_mutex);
+                               dev_err(nbd_to_dev(nbd),
+                                       "backend image doesn't match with %s\n",
+                                       nbd->backend);
+                               return -EINVAL;
+                       }
+               } else {
+                       mutex_unlock(&nbd_index_mutex);
+                       dev_err(nbd_to_dev(nbd), "must specify backend\n");
+                       return -EINVAL;
+               }
+       }
        if (!refcount_inc_not_zero(&nbd->refs)) {
                mutex_unlock(&nbd_index_mutex);
                printk(KERN_ERR "nbd: device at index %d is going down\n",