Commit 64f799ff authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-6.9/dm-fixes' of...

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

Pull device mapper fixes from Mike Snitzer:

 - Fix a memory leak in DM integrity recheck code that was added during
   the 6.9 merge. Also fix the recheck code to ensure it issues bios
   with proper alignment.

 - Fix DM snapshot's dm_exception_table_exit() to schedule while
   handling an large exception table during snapshot device shutdown.

* tag 'for-6.9/dm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
  dm-integrity: align the outgoing bio in integrity_recheck
  dm snapshot: fix lockup in dm_exception_table_exit
  dm-integrity: fix a memory leak when rechecking the data
parents ff9c18e4 b4d78cfe
Loading
Loading
Loading
Loading
+13 −5
Original line number Diff line number Diff line
@@ -1699,7 +1699,6 @@ static noinline void integrity_recheck(struct dm_integrity_io *dio, char *checks
	struct bio_vec bv;
	sector_t sector, logical_sector, area, offset;
	struct page *page;
	void *buffer;

	get_area_and_offset(ic, dio->range.logical_sector, &area, &offset);
	dio->metadata_block = get_metadata_sector_and_offset(ic, area, offset,
@@ -1708,13 +1707,14 @@ static noinline void integrity_recheck(struct dm_integrity_io *dio, char *checks
	logical_sector = dio->range.logical_sector;

	page = mempool_alloc(&ic->recheck_pool, GFP_NOIO);
	buffer = page_to_virt(page);

	__bio_for_each_segment(bv, bio, iter, dio->bio_details.bi_iter) {
		unsigned pos = 0;

		do {
			sector_t alignment;
			char *mem;
			char *buffer = page_to_virt(page);
			int r;
			struct dm_io_request io_req;
			struct dm_io_region io_loc;
@@ -1727,6 +1727,14 @@ static noinline void integrity_recheck(struct dm_integrity_io *dio, char *checks
			io_loc.sector = sector;
			io_loc.count = ic->sectors_per_block;

			/* Align the bio to logical block size */
			alignment = dio->range.logical_sector | bio_sectors(bio) | (PAGE_SIZE >> SECTOR_SHIFT);
			alignment &= -alignment;
			io_loc.sector = round_down(io_loc.sector, alignment);
			io_loc.count += sector - io_loc.sector;
			buffer += (sector - io_loc.sector) << SECTOR_SHIFT;
			io_loc.count = round_up(io_loc.count, alignment);

			r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT);
			if (unlikely(r)) {
				dio->bi_status = errno_to_blk_status(r);
@@ -1848,12 +1856,12 @@ static void integrity_metadata(struct work_struct *w)
			r = dm_integrity_rw_tag(ic, checksums, &dio->metadata_block, &dio->metadata_offset,
						checksums_ptr - checksums, dio->op == REQ_OP_READ ? TAG_CMP : TAG_WRITE);
			if (unlikely(r)) {
				if (likely(checksums != checksums_onstack))
					kfree(checksums);
				if (r > 0) {
					integrity_recheck(dio, checksums);
					integrity_recheck(dio, checksums_onstack);
					goto skip_io;
				}
				if (likely(checksums != checksums_onstack))
					kfree(checksums);
				goto error;
			}

+3 −1
Original line number Diff line number Diff line
@@ -684,8 +684,10 @@ static void dm_exception_table_exit(struct dm_exception_table *et,
	for (i = 0; i < size; i++) {
		slot = et->table + i;

		hlist_bl_for_each_entry_safe(ex, pos, n, slot, hash_list)
		hlist_bl_for_each_entry_safe(ex, pos, n, slot, hash_list) {
			kmem_cache_free(mem, ex);
			cond_resched();
		}
	}

	kvfree(et->table);