|
@@ -295,19 +295,55 @@ retry:
|
|
|
DMWARN("remove_all left %d open device(s)", dev_skipped);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Set the uuid of a hash_cell that isn't already set.
|
|
|
+ */
|
|
|
+static void __set_cell_uuid(struct hash_cell *hc, char *new_uuid)
|
|
|
+{
|
|
|
+ mutex_lock(&dm_hash_cells_mutex);
|
|
|
+ hc->uuid = new_uuid;
|
|
|
+ mutex_unlock(&dm_hash_cells_mutex);
|
|
|
+
|
|
|
+ list_add(&hc->uuid_list, _uuid_buckets + hash_str(new_uuid));
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Changes the name of a hash_cell and returns the old name for
|
|
|
+ * the caller to free.
|
|
|
+ */
|
|
|
+static char *__change_cell_name(struct hash_cell *hc, char *new_name)
|
|
|
+{
|
|
|
+ char *old_name;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Rename and move the name cell.
|
|
|
+ */
|
|
|
+ list_del(&hc->name_list);
|
|
|
+ old_name = hc->name;
|
|
|
+
|
|
|
+ mutex_lock(&dm_hash_cells_mutex);
|
|
|
+ hc->name = new_name;
|
|
|
+ mutex_unlock(&dm_hash_cells_mutex);
|
|
|
+
|
|
|
+ list_add(&hc->name_list, _name_buckets + hash_str(new_name));
|
|
|
+
|
|
|
+ return old_name;
|
|
|
+}
|
|
|
+
|
|
|
static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
|
|
|
const char *new)
|
|
|
{
|
|
|
- char *new_name, *old_name;
|
|
|
+ char *new_data, *old_name = NULL;
|
|
|
struct hash_cell *hc;
|
|
|
struct dm_table *table;
|
|
|
struct mapped_device *md;
|
|
|
+ unsigned change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0;
|
|
|
|
|
|
/*
|
|
|
* duplicate new.
|
|
|
*/
|
|
|
- new_name = kstrdup(new, GFP_KERNEL);
|
|
|
- if (!new_name)
|
|
|
+ new_data = kstrdup(new, GFP_KERNEL);
|
|
|
+ if (!new_data)
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
down_write(&_hash_lock);
|
|
@@ -315,13 +351,19 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
|
|
|
/*
|
|
|
* Is new free ?
|
|
|
*/
|
|
|
- hc = __get_name_cell(new);
|
|
|
+ if (change_uuid)
|
|
|
+ hc = __get_uuid_cell(new);
|
|
|
+ else
|
|
|
+ hc = __get_name_cell(new);
|
|
|
+
|
|
|
if (hc) {
|
|
|
- DMWARN("asked to rename to an already-existing name %s -> %s",
|
|
|
+ DMWARN("Unable to change %s on mapped device %s to one that "
|
|
|
+ "already exists: %s",
|
|
|
+ change_uuid ? "uuid" : "name",
|
|
|
param->name, new);
|
|
|
dm_put(hc->md);
|
|
|
up_write(&_hash_lock);
|
|
|
- kfree(new_name);
|
|
|
+ kfree(new_data);
|
|
|
return ERR_PTR(-EBUSY);
|
|
|
}
|
|
|
|
|
@@ -330,22 +372,30 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
|
|
|
*/
|
|
|
hc = __get_name_cell(param->name);
|
|
|
if (!hc) {
|
|
|
- DMWARN("asked to rename a non-existent device %s -> %s",
|
|
|
- param->name, new);
|
|
|
+ DMWARN("Unable to rename non-existent device, %s to %s%s",
|
|
|
+ param->name, change_uuid ? "uuid " : "", new);
|
|
|
up_write(&_hash_lock);
|
|
|
- kfree(new_name);
|
|
|
+ kfree(new_data);
|
|
|
return ERR_PTR(-ENXIO);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * rename and move the name cell.
|
|
|
+ * Does this device already have a uuid?
|
|
|
*/
|
|
|
- list_del(&hc->name_list);
|
|
|
- old_name = hc->name;
|
|
|
- mutex_lock(&dm_hash_cells_mutex);
|
|
|
- hc->name = new_name;
|
|
|
- mutex_unlock(&dm_hash_cells_mutex);
|
|
|
- list_add(&hc->name_list, _name_buckets + hash_str(new_name));
|
|
|
+ if (change_uuid && hc->uuid) {
|
|
|
+ DMWARN("Unable to change uuid of mapped device %s to %s "
|
|
|
+ "because uuid is already set to %s",
|
|
|
+ param->name, new, hc->uuid);
|
|
|
+ dm_put(hc->md);
|
|
|
+ up_write(&_hash_lock);
|
|
|
+ kfree(new_data);
|
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (change_uuid)
|
|
|
+ __set_cell_uuid(hc, new_data);
|
|
|
+ else
|
|
|
+ old_name = __change_cell_name(hc, new_data);
|
|
|
|
|
|
/*
|
|
|
* Wake up any dm event waiters.
|
|
@@ -774,21 +824,24 @@ static int invalid_str(char *str, void *end)
|
|
|
static int dev_rename(struct dm_ioctl *param, size_t param_size)
|
|
|
{
|
|
|
int r;
|
|
|
- char *new_name = (char *) param + param->data_start;
|
|
|
+ char *new_data = (char *) param + param->data_start;
|
|
|
struct mapped_device *md;
|
|
|
+ unsigned change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0;
|
|
|
|
|
|
- if (new_name < param->data ||
|
|
|
- invalid_str(new_name, (void *) param + param_size) ||
|
|
|
- strlen(new_name) > DM_NAME_LEN - 1) {
|
|
|
- DMWARN("Invalid new logical volume name supplied.");
|
|
|
+ if (new_data < param->data ||
|
|
|
+ invalid_str(new_data, (void *) param + param_size) ||
|
|
|
+ strlen(new_data) > (change_uuid ? DM_UUID_LEN - 1 : DM_NAME_LEN - 1)) {
|
|
|
+ DMWARN("Invalid new mapped device name or uuid string supplied.");
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- r = check_name(new_name);
|
|
|
- if (r)
|
|
|
- return r;
|
|
|
+ if (!change_uuid) {
|
|
|
+ r = check_name(new_data);
|
|
|
+ if (r)
|
|
|
+ return r;
|
|
|
+ }
|
|
|
|
|
|
- md = dm_hash_rename(param, new_name);
|
|
|
+ md = dm_hash_rename(param, new_data);
|
|
|
if (IS_ERR(md))
|
|
|
return PTR_ERR(md);
|
|
|
|