diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/md/dm-ioctl.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/md/dm-ioctl.c')
-rw-r--r-- | drivers/md/dm-ioctl.c | 158 |
1 files changed, 114 insertions, 44 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 3e39193e5036..4cacdad2270a 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. |
@@ -729,7 +779,7 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size) | |||
729 | hc = __find_device_hash_cell(param); | 779 | hc = __find_device_hash_cell(param); |
730 | 780 | ||
731 | if (!hc) { | 781 | if (!hc) { |
732 | DMWARN("device doesn't appear to be in the dev hash table."); | 782 | DMDEBUG_LIMIT("device doesn't appear to be in the dev hash table."); |
733 | up_write(&_hash_lock); | 783 | up_write(&_hash_lock); |
734 | return -ENXIO; | 784 | return -ENXIO; |
735 | } | 785 | } |
@@ -741,7 +791,7 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size) | |||
741 | */ | 791 | */ |
742 | r = dm_lock_for_deletion(md); | 792 | r = dm_lock_for_deletion(md); |
743 | if (r) { | 793 | if (r) { |
744 | DMWARN("unable to remove open device %s", hc->name); | 794 | DMDEBUG_LIMIT("unable to remove open device %s", hc->name); |
745 | up_write(&_hash_lock); | 795 | up_write(&_hash_lock); |
746 | dm_put(md); | 796 | dm_put(md); |
747 | return r; | 797 | return r; |
@@ -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 | ||
@@ -885,7 +938,7 @@ static int do_resume(struct dm_ioctl *param) | |||
885 | 938 | ||
886 | hc = __find_device_hash_cell(param); | 939 | hc = __find_device_hash_cell(param); |
887 | if (!hc) { | 940 | if (!hc) { |
888 | DMWARN("device doesn't appear to be in the dev hash table."); | 941 | DMDEBUG_LIMIT("device doesn't appear to be in the dev hash table."); |
889 | up_write(&_hash_lock); | 942 | up_write(&_hash_lock); |
890 | return -ENXIO; | 943 | return -ENXIO; |
891 | } | 944 | } |
@@ -1212,7 +1265,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size) | |||
1212 | 1265 | ||
1213 | hc = __find_device_hash_cell(param); | 1266 | hc = __find_device_hash_cell(param); |
1214 | if (!hc) { | 1267 | if (!hc) { |
1215 | DMWARN("device doesn't appear to be in the dev hash table."); | 1268 | DMDEBUG_LIMIT("device doesn't appear to be in the dev hash table."); |
1216 | up_write(&_hash_lock); | 1269 | up_write(&_hash_lock); |
1217 | return -ENXIO; | 1270 | return -ENXIO; |
1218 | } | 1271 | } |
@@ -1448,14 +1501,10 @@ static int check_version(unsigned int cmd, struct dm_ioctl __user *user) | |||
1448 | return r; | 1501 | return r; |
1449 | } | 1502 | } |
1450 | 1503 | ||
1451 | static void free_params(struct dm_ioctl *param) | ||
1452 | { | ||
1453 | vfree(param); | ||
1454 | } | ||
1455 | |||
1456 | static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) | 1504 | static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) |
1457 | { | 1505 | { |
1458 | struct dm_ioctl tmp, *dmi; | 1506 | struct dm_ioctl tmp, *dmi; |
1507 | int secure_data; | ||
1459 | 1508 | ||
1460 | if (copy_from_user(&tmp, user, sizeof(tmp) - sizeof(tmp.data))) | 1509 | if (copy_from_user(&tmp, user, sizeof(tmp) - sizeof(tmp.data))) |
1461 | return -EFAULT; | 1510 | return -EFAULT; |
@@ -1463,17 +1512,30 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) | |||
1463 | if (tmp.data_size < (sizeof(tmp) - sizeof(tmp.data))) | 1512 | if (tmp.data_size < (sizeof(tmp) - sizeof(tmp.data))) |
1464 | return -EINVAL; | 1513 | return -EINVAL; |
1465 | 1514 | ||
1515 | secure_data = tmp.flags & DM_SECURE_DATA_FLAG; | ||
1516 | |||
1466 | dmi = vmalloc(tmp.data_size); | 1517 | dmi = vmalloc(tmp.data_size); |
1467 | if (!dmi) | 1518 | if (!dmi) { |
1519 | if (secure_data && clear_user(user, tmp.data_size)) | ||
1520 | return -EFAULT; | ||
1468 | return -ENOMEM; | 1521 | return -ENOMEM; |
1469 | |||
1470 | if (copy_from_user(dmi, user, tmp.data_size)) { | ||
1471 | vfree(dmi); | ||
1472 | return -EFAULT; | ||
1473 | } | 1522 | } |
1474 | 1523 | ||
1524 | if (copy_from_user(dmi, user, tmp.data_size)) | ||
1525 | goto bad; | ||
1526 | |||
1527 | /* Wipe the user buffer so we do not return it to userspace */ | ||
1528 | if (secure_data && clear_user(user, tmp.data_size)) | ||
1529 | goto bad; | ||
1530 | |||
1475 | *param = dmi; | 1531 | *param = dmi; |
1476 | return 0; | 1532 | return 0; |
1533 | |||
1534 | bad: | ||
1535 | if (secure_data) | ||
1536 | memset(dmi, 0, tmp.data_size); | ||
1537 | vfree(dmi); | ||
1538 | return -EFAULT; | ||
1477 | } | 1539 | } |
1478 | 1540 | ||
1479 | static int validate_params(uint cmd, struct dm_ioctl *param) | 1541 | static int validate_params(uint cmd, struct dm_ioctl *param) |
@@ -1481,6 +1543,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param) | |||
1481 | /* Always clear this flag */ | 1543 | /* Always clear this flag */ |
1482 | param->flags &= ~DM_BUFFER_FULL_FLAG; | 1544 | param->flags &= ~DM_BUFFER_FULL_FLAG; |
1483 | param->flags &= ~DM_UEVENT_GENERATED_FLAG; | 1545 | param->flags &= ~DM_UEVENT_GENERATED_FLAG; |
1546 | param->flags &= ~DM_SECURE_DATA_FLAG; | ||
1484 | 1547 | ||
1485 | /* Ignores parameters */ | 1548 | /* Ignores parameters */ |
1486 | if (cmd == DM_REMOVE_ALL_CMD || | 1549 | if (cmd == DM_REMOVE_ALL_CMD || |
@@ -1508,10 +1571,11 @@ static int validate_params(uint cmd, struct dm_ioctl *param) | |||
1508 | static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | 1571 | static int ctl_ioctl(uint command, struct dm_ioctl __user *user) |
1509 | { | 1572 | { |
1510 | int r = 0; | 1573 | int r = 0; |
1574 | int wipe_buffer; | ||
1511 | unsigned int cmd; | 1575 | unsigned int cmd; |
1512 | struct dm_ioctl *uninitialized_var(param); | 1576 | struct dm_ioctl *uninitialized_var(param); |
1513 | ioctl_fn fn = NULL; | 1577 | ioctl_fn fn = NULL; |
1514 | size_t param_size; | 1578 | size_t input_param_size; |
1515 | 1579 | ||
1516 | /* only root can play with this */ | 1580 | /* only root can play with this */ |
1517 | if (!capable(CAP_SYS_ADMIN)) | 1581 | if (!capable(CAP_SYS_ADMIN)) |
@@ -1558,13 +1622,15 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | |||
1558 | if (r) | 1622 | if (r) |
1559 | return r; | 1623 | return r; |
1560 | 1624 | ||
1625 | input_param_size = param->data_size; | ||
1626 | wipe_buffer = param->flags & DM_SECURE_DATA_FLAG; | ||
1627 | |||
1561 | r = validate_params(cmd, param); | 1628 | r = validate_params(cmd, param); |
1562 | if (r) | 1629 | if (r) |
1563 | goto out; | 1630 | goto out; |
1564 | 1631 | ||
1565 | param_size = param->data_size; | ||
1566 | param->data_size = sizeof(*param); | 1632 | param->data_size = sizeof(*param); |
1567 | r = fn(param, param_size); | 1633 | r = fn(param, input_param_size); |
1568 | 1634 | ||
1569 | /* | 1635 | /* |
1570 | * Copy the results back to userland. | 1636 | * Copy the results back to userland. |
@@ -1572,8 +1638,11 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) | |||
1572 | if (!r && copy_to_user(user, param, param->data_size)) | 1638 | if (!r && copy_to_user(user, param, param->data_size)) |
1573 | r = -EFAULT; | 1639 | r = -EFAULT; |
1574 | 1640 | ||
1575 | out: | 1641 | out: |
1576 | free_params(param); | 1642 | if (wipe_buffer) |
1643 | memset(param, 0, input_param_size); | ||
1644 | |||
1645 | vfree(param); | ||
1577 | return r; | 1646 | return r; |
1578 | } | 1647 | } |
1579 | 1648 | ||
@@ -1596,6 +1665,7 @@ static const struct file_operations _ctl_fops = { | |||
1596 | .unlocked_ioctl = dm_ctl_ioctl, | 1665 | .unlocked_ioctl = dm_ctl_ioctl, |
1597 | .compat_ioctl = dm_compat_ctl_ioctl, | 1666 | .compat_ioctl = dm_compat_ctl_ioctl, |
1598 | .owner = THIS_MODULE, | 1667 | .owner = THIS_MODULE, |
1668 | .llseek = noop_llseek, | ||
1599 | }; | 1669 | }; |
1600 | 1670 | ||
1601 | static struct miscdevice _dm_misc = { | 1671 | static struct miscdevice _dm_misc = { |