diff options
-rw-r--r-- | drivers/md/dm-ioctl.c | 103 | ||||
-rw-r--r-- | include/linux/dm-ioctl.h | 12 |
2 files changed, 87 insertions, 28 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 4b54618b4159..f3481d922206 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c | |||
@@ -295,19 +295,55 @@ retry: | |||
295 | DMWARN("remove_all left %d open device(s)", dev_skipped); | 295 | DMWARN("remove_all left %d open device(s)", dev_skipped); |
296 | } | 296 | } |
297 | 297 | ||
298 | /* | ||
299 | * Set the uuid of a hash_cell that isn't already set. | ||
300 | */ | ||
301 | static void __set_cell_uuid(struct hash_cell *hc, char *new_uuid) | ||
302 | { | ||
303 | mutex_lock(&dm_hash_cells_mutex); | ||
304 | hc->uuid = new_uuid; | ||
305 | mutex_unlock(&dm_hash_cells_mutex); | ||
306 | |||
307 | list_add(&hc->uuid_list, _uuid_buckets + hash_str(new_uuid)); | ||
308 | } | ||
309 | |||
310 | /* | ||
311 | * Changes the name of a hash_cell and returns the old name for | ||
312 | * the caller to free. | ||
313 | */ | ||
314 | static char *__change_cell_name(struct hash_cell *hc, char *new_name) | ||
315 | { | ||
316 | char *old_name; | ||
317 | |||
318 | /* | ||
319 | * Rename and move the name cell. | ||
320 | */ | ||
321 | list_del(&hc->name_list); | ||
322 | old_name = hc->name; | ||
323 | |||
324 | mutex_lock(&dm_hash_cells_mutex); | ||
325 | hc->name = new_name; | ||
326 | mutex_unlock(&dm_hash_cells_mutex); | ||
327 | |||
328 | list_add(&hc->name_list, _name_buckets + hash_str(new_name)); | ||
329 | |||
330 | return old_name; | ||
331 | } | ||
332 | |||
298 | static struct mapped_device *dm_hash_rename(struct dm_ioctl *param, | 333 | static struct mapped_device *dm_hash_rename(struct dm_ioctl *param, |
299 | const char *new) | 334 | const char *new) |
300 | { | 335 | { |
301 | char *new_name, *old_name; | 336 | char *new_data, *old_name = NULL; |
302 | struct hash_cell *hc; | 337 | struct hash_cell *hc; |
303 | struct dm_table *table; | 338 | struct dm_table *table; |
304 | struct mapped_device *md; | 339 | struct mapped_device *md; |
340 | unsigned change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0; | ||
305 | 341 | ||
306 | /* | 342 | /* |
307 | * duplicate new. | 343 | * duplicate new. |
308 | */ | 344 | */ |
309 | new_name = kstrdup(new, GFP_KERNEL); | 345 | new_data = kstrdup(new, GFP_KERNEL); |
310 | if (!new_name) | 346 | if (!new_data) |
311 | return ERR_PTR(-ENOMEM); | 347 | return ERR_PTR(-ENOMEM); |
312 | 348 | ||
313 | down_write(&_hash_lock); | 349 | down_write(&_hash_lock); |
@@ -315,13 +351,19 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param, | |||
315 | /* | 351 | /* |
316 | * Is new free ? | 352 | * Is new free ? |
317 | */ | 353 | */ |
318 | hc = __get_name_cell(new); | 354 | if (change_uuid) |
355 | hc = __get_uuid_cell(new); | ||
356 | else | ||
357 | hc = __get_name_cell(new); | ||
358 | |||
319 | if (hc) { | 359 | if (hc) { |
320 | DMWARN("asked to rename to an already-existing name %s -> %s", | 360 | DMWARN("Unable to change %s on mapped device %s to one that " |
361 | "already exists: %s", | ||
362 | change_uuid ? "uuid" : "name", | ||
321 | param->name, new); | 363 | param->name, new); |
322 | dm_put(hc->md); | 364 | dm_put(hc->md); |
323 | up_write(&_hash_lock); | 365 | up_write(&_hash_lock); |
324 | kfree(new_name); | 366 | kfree(new_data); |
325 | return ERR_PTR(-EBUSY); | 367 | return ERR_PTR(-EBUSY); |
326 | } | 368 | } |
327 | 369 | ||
@@ -330,22 +372,30 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param, | |||
330 | */ | 372 | */ |
331 | hc = __get_name_cell(param->name); | 373 | hc = __get_name_cell(param->name); |
332 | if (!hc) { | 374 | if (!hc) { |
333 | DMWARN("asked to rename a non-existent device %s -> %s", | 375 | DMWARN("Unable to rename non-existent device, %s to %s%s", |
334 | param->name, new); | 376 | param->name, change_uuid ? "uuid " : "", new); |
335 | up_write(&_hash_lock); | 377 | up_write(&_hash_lock); |
336 | kfree(new_name); | 378 | kfree(new_data); |
337 | return ERR_PTR(-ENXIO); | 379 | return ERR_PTR(-ENXIO); |
338 | } | 380 | } |
339 | 381 | ||
340 | /* | 382 | /* |
341 | * rename and move the name cell. | 383 | * Does this device already have a uuid? |
342 | */ | 384 | */ |
343 | list_del(&hc->name_list); | 385 | if (change_uuid && hc->uuid) { |
344 | old_name = hc->name; | 386 | DMWARN("Unable to change uuid of mapped device %s to %s " |
345 | mutex_lock(&dm_hash_cells_mutex); | 387 | "because uuid is already set to %s", |
346 | hc->name = new_name; | 388 | param->name, new, hc->uuid); |
347 | mutex_unlock(&dm_hash_cells_mutex); | 389 | dm_put(hc->md); |
348 | list_add(&hc->name_list, _name_buckets + hash_str(new_name)); | 390 | up_write(&_hash_lock); |
391 | kfree(new_data); | ||
392 | return ERR_PTR(-EINVAL); | ||
393 | } | ||
394 | |||
395 | if (change_uuid) | ||
396 | __set_cell_uuid(hc, new_data); | ||
397 | else | ||
398 | old_name = __change_cell_name(hc, new_data); | ||
349 | 399 | ||
350 | /* | 400 | /* |
351 | * Wake up any dm event waiters. | 401 | * Wake up any dm event waiters. |
@@ -774,21 +824,24 @@ static int invalid_str(char *str, void *end) | |||
774 | static int dev_rename(struct dm_ioctl *param, size_t param_size) | 824 | static int dev_rename(struct dm_ioctl *param, size_t param_size) |
775 | { | 825 | { |
776 | int r; | 826 | int r; |
777 | char *new_name = (char *) param + param->data_start; | 827 | char *new_data = (char *) param + param->data_start; |
778 | struct mapped_device *md; | 828 | struct mapped_device *md; |
829 | unsigned change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0; | ||
779 | 830 | ||
780 | if (new_name < param->data || | 831 | if (new_data < param->data || |
781 | invalid_str(new_name, (void *) param + param_size) || | 832 | invalid_str(new_data, (void *) param + param_size) || |
782 | strlen(new_name) > DM_NAME_LEN - 1) { | 833 | strlen(new_data) > (change_uuid ? DM_UUID_LEN - 1 : DM_NAME_LEN - 1)) { |
783 | DMWARN("Invalid new logical volume name supplied."); | 834 | DMWARN("Invalid new mapped device name or uuid string supplied."); |
784 | return -EINVAL; | 835 | return -EINVAL; |
785 | } | 836 | } |
786 | 837 | ||
787 | r = check_name(new_name); | 838 | if (!change_uuid) { |
788 | if (r) | 839 | r = check_name(new_data); |
789 | return r; | 840 | if (r) |
841 | return r; | ||
842 | } | ||
790 | 843 | ||
791 | md = dm_hash_rename(param, new_name); | 844 | md = dm_hash_rename(param, new_data); |
792 | if (IS_ERR(md)) | 845 | if (IS_ERR(md)) |
793 | return PTR_ERR(md); | 846 | return PTR_ERR(md); |
794 | 847 | ||
diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h index 49eab360d5d4..e453e1174ae1 100644 --- a/include/linux/dm-ioctl.h +++ b/include/linux/dm-ioctl.h | |||
@@ -44,7 +44,7 @@ | |||
44 | * Remove a device, destroy any tables. | 44 | * Remove a device, destroy any tables. |
45 | * | 45 | * |
46 | * DM_DEV_RENAME: | 46 | * DM_DEV_RENAME: |
47 | * Rename a device. | 47 | * Rename a device or set its uuid if none was previously supplied. |
48 | * | 48 | * |
49 | * DM_SUSPEND: | 49 | * DM_SUSPEND: |
50 | * This performs both suspend and resume, depending which flag is | 50 | * This performs both suspend and resume, depending which flag is |
@@ -267,9 +267,9 @@ enum { | |||
267 | #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) | 267 | #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) |
268 | 268 | ||
269 | #define DM_VERSION_MAJOR 4 | 269 | #define DM_VERSION_MAJOR 4 |
270 | #define DM_VERSION_MINOR 18 | 270 | #define DM_VERSION_MINOR 19 |
271 | #define DM_VERSION_PATCHLEVEL 0 | 271 | #define DM_VERSION_PATCHLEVEL 0 |
272 | #define DM_VERSION_EXTRA "-ioctl (2010-06-29)" | 272 | #define DM_VERSION_EXTRA "-ioctl (2010-10-14)" |
273 | 273 | ||
274 | /* Status bits */ | 274 | /* Status bits */ |
275 | #define DM_READONLY_FLAG (1 << 0) /* In/Out */ | 275 | #define DM_READONLY_FLAG (1 << 0) /* In/Out */ |
@@ -322,4 +322,10 @@ enum { | |||
322 | */ | 322 | */ |
323 | #define DM_UEVENT_GENERATED_FLAG (1 << 13) /* Out */ | 323 | #define DM_UEVENT_GENERATED_FLAG (1 << 13) /* Out */ |
324 | 324 | ||
325 | /* | ||
326 | * If set, rename changes the uuid not the name. Only permitted | ||
327 | * if no uuid was previously supplied: an existing uuid cannot be changed. | ||
328 | */ | ||
329 | #define DM_UUID_FLAG (1 << 14) /* In */ | ||
330 | |||
325 | #endif /* _LINUX_DM_IOCTL_H */ | 331 | #endif /* _LINUX_DM_IOCTL_H */ |