Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'for-6.8/dm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm

Pull device mapper fixes from Mike Snitzer:

- Fix DM ioctl interface to avoid INT_MAX overflow warnings from
kvmalloc by limiting the number of targets and parameter size area.

- Fix DM stats to avoid INT_MAX overflow warnings from kvmalloc by
limiting the number of entries supported.

- Fix DM writecache to support mapping devices larger than 1 TiB by
switching from using kvmalloc_array to vmalloc_array -- which avoids
INT_MAX overflow in kvmalloc_node and associated warnings.

- Remove the (ab)use of tasklets from both the DM crypt and verity
targets. They will be converted to use BH workqueue in future.

* tag 'for-6.8/dm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
dm-crypt, dm-verity: disable tasklets
dm writecache: allow allocations larger than 2GiB
dm stats: limit the number of entries
dm: limit the number of targets and parameter size area

+28 -68
+2
drivers/md/dm-core.h
··· 22 22 #include "dm-ima.h" 23 23 24 24 #define DM_RESERVED_MAX_IOS 1024 25 + #define DM_MAX_TARGETS 1048576 26 + #define DM_MAX_TARGET_PARAMS 1024 25 27 26 28 struct dm_io; 27 29
+2 -36
drivers/md/dm-crypt.c
··· 73 73 struct bio *base_bio; 74 74 u8 *integrity_metadata; 75 75 bool integrity_metadata_from_pool:1; 76 - bool in_tasklet:1; 77 76 78 77 struct work_struct work; 79 - struct tasklet_struct tasklet; 80 78 81 79 struct convert_context ctx; 82 80 ··· 1760 1762 io->ctx.r.req = NULL; 1761 1763 io->integrity_metadata = NULL; 1762 1764 io->integrity_metadata_from_pool = false; 1763 - io->in_tasklet = false; 1764 1765 atomic_set(&io->io_pending, 0); 1765 1766 } 1766 1767 1767 1768 static void crypt_inc_pending(struct dm_crypt_io *io) 1768 1769 { 1769 1770 atomic_inc(&io->io_pending); 1770 - } 1771 - 1772 - static void kcryptd_io_bio_endio(struct work_struct *work) 1773 - { 1774 - struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work); 1775 - 1776 - bio_endio(io->base_bio); 1777 1771 } 1778 1772 1779 1773 /* ··· 1790 1800 kfree(io->integrity_metadata); 1791 1801 1792 1802 base_bio->bi_status = error; 1793 - 1794 - /* 1795 - * If we are running this function from our tasklet, 1796 - * we can't call bio_endio() here, because it will call 1797 - * clone_endio() from dm.c, which in turn will 1798 - * free the current struct dm_crypt_io structure with 1799 - * our tasklet. In this case we need to delay bio_endio() 1800 - * execution to after the tasklet is done and dequeued. 1801 - */ 1802 - if (io->in_tasklet) { 1803 - INIT_WORK(&io->work, kcryptd_io_bio_endio); 1804 - queue_work(cc->io_queue, &io->work); 1805 - return; 1806 - } 1807 1803 1808 1804 bio_endio(base_bio); 1809 1805 } ··· 2222 2246 kcryptd_crypt_write_convert(io); 2223 2247 } 2224 2248 2225 - static void kcryptd_crypt_tasklet(unsigned long work) 2226 - { 2227 - kcryptd_crypt((struct work_struct *)work); 2228 - } 2229 - 2230 2249 static void kcryptd_queue_crypt(struct dm_crypt_io *io) 2231 2250 { 2232 2251 struct crypt_config *cc = io->cc; ··· 2233 2262 * irqs_disabled(): the kernel may run some IO completion from the idle thread, but 2234 2263 * it is being executed with irqs disabled. 2235 2264 */ 2236 - if (in_hardirq() || irqs_disabled()) { 2237 - io->in_tasklet = true; 2238 - tasklet_init(&io->tasklet, kcryptd_crypt_tasklet, (unsigned long)&io->work); 2239 - tasklet_schedule(&io->tasklet); 2265 + if (!(in_hardirq() || irqs_disabled())) { 2266 + kcryptd_crypt(&io->work); 2240 2267 return; 2241 2268 } 2242 - 2243 - kcryptd_crypt(&io->work); 2244 - return; 2245 2269 } 2246 2270 2247 2271 INIT_WORK(&io->work, kcryptd_crypt);
+2 -1
drivers/md/dm-ioctl.c
··· 1941 1941 minimum_data_size - sizeof(param_kernel->version))) 1942 1942 return -EFAULT; 1943 1943 1944 - if (param_kernel->data_size < minimum_data_size) { 1944 + if (unlikely(param_kernel->data_size < minimum_data_size) || 1945 + unlikely(param_kernel->data_size > DM_MAX_TARGETS * DM_MAX_TARGET_PARAMS)) { 1945 1946 DMERR("Invalid data size in the ioctl structure: %u", 1946 1947 param_kernel->data_size); 1947 1948 return -EINVAL;
+9
drivers/md/dm-stats.c
··· 66 66 unsigned int last_rw; 67 67 }; 68 68 69 + #define DM_STAT_MAX_ENTRIES 8388608 70 + #define DM_STAT_MAX_HISTOGRAM_ENTRIES 134217728 71 + 69 72 /* 70 73 * A typo on the command line could possibly make the kernel run out of memory 71 74 * and crash. To prevent the crash we account all used memory. We fail if we ··· 288 285 if (n_entries != (size_t)n_entries || !(size_t)(n_entries + 1)) 289 286 return -EOVERFLOW; 290 287 288 + if (n_entries > DM_STAT_MAX_ENTRIES) 289 + return -EOVERFLOW; 290 + 291 291 shared_alloc_size = struct_size(s, stat_shared, n_entries); 292 292 if ((shared_alloc_size - sizeof(struct dm_stat)) / sizeof(struct dm_stat_shared) != n_entries) 293 293 return -EOVERFLOW; ··· 301 295 302 296 histogram_alloc_size = (n_histogram_entries + 1) * (size_t)n_entries * sizeof(unsigned long long); 303 297 if (histogram_alloc_size / (n_histogram_entries + 1) != (size_t)n_entries * sizeof(unsigned long long)) 298 + return -EOVERFLOW; 299 + 300 + if ((n_histogram_entries + 1) * (size_t)n_entries > DM_STAT_MAX_HISTOGRAM_ENTRIES) 304 301 return -EOVERFLOW; 305 302 306 303 if (!check_shared_memory(shared_alloc_size + histogram_alloc_size +
+7 -2
drivers/md/dm-table.c
··· 129 129 int dm_table_create(struct dm_table **result, blk_mode_t mode, 130 130 unsigned int num_targets, struct mapped_device *md) 131 131 { 132 - struct dm_table *t = kzalloc(sizeof(*t), GFP_KERNEL); 132 + struct dm_table *t; 133 + 134 + if (num_targets > DM_MAX_TARGETS) 135 + return -EOVERFLOW; 136 + 137 + t = kzalloc(sizeof(*t), GFP_KERNEL); 133 138 134 139 if (!t) 135 140 return -ENOMEM; ··· 149 144 150 145 if (!num_targets) { 151 146 kfree(t); 152 - return -ENOMEM; 147 + return -EOVERFLOW; 153 148 } 154 149 155 150 if (alloc_targets(t, num_targets)) {
+2 -24
drivers/md/dm-verity-target.c
··· 645 645 verity_finish_io(io, errno_to_blk_status(verity_verify_io(io))); 646 646 } 647 647 648 - static void verity_tasklet(unsigned long data) 649 - { 650 - struct dm_verity_io *io = (struct dm_verity_io *)data; 651 - int err; 652 - 653 - io->in_tasklet = true; 654 - err = verity_verify_io(io); 655 - if (err == -EAGAIN || err == -ENOMEM) { 656 - /* fallback to retrying with work-queue */ 657 - INIT_WORK(&io->work, verity_work); 658 - queue_work(io->v->verify_wq, &io->work); 659 - return; 660 - } 661 - 662 - verity_finish_io(io, errno_to_blk_status(err)); 663 - } 664 - 665 648 static void verity_end_io(struct bio *bio) 666 649 { 667 650 struct dm_verity_io *io = bio->bi_private; ··· 657 674 return; 658 675 } 659 676 660 - if (static_branch_unlikely(&use_tasklet_enabled) && io->v->use_tasklet) { 661 - tasklet_init(&io->tasklet, verity_tasklet, (unsigned long)io); 662 - tasklet_schedule(&io->tasklet); 663 - } else { 664 - INIT_WORK(&io->work, verity_work); 665 - queue_work(io->v->verify_wq, &io->work); 666 - } 677 + INIT_WORK(&io->work, verity_work); 678 + queue_work(io->v->verify_wq, &io->work); 667 679 } 668 680 669 681 /*
-1
drivers/md/dm-verity.h
··· 83 83 struct bvec_iter iter; 84 84 85 85 struct work_struct work; 86 - struct tasklet_struct tasklet; 87 86 88 87 /* 89 88 * Three variably-size fields follow this struct:
+4 -4
drivers/md/dm-writecache.c
··· 299 299 long i; 300 300 301 301 wc->memory_map = NULL; 302 - pages = kvmalloc_array(p, sizeof(struct page *), GFP_KERNEL); 302 + pages = vmalloc_array(p, sizeof(struct page *)); 303 303 if (!pages) { 304 304 r = -ENOMEM; 305 305 goto err2; ··· 330 330 r = -ENOMEM; 331 331 goto err3; 332 332 } 333 - kvfree(pages); 333 + vfree(pages); 334 334 wc->memory_vmapped = true; 335 335 } 336 336 ··· 341 341 342 342 return 0; 343 343 err3: 344 - kvfree(pages); 344 + vfree(pages); 345 345 err2: 346 346 dax_read_unlock(id); 347 347 err1: ··· 962 962 963 963 if (wc->entries) 964 964 return 0; 965 - wc->entries = vmalloc(array_size(sizeof(struct wc_entry), wc->n_blocks)); 965 + wc->entries = vmalloc_array(wc->n_blocks, sizeof(struct wc_entry)); 966 966 if (!wc->entries) 967 967 return -ENOMEM; 968 968 for (b = 0; b < wc->n_blocks; b++) {