mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 22:19:30 +02:00
Merge tag 'for-7.3/dm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm
Pull device mapper fixes from Mikulas Patocka:
- fix a dm-crypt race condition that could make errors not being reported
- dm-cache:
- fix rwsem being locked and unlocked from different processes
- fix demotion statistics
- dm-integrity:
- set the 'stable writes' flag
- fix a buffer overflow introduced in this merge window
- fix an infinite loop if tag size is greater than 64
- fix NULL pointer dereference in dm-integrity data-recovery mode
- remove a bogus restriction on the dm-ebs starting sector offset
* tag 'for-7.3/dm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
dm-ebs: fix incorrect device offset check in ebs_ctr()
dm-integrity: fix NULL pointer dereference when the 'R' flag is used
dm cache: fix demotion stats in passthrough mode
dm-integrity: fix infinite loop on discard with large tag size
dm-integrity: fix buffer overflow with keyed discard
dm-integrity: require stable writes for internal hash modes
dm cache: fix issue with background work locking
dm-crypt: fix a tiny race condition in crypt_dec_pending
This commit is contained in:
@@ -340,8 +340,6 @@ struct cache {
|
||||
struct list_head invalidation_requests;
|
||||
|
||||
sector_t migration_threshold;
|
||||
wait_queue_head_t migration_wait;
|
||||
atomic_t nr_allocated_migrations;
|
||||
|
||||
/*
|
||||
* The number of in flight migrations that are performing
|
||||
@@ -397,7 +395,11 @@ struct cache {
|
||||
bool loaded_mappings:1;
|
||||
bool loaded_discards:1;
|
||||
|
||||
struct rw_semaphore background_work_lock;
|
||||
/* background work management */
|
||||
bool background_work_allowed;
|
||||
unsigned background_work_nr;
|
||||
spinlock_t background_work_lock;
|
||||
wait_queue_head_t background_work_wait;
|
||||
|
||||
struct batcher committer;
|
||||
struct work_struct commit_ws;
|
||||
@@ -488,19 +490,13 @@ static struct dm_cache_migration *alloc_migration(struct cache *cache)
|
||||
memset(mg, 0, sizeof(*mg));
|
||||
|
||||
mg->cache = cache;
|
||||
atomic_inc(&cache->nr_allocated_migrations);
|
||||
|
||||
return mg;
|
||||
}
|
||||
|
||||
static void free_migration(struct dm_cache_migration *mg)
|
||||
{
|
||||
struct cache *cache = mg->cache;
|
||||
|
||||
if (atomic_dec_and_test(&cache->nr_allocated_migrations))
|
||||
wake_up(&cache->migration_wait);
|
||||
|
||||
mempool_free(mg, &cache->migration_pool);
|
||||
mempool_free(mg, &mg->cache->migration_pool);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
@@ -1030,34 +1026,39 @@ static void calc_discard_block_range(struct cache *cache, struct bio *bio,
|
||||
|
||||
static void prevent_background_work(struct cache *cache)
|
||||
{
|
||||
lockdep_off();
|
||||
down_write(&cache->background_work_lock);
|
||||
lockdep_on();
|
||||
spin_lock_irq(&cache->background_work_lock);
|
||||
cache->background_work_allowed = false;
|
||||
wait_event_lock_irq(cache->background_work_wait,
|
||||
cache->background_work_nr == 0,
|
||||
cache->background_work_lock);
|
||||
spin_unlock_irq(&cache->background_work_lock);
|
||||
}
|
||||
|
||||
static void allow_background_work(struct cache *cache)
|
||||
{
|
||||
lockdep_off();
|
||||
up_write(&cache->background_work_lock);
|
||||
lockdep_on();
|
||||
spin_lock_irq(&cache->background_work_lock);
|
||||
cache->background_work_allowed = true;
|
||||
spin_unlock_irq(&cache->background_work_lock);
|
||||
}
|
||||
|
||||
static bool background_work_begin(struct cache *cache)
|
||||
{
|
||||
bool r;
|
||||
|
||||
lockdep_off();
|
||||
r = down_read_trylock(&cache->background_work_lock);
|
||||
lockdep_on();
|
||||
|
||||
spin_lock_irq(&cache->background_work_lock);
|
||||
r = cache->background_work_allowed;
|
||||
if (r)
|
||||
cache->background_work_nr++;
|
||||
spin_unlock_irq(&cache->background_work_lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void background_work_end(struct cache *cache)
|
||||
{
|
||||
lockdep_off();
|
||||
up_read(&cache->background_work_lock);
|
||||
lockdep_on();
|
||||
spin_lock_irq(&cache->background_work_lock);
|
||||
if (--cache->background_work_nr == 0)
|
||||
wake_up(&cache->background_work_wait);
|
||||
spin_unlock_irq(&cache->background_work_lock);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
@@ -1462,6 +1463,9 @@ static void invalidate_complete(struct dm_cache_migration *mg, bool success)
|
||||
struct bio_list bios;
|
||||
struct cache *cache = mg->cache;
|
||||
|
||||
if (success)
|
||||
atomic_inc(&cache->stats.demotion);
|
||||
|
||||
bio_list_init(&bios);
|
||||
if (mg->cell) {
|
||||
if (dm_cell_unlock_v2(cache->prison, mg->cell, &bios))
|
||||
@@ -1733,7 +1737,6 @@ static int map_bio(struct cache *cache, struct bio *bio, dm_oblock_t block,
|
||||
if (passthrough_mode(cache)) {
|
||||
if (bio_data_dir(bio) == WRITE) {
|
||||
bio_drop_shared_lock(cache, bio);
|
||||
atomic_inc(&cache->stats.demotion);
|
||||
invalidate_start(cache, cblock, block, bio);
|
||||
return DM_MAPIO_SUBMITTED;
|
||||
} else
|
||||
@@ -2507,9 +2510,7 @@ static int cache_create(struct cache_args *ca, struct cache **result)
|
||||
|
||||
spin_lock_init(&cache->lock);
|
||||
bio_list_init(&cache->deferred_bios);
|
||||
atomic_set(&cache->nr_allocated_migrations, 0);
|
||||
atomic_set(&cache->nr_io_migrations, 0);
|
||||
init_waitqueue_head(&cache->migration_wait);
|
||||
|
||||
r = -ENOMEM;
|
||||
atomic_set(&cache->nr_dirty, 0);
|
||||
@@ -2592,8 +2593,10 @@ static int cache_create(struct cache_args *ca, struct cache **result)
|
||||
issue_op, cache, cache->wq);
|
||||
dm_iot_init(&cache->tracker);
|
||||
|
||||
init_rwsem(&cache->background_work_lock);
|
||||
prevent_background_work(cache);
|
||||
init_waitqueue_head(&cache->background_work_wait);
|
||||
spin_lock_init(&cache->background_work_lock);
|
||||
cache->background_work_allowed = false;
|
||||
cache->background_work_nr = 0;
|
||||
|
||||
*result = cache;
|
||||
return 0;
|
||||
|
||||
@@ -1745,7 +1745,6 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
|
||||
{
|
||||
struct crypt_config *cc = io->cc;
|
||||
struct bio *base_bio = io->base_bio;
|
||||
blk_status_t error = io->error;
|
||||
|
||||
if (!atomic_dec_and_test(&io->io_pending))
|
||||
return;
|
||||
@@ -1767,7 +1766,7 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
|
||||
else
|
||||
kfree(io->integrity_metadata);
|
||||
|
||||
base_bio->bi_status = error;
|
||||
base_bio->bi_status = io->error;
|
||||
|
||||
bio_endio(base_bio);
|
||||
}
|
||||
|
||||
@@ -265,8 +265,7 @@ static int ebs_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
|
||||
r = -EINVAL;
|
||||
if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1 ||
|
||||
tmp != (sector_t)tmp ||
|
||||
(sector_t)tmp >= ti->len) {
|
||||
tmp != (sector_t)tmp) {
|
||||
ti->error = "Invalid device offset sector";
|
||||
goto bad;
|
||||
}
|
||||
|
||||
@@ -1979,8 +1979,8 @@ static void integrity_metadata(struct work_struct *w)
|
||||
|
||||
if (unlikely(dio->op == REQ_OP_DISCARD)) {
|
||||
unsigned int bi_size = dio->bio_details.bi_iter.bi_size;
|
||||
unsigned int max_size = likely(checksums != checksums_onstack) ? PAGE_SIZE : HASH_MAX_DIGESTSIZE;
|
||||
unsigned int max_blocks = max_size / ic->tag_size;
|
||||
unsigned int max_size = likely(checksums != checksums_onstack) ? PAGE_SIZE : sizeof(checksums_onstack);
|
||||
unsigned int max_blocks = (max_size - extra_space) / ic->tag_size;
|
||||
sector_t sector = dio->range.logical_sector;
|
||||
|
||||
if (!ic->discard_keyed)
|
||||
@@ -3875,6 +3875,10 @@ static void dm_integrity_resume(struct dm_target *ti)
|
||||
r = sync_rw_sb(ic, REQ_OP_READ);
|
||||
if (r)
|
||||
dm_integrity_io_error(ic, "reading superblock", r);
|
||||
|
||||
if (ic->mode == 'R')
|
||||
goto skip_writes;
|
||||
|
||||
if ((ic->sb->flags & flags) != flags) {
|
||||
ic->sb->flags |= flags;
|
||||
r = sync_rw_sb(ic, REQ_OP_WRITE | REQ_FUA);
|
||||
@@ -3984,6 +3988,7 @@ static void dm_integrity_resume(struct dm_target *ti)
|
||||
}
|
||||
}
|
||||
|
||||
skip_writes:
|
||||
ic->reboot_notifier.notifier_call = dm_integrity_reboot;
|
||||
ic->reboot_notifier.next = NULL;
|
||||
ic->reboot_notifier.priority = INT_MAX - 1; /* be notified after md and before hardware drivers */
|
||||
@@ -4130,6 +4135,10 @@ static void dm_integrity_io_hints(struct dm_target *ti, struct queue_limits *lim
|
||||
limits->dma_alignment = limits->logical_block_size - 1;
|
||||
limits->discard_granularity = ic->sectors_per_block << SECTOR_SHIFT;
|
||||
|
||||
if (ic->internal_hash &&
|
||||
(ic->mode == 'D' || ic->mode == 'B' || ic->mode == 'I'))
|
||||
limits->features |= BLK_FEAT_STABLE_WRITES;
|
||||
|
||||
if (!ic->internal_hash) {
|
||||
struct blk_integrity *bi = &limits->integrity;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user