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

dm writecache: fix writing beyond end of underlying device when shrinking

Do not attempt to write any data beyond the end of the underlying data
device while shrinking it.

The DM writecache device must be suspended when the underlying data
device is shrunk.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Cc: stable@vger.kernel.org
Signed-off-by: Mike Snitzer <snitzer@redhat.com>

authored by

Mikulas Patocka and committed by
Mike Snitzer
4134455f cccb493c

+18
+18
drivers/md/dm-writecache.c
··· 148 148 size_t metadata_sectors; 149 149 size_t n_blocks; 150 150 uint64_t seq_count; 151 + sector_t data_device_sectors; 151 152 void *block_start; 152 153 struct wc_entry *entries; 153 154 unsigned block_size; ··· 978 977 979 978 wc_lock(wc); 980 979 980 + wc->data_device_sectors = i_size_read(wc->dev->bdev->bd_inode) >> SECTOR_SHIFT; 981 + 981 982 if (WC_MODE_PMEM(wc)) { 982 983 persistent_memory_invalidate_cache(wc->memory_map, wc->memory_map_size); 983 984 } else { ··· 1649 1646 void *address = memory_data(wc, e); 1650 1647 1651 1648 persistent_memory_flush_cache(address, block_size); 1649 + 1650 + if (unlikely(bio_end_sector(&wb->bio) >= wc->data_device_sectors)) 1651 + return true; 1652 + 1652 1653 return bio_add_page(&wb->bio, persistent_memory_page(address), 1653 1654 block_size, persistent_memory_page_offset(address)) != 0; 1654 1655 } ··· 1724 1717 if (writecache_has_error(wc)) { 1725 1718 bio->bi_status = BLK_STS_IOERR; 1726 1719 bio_endio(bio); 1720 + } else if (unlikely(!bio_sectors(bio))) { 1721 + bio->bi_status = BLK_STS_OK; 1722 + bio_endio(bio); 1727 1723 } else { 1728 1724 submit_bio(bio); 1729 1725 } ··· 1768 1758 BUG_ON(f != e + 1); 1769 1759 list_del(&f->lru); 1770 1760 e = f; 1761 + } 1762 + 1763 + if (unlikely(to.sector + to.count > wc->data_device_sectors)) { 1764 + if (to.sector >= wc->data_device_sectors) { 1765 + writecache_copy_endio(0, 0, c); 1766 + continue; 1767 + } 1768 + from.count = to.count = wc->data_device_sectors - to.sector; 1771 1769 } 1772 1770 1773 1771 dm_kcopyd_copy(wc->dm_kcopyd, &from, 1, &to, 0, writecache_copy_endio, c);