diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-10-05 18:17:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-10-05 18:17:40 -0400 |
commit | 076264ada9a307300be7a4581165f9c9deed5d1b (patch) | |
tree | dca4d0067d40018d1daa9e069f0a1119e47bd049 | |
parent | 0f380715e51f5ff418cfccb4cd0d4fe4c48c3241 (diff) | |
parent | 41dcf197ad5373a7dd0a4b6572aec2e3ec6a0e49 (diff) |
Merge tag 'for-4.14/dm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm
Pull device mapper fixes from Mike Snitzer:
- a stable fix for the alignment of the event number reported at the
end of the 'DM_LIST_DEVICES' ioctl.
- a couple stable fixes for the DM crypt target.
- a DM raid health status reporting fix.
* tag 'for-4.14/dm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
dm raid: fix incorrect status output at the end of a "recover" process
dm crypt: reject sector_size feature if device length is not aligned to it
dm crypt: fix memory leak in crypt_ctr_cipher_old()
dm ioctl: fix alignment of event number in the device list
-rw-r--r-- | Documentation/device-mapper/dm-raid.txt | 1 | ||||
-rw-r--r-- | drivers/md/dm-core.h | 1 | ||||
-rw-r--r-- | drivers/md/dm-crypt.c | 5 | ||||
-rw-r--r-- | drivers/md/dm-ioctl.c | 37 | ||||
-rw-r--r-- | drivers/md/dm-raid.c | 11 | ||||
-rw-r--r-- | drivers/md/dm.c | 10 | ||||
-rw-r--r-- | include/uapi/linux/dm-ioctl.h | 4 |
7 files changed, 47 insertions, 22 deletions
diff --git a/Documentation/device-mapper/dm-raid.txt b/Documentation/device-mapper/dm-raid.txt index 4a0a7469fdd7..32df07e29f68 100644 --- a/Documentation/device-mapper/dm-raid.txt +++ b/Documentation/device-mapper/dm-raid.txt | |||
@@ -344,3 +344,4 @@ Version History | |||
344 | (wrong raid10_copies/raid10_format sequence) | 344 | (wrong raid10_copies/raid10_format sequence) |
345 | 1.11.1 Add raid4/5/6 journal write-back support via journal_mode option | 345 | 1.11.1 Add raid4/5/6 journal write-back support via journal_mode option |
346 | 1.12.1 fix for MD deadlock between mddev_suspend() and md_write_start() available | 346 | 1.12.1 fix for MD deadlock between mddev_suspend() and md_write_start() available |
347 | 1.13.0 Fix dev_health status at end of "recover" (was 'a', now 'A') | ||
diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h index 24eddbdf2ab4..203144762f36 100644 --- a/drivers/md/dm-core.h +++ b/drivers/md/dm-core.h | |||
@@ -149,5 +149,6 @@ static inline bool dm_message_test_buffer_overflow(char *result, unsigned maxlen | |||
149 | 149 | ||
150 | extern atomic_t dm_global_event_nr; | 150 | extern atomic_t dm_global_event_nr; |
151 | extern wait_queue_head_t dm_global_eventq; | 151 | extern wait_queue_head_t dm_global_eventq; |
152 | void dm_issue_global_event(void); | ||
152 | 153 | ||
153 | #endif | 154 | #endif |
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index a55ffd4f5933..96ab46512e1f 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c | |||
@@ -2466,6 +2466,7 @@ static int crypt_ctr_cipher_old(struct dm_target *ti, char *cipher_in, char *key | |||
2466 | kfree(cipher_api); | 2466 | kfree(cipher_api); |
2467 | return ret; | 2467 | return ret; |
2468 | } | 2468 | } |
2469 | kfree(cipher_api); | ||
2469 | 2470 | ||
2470 | return 0; | 2471 | return 0; |
2471 | bad_mem: | 2472 | bad_mem: |
@@ -2584,6 +2585,10 @@ static int crypt_ctr_optional(struct dm_target *ti, unsigned int argc, char **ar | |||
2584 | ti->error = "Invalid feature value for sector_size"; | 2585 | ti->error = "Invalid feature value for sector_size"; |
2585 | return -EINVAL; | 2586 | return -EINVAL; |
2586 | } | 2587 | } |
2588 | if (ti->len & ((cc->sector_size >> SECTOR_SHIFT) - 1)) { | ||
2589 | ti->error = "Device size is not multiple of sector_size feature"; | ||
2590 | return -EINVAL; | ||
2591 | } | ||
2587 | cc->sector_shift = __ffs(cc->sector_size) - SECTOR_SHIFT; | 2592 | cc->sector_shift = __ffs(cc->sector_size) - SECTOR_SHIFT; |
2588 | } else if (!strcasecmp(opt_string, "iv_large_sectors")) | 2593 | } else if (!strcasecmp(opt_string, "iv_large_sectors")) |
2589 | set_bit(CRYPT_IV_LARGE_SECTORS, &cc->cipher_flags); | 2594 | set_bit(CRYPT_IV_LARGE_SECTORS, &cc->cipher_flags); |
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 8756a6850431..e52676fa9832 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c | |||
@@ -477,9 +477,13 @@ static int remove_all(struct file *filp, struct dm_ioctl *param, size_t param_si | |||
477 | * Round up the ptr to an 8-byte boundary. | 477 | * Round up the ptr to an 8-byte boundary. |
478 | */ | 478 | */ |
479 | #define ALIGN_MASK 7 | 479 | #define ALIGN_MASK 7 |
480 | static inline size_t align_val(size_t val) | ||
481 | { | ||
482 | return (val + ALIGN_MASK) & ~ALIGN_MASK; | ||
483 | } | ||
480 | static inline void *align_ptr(void *ptr) | 484 | static inline void *align_ptr(void *ptr) |
481 | { | 485 | { |
482 | return (void *) (((size_t) (ptr + ALIGN_MASK)) & ~ALIGN_MASK); | 486 | return (void *)align_val((size_t)ptr); |
483 | } | 487 | } |
484 | 488 | ||
485 | /* | 489 | /* |
@@ -505,7 +509,7 @@ static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_ | |||
505 | struct hash_cell *hc; | 509 | struct hash_cell *hc; |
506 | size_t len, needed = 0; | 510 | size_t len, needed = 0; |
507 | struct gendisk *disk; | 511 | struct gendisk *disk; |
508 | struct dm_name_list *nl, *old_nl = NULL; | 512 | struct dm_name_list *orig_nl, *nl, *old_nl = NULL; |
509 | uint32_t *event_nr; | 513 | uint32_t *event_nr; |
510 | 514 | ||
511 | down_write(&_hash_lock); | 515 | down_write(&_hash_lock); |
@@ -516,17 +520,15 @@ static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_ | |||
516 | */ | 520 | */ |
517 | for (i = 0; i < NUM_BUCKETS; i++) { | 521 | for (i = 0; i < NUM_BUCKETS; i++) { |
518 | list_for_each_entry (hc, _name_buckets + i, name_list) { | 522 | list_for_each_entry (hc, _name_buckets + i, name_list) { |
519 | needed += sizeof(struct dm_name_list); | 523 | needed += align_val(offsetof(struct dm_name_list, name) + strlen(hc->name) + 1); |
520 | needed += strlen(hc->name) + 1; | 524 | needed += align_val(sizeof(uint32_t)); |
521 | needed += ALIGN_MASK; | ||
522 | needed += (sizeof(uint32_t) + ALIGN_MASK) & ~ALIGN_MASK; | ||
523 | } | 525 | } |
524 | } | 526 | } |
525 | 527 | ||
526 | /* | 528 | /* |
527 | * Grab our output buffer. | 529 | * Grab our output buffer. |
528 | */ | 530 | */ |
529 | nl = get_result_buffer(param, param_size, &len); | 531 | nl = orig_nl = get_result_buffer(param, param_size, &len); |
530 | if (len < needed) { | 532 | if (len < needed) { |
531 | param->flags |= DM_BUFFER_FULL_FLAG; | 533 | param->flags |= DM_BUFFER_FULL_FLAG; |
532 | goto out; | 534 | goto out; |
@@ -549,11 +551,16 @@ static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_ | |||
549 | strcpy(nl->name, hc->name); | 551 | strcpy(nl->name, hc->name); |
550 | 552 | ||
551 | old_nl = nl; | 553 | old_nl = nl; |
552 | event_nr = align_ptr(((void *) (nl + 1)) + strlen(hc->name) + 1); | 554 | event_nr = align_ptr(nl->name + strlen(hc->name) + 1); |
553 | *event_nr = dm_get_event_nr(hc->md); | 555 | *event_nr = dm_get_event_nr(hc->md); |
554 | nl = align_ptr(event_nr + 1); | 556 | nl = align_ptr(event_nr + 1); |
555 | } | 557 | } |
556 | } | 558 | } |
559 | /* | ||
560 | * If mismatch happens, security may be compromised due to buffer | ||
561 | * overflow, so it's better to crash. | ||
562 | */ | ||
563 | BUG_ON((char *)nl - (char *)orig_nl != needed); | ||
557 | 564 | ||
558 | out: | 565 | out: |
559 | up_write(&_hash_lock); | 566 | up_write(&_hash_lock); |
@@ -1621,7 +1628,8 @@ static int target_message(struct file *filp, struct dm_ioctl *param, size_t para | |||
1621 | * which has a variable size, is not used by the function processing | 1628 | * which has a variable size, is not used by the function processing |
1622 | * the ioctl. | 1629 | * the ioctl. |
1623 | */ | 1630 | */ |
1624 | #define IOCTL_FLAGS_NO_PARAMS 1 | 1631 | #define IOCTL_FLAGS_NO_PARAMS 1 |
1632 | #define IOCTL_FLAGS_ISSUE_GLOBAL_EVENT 2 | ||
1625 | 1633 | ||
1626 | /*----------------------------------------------------------------- | 1634 | /*----------------------------------------------------------------- |
1627 | * Implementation of open/close/ioctl on the special char | 1635 | * Implementation of open/close/ioctl on the special char |
@@ -1635,12 +1643,12 @@ static ioctl_fn lookup_ioctl(unsigned int cmd, int *ioctl_flags) | |||
1635 | ioctl_fn fn; | 1643 | ioctl_fn fn; |
1636 | } _ioctls[] = { | 1644 | } _ioctls[] = { |
1637 | {DM_VERSION_CMD, 0, NULL}, /* version is dealt with elsewhere */ | 1645 | {DM_VERSION_CMD, 0, NULL}, /* version is dealt with elsewhere */ |
1638 | {DM_REMOVE_ALL_CMD, IOCTL_FLAGS_NO_PARAMS, remove_all}, | 1646 | {DM_REMOVE_ALL_CMD, IOCTL_FLAGS_NO_PARAMS | IOCTL_FLAGS_ISSUE_GLOBAL_EVENT, remove_all}, |
1639 | {DM_LIST_DEVICES_CMD, 0, list_devices}, | 1647 | {DM_LIST_DEVICES_CMD, 0, list_devices}, |
1640 | 1648 | ||
1641 | {DM_DEV_CREATE_CMD, IOCTL_FLAGS_NO_PARAMS, dev_create}, | 1649 | {DM_DEV_CREATE_CMD, IOCTL_FLAGS_NO_PARAMS | IOCTL_FLAGS_ISSUE_GLOBAL_EVENT, dev_create}, |
1642 | {DM_DEV_REMOVE_CMD, IOCTL_FLAGS_NO_PARAMS, dev_remove}, | 1650 | {DM_DEV_REMOVE_CMD, IOCTL_FLAGS_NO_PARAMS | IOCTL_FLAGS_ISSUE_GLOBAL_EVENT, dev_remove}, |
1643 | {DM_DEV_RENAME_CMD, 0, dev_rename}, | 1651 | {DM_DEV_RENAME_CMD, IOCTL_FLAGS_ISSUE_GLOBAL_EVENT, dev_rename}, |
1644 | {DM_DEV_SUSPEND_CMD, IOCTL_FLAGS_NO_PARAMS, dev_suspend}, | 1652 | {DM_DEV_SUSPEND_CMD, IOCTL_FLAGS_NO_PARAMS, dev_suspend}, |
1645 | {DM_DEV_STATUS_CMD, IOCTL_FLAGS_NO_PARAMS, dev_status}, | 1653 | {DM_DEV_STATUS_CMD, IOCTL_FLAGS_NO_PARAMS, dev_status}, |
1646 | {DM_DEV_WAIT_CMD, 0, dev_wait}, | 1654 | {DM_DEV_WAIT_CMD, 0, dev_wait}, |
@@ -1869,6 +1877,9 @@ static int ctl_ioctl(struct file *file, uint command, struct dm_ioctl __user *us | |||
1869 | unlikely(ioctl_flags & IOCTL_FLAGS_NO_PARAMS)) | 1877 | unlikely(ioctl_flags & IOCTL_FLAGS_NO_PARAMS)) |
1870 | DMERR("ioctl %d tried to output some data but has IOCTL_FLAGS_NO_PARAMS set", cmd); | 1878 | DMERR("ioctl %d tried to output some data but has IOCTL_FLAGS_NO_PARAMS set", cmd); |
1871 | 1879 | ||
1880 | if (!r && ioctl_flags & IOCTL_FLAGS_ISSUE_GLOBAL_EVENT) | ||
1881 | dm_issue_global_event(); | ||
1882 | |||
1872 | /* | 1883 | /* |
1873 | * Copy the results back to userland. | 1884 | * Copy the results back to userland. |
1874 | */ | 1885 | */ |
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 1ac58c5651b7..2245d06d2045 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c | |||
@@ -3297,11 +3297,10 @@ static const char *__raid_dev_status(struct raid_set *rs, struct md_rdev *rdev, | |||
3297 | static sector_t rs_get_progress(struct raid_set *rs, | 3297 | static sector_t rs_get_progress(struct raid_set *rs, |
3298 | sector_t resync_max_sectors, bool *array_in_sync) | 3298 | sector_t resync_max_sectors, bool *array_in_sync) |
3299 | { | 3299 | { |
3300 | sector_t r, recovery_cp, curr_resync_completed; | 3300 | sector_t r, curr_resync_completed; |
3301 | struct mddev *mddev = &rs->md; | 3301 | struct mddev *mddev = &rs->md; |
3302 | 3302 | ||
3303 | curr_resync_completed = mddev->curr_resync_completed ?: mddev->recovery_cp; | 3303 | curr_resync_completed = mddev->curr_resync_completed ?: mddev->recovery_cp; |
3304 | recovery_cp = mddev->recovery_cp; | ||
3305 | *array_in_sync = false; | 3304 | *array_in_sync = false; |
3306 | 3305 | ||
3307 | if (rs_is_raid0(rs)) { | 3306 | if (rs_is_raid0(rs)) { |
@@ -3330,9 +3329,11 @@ static sector_t rs_get_progress(struct raid_set *rs, | |||
3330 | } else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) | 3329 | } else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) |
3331 | r = curr_resync_completed; | 3330 | r = curr_resync_completed; |
3332 | else | 3331 | else |
3333 | r = recovery_cp; | 3332 | r = mddev->recovery_cp; |
3334 | 3333 | ||
3335 | if (r == MaxSector) { | 3334 | if ((r == MaxSector) || |
3335 | (test_bit(MD_RECOVERY_DONE, &mddev->recovery) && | ||
3336 | (mddev->curr_resync_completed == resync_max_sectors))) { | ||
3336 | /* | 3337 | /* |
3337 | * Sync complete. | 3338 | * Sync complete. |
3338 | */ | 3339 | */ |
@@ -3892,7 +3893,7 @@ static void raid_resume(struct dm_target *ti) | |||
3892 | 3893 | ||
3893 | static struct target_type raid_target = { | 3894 | static struct target_type raid_target = { |
3894 | .name = "raid", | 3895 | .name = "raid", |
3895 | .version = {1, 12, 1}, | 3896 | .version = {1, 13, 0}, |
3896 | .module = THIS_MODULE, | 3897 | .module = THIS_MODULE, |
3897 | .ctr = raid_ctr, | 3898 | .ctr = raid_ctr, |
3898 | .dtr = raid_dtr, | 3899 | .dtr = raid_dtr, |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 6e54145969c5..4be85324f44d 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -52,6 +52,12 @@ static struct workqueue_struct *deferred_remove_workqueue; | |||
52 | atomic_t dm_global_event_nr = ATOMIC_INIT(0); | 52 | atomic_t dm_global_event_nr = ATOMIC_INIT(0); |
53 | DECLARE_WAIT_QUEUE_HEAD(dm_global_eventq); | 53 | DECLARE_WAIT_QUEUE_HEAD(dm_global_eventq); |
54 | 54 | ||
55 | void dm_issue_global_event(void) | ||
56 | { | ||
57 | atomic_inc(&dm_global_event_nr); | ||
58 | wake_up(&dm_global_eventq); | ||
59 | } | ||
60 | |||
55 | /* | 61 | /* |
56 | * One of these is allocated per bio. | 62 | * One of these is allocated per bio. |
57 | */ | 63 | */ |
@@ -1865,9 +1871,8 @@ static void event_callback(void *context) | |||
1865 | dm_send_uevents(&uevents, &disk_to_dev(md->disk)->kobj); | 1871 | dm_send_uevents(&uevents, &disk_to_dev(md->disk)->kobj); |
1866 | 1872 | ||
1867 | atomic_inc(&md->event_nr); | 1873 | atomic_inc(&md->event_nr); |
1868 | atomic_inc(&dm_global_event_nr); | ||
1869 | wake_up(&md->eventq); | 1874 | wake_up(&md->eventq); |
1870 | wake_up(&dm_global_eventq); | 1875 | dm_issue_global_event(); |
1871 | } | 1876 | } |
1872 | 1877 | ||
1873 | /* | 1878 | /* |
@@ -2283,6 +2288,7 @@ struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table) | |||
2283 | } | 2288 | } |
2284 | 2289 | ||
2285 | map = __bind(md, table, &limits); | 2290 | map = __bind(md, table, &limits); |
2291 | dm_issue_global_event(); | ||
2286 | 2292 | ||
2287 | out: | 2293 | out: |
2288 | mutex_unlock(&md->suspend_lock); | 2294 | mutex_unlock(&md->suspend_lock); |
diff --git a/include/uapi/linux/dm-ioctl.h b/include/uapi/linux/dm-ioctl.h index 412c06a624c8..ccaea525340b 100644 --- a/include/uapi/linux/dm-ioctl.h +++ b/include/uapi/linux/dm-ioctl.h | |||
@@ -269,9 +269,9 @@ enum { | |||
269 | #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) | 269 | #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) |
270 | 270 | ||
271 | #define DM_VERSION_MAJOR 4 | 271 | #define DM_VERSION_MAJOR 4 |
272 | #define DM_VERSION_MINOR 36 | 272 | #define DM_VERSION_MINOR 37 |
273 | #define DM_VERSION_PATCHLEVEL 0 | 273 | #define DM_VERSION_PATCHLEVEL 0 |
274 | #define DM_VERSION_EXTRA "-ioctl (2017-06-09)" | 274 | #define DM_VERSION_EXTRA "-ioctl (2017-09-20)" |
275 | 275 | ||
276 | /* Status bits */ | 276 | /* Status bits */ |
277 | #define DM_READONLY_FLAG (1 << 0) /* In/Out */ | 277 | #define DM_READONLY_FLAG (1 << 0) /* In/Out */ |