]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/md/dm-ioctl.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / md / dm-ioctl.c
index 4b54618b4159368eed4e3febee680b2ff94724df..6d12775a1061059e483fdbeab3bf7b6ccbe53011 100644 (file)
@@ -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.
@@ -729,7 +779,7 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
        hc = __find_device_hash_cell(param);
 
        if (!hc) {
-               DMWARN("device doesn't appear to be in the dev hash table.");
+               DMDEBUG_LIMIT("device doesn't appear to be in the dev hash table.");
                up_write(&_hash_lock);
                return -ENXIO;
        }
@@ -741,7 +791,7 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
         */
        r = dm_lock_for_deletion(md);
        if (r) {
-               DMWARN("unable to remove open device %s", hc->name);
+               DMDEBUG_LIMIT("unable to remove open device %s", hc->name);
                up_write(&_hash_lock);
                dm_put(md);
                return r;
@@ -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);
 
@@ -885,7 +938,7 @@ static int do_resume(struct dm_ioctl *param)
 
        hc = __find_device_hash_cell(param);
        if (!hc) {
-               DMWARN("device doesn't appear to be in the dev hash table.");
+               DMDEBUG_LIMIT("device doesn't appear to be in the dev hash table.");
                up_write(&_hash_lock);
                return -ENXIO;
        }
@@ -1212,7 +1265,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
 
        hc = __find_device_hash_cell(param);
        if (!hc) {
-               DMWARN("device doesn't appear to be in the dev hash table.");
+               DMDEBUG_LIMIT("device doesn't appear to be in the dev hash table.");
                up_write(&_hash_lock);
                return -ENXIO;
        }