. stable fix for dm-thin that avoids normal IO racing with discard
. stable fix for a dm-cache related bug in dm-btree walking code that results from using very large fast device (e.g. 4T) with a very small cache blocksize (e.g. 32K) -- this is a very uncommon configuration . a couple fixes for dm-raid (one for stable and the other addresses a crash in 3.18-rc1 code) . stable fix for dm-thinp that addresses a very rare dm-bufio bug having to do with memory reclaimation (via shrinker) when using dm-thinp ontop of loopback devices . fix a leak in dm-stripe target constructor's error path -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJUY/p7AAoJEMUj8QotnQNaxPEIAJsmJC5ujQAIdm5yUxsOWruU Y/36HbPvlmV8fgWqGyjaubBrzqgWry/yW/u/Sv9+9rE3Zh6JSVLVrCA6uZZ3Yr+j HKYEPjm/O0zVJepfEDKtjG6dxeaql47+luwU1iP1bAYeZE3zmKn1oFT2GW5gTbxO 2n3MiN/dyX8v0cTw6r0O69luIAu93CSY0XDk+1ynfKlKKVmgcAUPvKuobF+yHXoF Rd7KTqFoK6HgRhdUHvUQnCGDandZ9MHjt3oW9p3dv3ezvW1cNUARoVHMRGG6Awfu WZkQ/VORDeaJT+bhjGfPIla1HbgxEKJrgzTUlpj+P6K2uPK2f6ECEyBpDLWKy9g= =lkSu -----END PGP SIGNATURE----- Merge tag 'dm-3.18-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm Pull device mapper fixes from Mike Snitzer: - stable fix for dm-thin that avoids normal IO racing with discard - stable fix for a dm-cache related bug in dm-btree walking code that results from using very large fast device (eg 4T) with a very small cache blocksize (eg 32K) -- this is a very uncommon configuration - a couple fixes for dm-raid (one for stable and the other addresses a crash in 3.18-rc1 code) - stable fix for dm-thinp that addresses a very rare dm-bufio bug having to do with memory reclaimation (via shrinker) when using dm-thinp ontop of loopback devices - fix a leak in dm-stripe target constructor's error path * tag 'dm-3.18-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm: dm btree: fix a recursion depth bug in btree walking code dm thin: grab a virtual cell before looking up the mapping dm raid: fix inaccessible superblocks causing oops in configure_discard_support dm raid: ensure superblock's size matches device's logical block size dm bufio: change __GFP_IO to __GFP_FS in shrinker callbacks dm stripe: fix potential for leak in stripe_ctr error path
This commit is contained in:
Коммит
5a7a662cc6
|
@ -1434,9 +1434,9 @@ static void drop_buffers(struct dm_bufio_client *c)
|
|||
|
||||
/*
|
||||
* Test if the buffer is unused and too old, and commit it.
|
||||
* At if noio is set, we must not do any I/O because we hold
|
||||
* dm_bufio_clients_lock and we would risk deadlock if the I/O gets rerouted to
|
||||
* different bufio client.
|
||||
* And if GFP_NOFS is used, we must not do any I/O because we hold
|
||||
* dm_bufio_clients_lock and we would risk deadlock if the I/O gets
|
||||
* rerouted to different bufio client.
|
||||
*/
|
||||
static int __cleanup_old_buffer(struct dm_buffer *b, gfp_t gfp,
|
||||
unsigned long max_jiffies)
|
||||
|
@ -1444,7 +1444,7 @@ static int __cleanup_old_buffer(struct dm_buffer *b, gfp_t gfp,
|
|||
if (jiffies - b->last_accessed < max_jiffies)
|
||||
return 0;
|
||||
|
||||
if (!(gfp & __GFP_IO)) {
|
||||
if (!(gfp & __GFP_FS)) {
|
||||
if (test_bit(B_READING, &b->state) ||
|
||||
test_bit(B_WRITING, &b->state) ||
|
||||
test_bit(B_DIRTY, &b->state))
|
||||
|
@ -1486,7 +1486,7 @@ dm_bufio_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
|
|||
unsigned long freed;
|
||||
|
||||
c = container_of(shrink, struct dm_bufio_client, shrinker);
|
||||
if (sc->gfp_mask & __GFP_IO)
|
||||
if (sc->gfp_mask & __GFP_FS)
|
||||
dm_bufio_lock(c);
|
||||
else if (!dm_bufio_trylock(c))
|
||||
return SHRINK_STOP;
|
||||
|
@ -1503,7 +1503,7 @@ dm_bufio_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
|
|||
unsigned long count;
|
||||
|
||||
c = container_of(shrink, struct dm_bufio_client, shrinker);
|
||||
if (sc->gfp_mask & __GFP_IO)
|
||||
if (sc->gfp_mask & __GFP_FS)
|
||||
dm_bufio_lock(c);
|
||||
else if (!dm_bufio_trylock(c))
|
||||
return 0;
|
||||
|
|
|
@ -789,8 +789,7 @@ struct dm_raid_superblock {
|
|||
__le32 layout;
|
||||
__le32 stripe_sectors;
|
||||
|
||||
__u8 pad[452]; /* Round struct to 512 bytes. */
|
||||
/* Always set to 0 when writing. */
|
||||
/* Remainder of a logical block is zero-filled when writing (see super_sync()). */
|
||||
} __packed;
|
||||
|
||||
static int read_disk_sb(struct md_rdev *rdev, int size)
|
||||
|
@ -827,7 +826,7 @@ static void super_sync(struct mddev *mddev, struct md_rdev *rdev)
|
|||
test_bit(Faulty, &(rs->dev[i].rdev.flags)))
|
||||
failed_devices |= (1ULL << i);
|
||||
|
||||
memset(sb, 0, sizeof(*sb));
|
||||
memset(sb + 1, 0, rdev->sb_size - sizeof(*sb));
|
||||
|
||||
sb->magic = cpu_to_le32(DM_RAID_MAGIC);
|
||||
sb->features = cpu_to_le32(0); /* No features yet */
|
||||
|
@ -862,7 +861,11 @@ static int super_load(struct md_rdev *rdev, struct md_rdev *refdev)
|
|||
uint64_t events_sb, events_refsb;
|
||||
|
||||
rdev->sb_start = 0;
|
||||
rdev->sb_size = sizeof(*sb);
|
||||
rdev->sb_size = bdev_logical_block_size(rdev->meta_bdev);
|
||||
if (rdev->sb_size < sizeof(*sb) || rdev->sb_size > PAGE_SIZE) {
|
||||
DMERR("superblock size of a logical block is no longer valid");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = read_disk_sb(rdev, rdev->sb_size);
|
||||
if (ret)
|
||||
|
@ -1169,8 +1172,12 @@ static void configure_discard_support(struct dm_target *ti, struct raid_set *rs)
|
|||
raid456 = (rs->md.level == 4 || rs->md.level == 5 || rs->md.level == 6);
|
||||
|
||||
for (i = 0; i < rs->md.raid_disks; i++) {
|
||||
struct request_queue *q = bdev_get_queue(rs->dev[i].rdev.bdev);
|
||||
struct request_queue *q;
|
||||
|
||||
if (!rs->dev[i].rdev.bdev)
|
||||
continue;
|
||||
|
||||
q = bdev_get_queue(rs->dev[i].rdev.bdev);
|
||||
if (!q || !blk_queue_discard(q))
|
||||
return;
|
||||
|
||||
|
|
|
@ -159,8 +159,10 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
|||
sc->stripes_shift = __ffs(stripes);
|
||||
|
||||
r = dm_set_target_max_io_len(ti, chunk_size);
|
||||
if (r)
|
||||
if (r) {
|
||||
kfree(sc);
|
||||
return r;
|
||||
}
|
||||
|
||||
ti->num_flush_bios = stripes;
|
||||
ti->num_discard_bios = stripes;
|
||||
|
|
|
@ -1936,6 +1936,14 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
|
|||
return DM_MAPIO_SUBMITTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* We must hold the virtual cell before doing the lookup, otherwise
|
||||
* there's a race with discard.
|
||||
*/
|
||||
build_virtual_key(tc->td, block, &key);
|
||||
if (dm_bio_detain(tc->pool->prison, &key, bio, &cell1, &cell_result))
|
||||
return DM_MAPIO_SUBMITTED;
|
||||
|
||||
r = dm_thin_find_block(td, block, 0, &result);
|
||||
|
||||
/*
|
||||
|
@ -1959,13 +1967,10 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
|
|||
* shared flag will be set in their case.
|
||||
*/
|
||||
thin_defer_bio(tc, bio);
|
||||
cell_defer_no_holder_no_free(tc, &cell1);
|
||||
return DM_MAPIO_SUBMITTED;
|
||||
}
|
||||
|
||||
build_virtual_key(tc->td, block, &key);
|
||||
if (dm_bio_detain(tc->pool->prison, &key, bio, &cell1, &cell_result))
|
||||
return DM_MAPIO_SUBMITTED;
|
||||
|
||||
build_data_key(tc->td, result.block, &key);
|
||||
if (dm_bio_detain(tc->pool->prison, &key, bio, &cell2, &cell_result)) {
|
||||
cell_defer_no_holder_no_free(tc, &cell1);
|
||||
|
@ -1986,6 +1991,7 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
|
|||
* of doing so.
|
||||
*/
|
||||
handle_unserviceable_bio(tc->pool, bio);
|
||||
cell_defer_no_holder_no_free(tc, &cell1);
|
||||
return DM_MAPIO_SUBMITTED;
|
||||
}
|
||||
/* fall through */
|
||||
|
@ -1996,6 +2002,7 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
|
|||
* provide the hint to load the metadata into cache.
|
||||
*/
|
||||
thin_defer_bio(tc, bio);
|
||||
cell_defer_no_holder_no_free(tc, &cell1);
|
||||
return DM_MAPIO_SUBMITTED;
|
||||
|
||||
default:
|
||||
|
@ -2005,6 +2012,7 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
|
|||
* pool is switched to fail-io mode.
|
||||
*/
|
||||
bio_io_error(bio);
|
||||
cell_defer_no_holder_no_free(tc, &cell1);
|
||||
return DM_MAPIO_SUBMITTED;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,12 @@ struct btree_node {
|
|||
} __packed;
|
||||
|
||||
|
||||
/*
|
||||
* Locks a block using the btree node validator.
|
||||
*/
|
||||
int bn_read_lock(struct dm_btree_info *info, dm_block_t b,
|
||||
struct dm_block **result);
|
||||
|
||||
void inc_children(struct dm_transaction_manager *tm, struct btree_node *n,
|
||||
struct dm_btree_value_type *vt);
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ struct dm_block_validator btree_node_validator = {
|
|||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
static int bn_read_lock(struct dm_btree_info *info, dm_block_t b,
|
||||
int bn_read_lock(struct dm_btree_info *info, dm_block_t b,
|
||||
struct dm_block **result)
|
||||
{
|
||||
return dm_tm_read_lock(info->tm, b, &btree_node_validator, result);
|
||||
|
|
|
@ -847,22 +847,26 @@ EXPORT_SYMBOL_GPL(dm_btree_find_lowest_key);
|
|||
* FIXME: We shouldn't use a recursive algorithm when we have limited stack
|
||||
* space. Also this only works for single level trees.
|
||||
*/
|
||||
static int walk_node(struct ro_spine *s, dm_block_t block,
|
||||
static int walk_node(struct dm_btree_info *info, dm_block_t block,
|
||||
int (*fn)(void *context, uint64_t *keys, void *leaf),
|
||||
void *context)
|
||||
{
|
||||
int r;
|
||||
unsigned i, nr;
|
||||
struct dm_block *node;
|
||||
struct btree_node *n;
|
||||
uint64_t keys;
|
||||
|
||||
r = ro_step(s, block);
|
||||
n = ro_node(s);
|
||||
r = bn_read_lock(info, block, &node);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
n = dm_block_data(node);
|
||||
|
||||
nr = le32_to_cpu(n->header.nr_entries);
|
||||
for (i = 0; i < nr; i++) {
|
||||
if (le32_to_cpu(n->header.flags) & INTERNAL_NODE) {
|
||||
r = walk_node(s, value64(n, i), fn, context);
|
||||
r = walk_node(info, value64(n, i), fn, context);
|
||||
if (r)
|
||||
goto out;
|
||||
} else {
|
||||
|
@ -874,7 +878,7 @@ static int walk_node(struct ro_spine *s, dm_block_t block,
|
|||
}
|
||||
|
||||
out:
|
||||
ro_pop(s);
|
||||
dm_tm_unlock(info->tm, node);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -882,15 +886,7 @@ int dm_btree_walk(struct dm_btree_info *info, dm_block_t root,
|
|||
int (*fn)(void *context, uint64_t *keys, void *leaf),
|
||||
void *context)
|
||||
{
|
||||
int r;
|
||||
struct ro_spine spine;
|
||||
|
||||
BUG_ON(info->levels > 1);
|
||||
|
||||
init_ro_spine(&spine, info);
|
||||
r = walk_node(&spine, root, fn, context);
|
||||
exit_ro_spine(&spine);
|
||||
|
||||
return r;
|
||||
return walk_node(info, root, fn, context);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dm_btree_walk);
|
||||
|
|
Загрузка…
Ссылка в новой задаче