nvmet: model_number must be immutable once set
[linux-2.6-microblaze.git] / drivers / nvme / target / configfs.c
index 635a7cb..e5dbd19 100644 (file)
@@ -1118,16 +1118,12 @@ static ssize_t nvmet_subsys_attr_model_show(struct config_item *item,
                                            char *page)
 {
        struct nvmet_subsys *subsys = to_subsys(item);
-       struct nvmet_subsys_model *subsys_model;
-       char *model = NVMET_DEFAULT_CTRL_MODEL;
        int ret;
 
-       rcu_read_lock();
-       subsys_model = rcu_dereference(subsys->model);
-       if (subsys_model)
-               model = subsys_model->number;
-       ret = snprintf(page, PAGE_SIZE, "%s\n", model);
-       rcu_read_unlock();
+       mutex_lock(&subsys->lock);
+       ret = snprintf(page, PAGE_SIZE, "%s\n", subsys->model_number ?
+                       subsys->model_number : NVMET_DEFAULT_CTRL_MODEL);
+       mutex_unlock(&subsys->lock);
 
        return ret;
 }
@@ -1138,14 +1134,17 @@ static bool nvmet_is_ascii(const char c)
        return c >= 0x20 && c <= 0x7e;
 }
 
-static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
-                                            const char *page, size_t count)
+static ssize_t nvmet_subsys_attr_model_store_locked(struct nvmet_subsys *subsys,
+               const char *page, size_t count)
 {
-       struct nvmet_subsys *subsys = to_subsys(item);
-       struct nvmet_subsys_model *new_model;
-       char *new_model_number;
        int pos = 0, len;
 
+       if (subsys->model_number) {
+               pr_err("Can't set model number. %s is already assigned\n",
+                      subsys->model_number);
+               return -EINVAL;
+       }
+
        len = strcspn(page, "\n");
        if (!len)
                return -EINVAL;
@@ -1155,28 +1154,25 @@ static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
                        return -EINVAL;
        }
 
-       new_model_number = kmemdup_nul(page, len, GFP_KERNEL);
-       if (!new_model_number)
+       subsys->model_number = kmemdup_nul(page, len, GFP_KERNEL);
+       if (!subsys->model_number)
                return -ENOMEM;
+       return count;
+}
 
-       new_model = kzalloc(sizeof(*new_model) + len + 1, GFP_KERNEL);
-       if (!new_model) {
-               kfree(new_model_number);
-               return -ENOMEM;
-       }
-       memcpy(new_model->number, new_model_number, len);
+static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
+                                            const char *page, size_t count)
+{
+       struct nvmet_subsys *subsys = to_subsys(item);
+       ssize_t ret;
 
        down_write(&nvmet_config_sem);
        mutex_lock(&subsys->lock);
-       new_model = rcu_replace_pointer(subsys->model, new_model,
-                                       mutex_is_locked(&subsys->lock));
+       ret = nvmet_subsys_attr_model_store_locked(subsys, page, count);
        mutex_unlock(&subsys->lock);
        up_write(&nvmet_config_sem);
 
-       kfree_rcu(new_model, rcuhead);
-       kfree(new_model_number);
-
-       return count;
+       return ret;
 }
 CONFIGFS_ATTR(nvmet_subsys_, attr_model);