Skip to content

Commit e93dd91

Browse files
committed
Merge tag 'dm-3.12-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm
Pull device-mapper fixes from Mike Snitzer: "A few fixes for dm-snapshot, a 32 bit fix for dm-stats, a couple error handling fixes for dm-multipath. A fix for the thin provisioning target to not expose non-zero discard limits if discards are disabled. Lastly, add two DM module parameters which allow users to tune the emergency memory reserves that DM mainatins per device -- this helps fix a long-standing issue for dm-multipath. The conservative default reserve for request-based dm-multipath devices (256) has proven problematic for users with many multipathed SCSI devices but relatively little memory. To responsibly select a smaller value users should use the new nr_bios tracepoint info (via commit 75afb35 "block: Add nr_bios to block_rq_remap tracepoint") to determine the peak number of bios their workloads create" * tag 'dm-3.12-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm: dm: add reserved_bio_based_ios module parameter dm: add reserved_rq_based_ios module parameter dm: lower bio-based mempool reservation dm thin: do not expose non-zero discard limits if discards disabled dm mpath: disable WRITE SAME if it fails dm-snapshot: fix performance degradation due to small hash size dm snapshot: workaround for a false positive lockdep warning dm stats: fix possible counter corruption on 32-bit systems dm mpath: do not fail path on -ENOSPC
2 parents b482041 + e860313 commit e93dd91

File tree

9 files changed

+120
-26
lines changed

9 files changed

+120
-26
lines changed

drivers/md/dm-io.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
#define DM_MSG_PREFIX "io"
2020

2121
#define DM_IO_MAX_REGIONS BITS_PER_LONG
22-
#define MIN_IOS 16
23-
#define MIN_BIOS 16
2422

2523
struct dm_io_client {
2624
mempool_t *pool;
@@ -50,16 +48,17 @@ static struct kmem_cache *_dm_io_cache;
5048
struct dm_io_client *dm_io_client_create(void)
5149
{
5250
struct dm_io_client *client;
51+
unsigned min_ios = dm_get_reserved_bio_based_ios();
5352

5453
client = kmalloc(sizeof(*client), GFP_KERNEL);
5554
if (!client)
5655
return ERR_PTR(-ENOMEM);
5756

58-
client->pool = mempool_create_slab_pool(MIN_IOS, _dm_io_cache);
57+
client->pool = mempool_create_slab_pool(min_ios, _dm_io_cache);
5958
if (!client->pool)
6059
goto bad;
6160

62-
client->bios = bioset_create(MIN_BIOS, 0);
61+
client->bios = bioset_create(min_ios, 0);
6362
if (!client->bios)
6463
goto bad;
6564

drivers/md/dm-mpath.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <linux/device-mapper.h>
99

10+
#include "dm.h"
1011
#include "dm-path-selector.h"
1112
#include "dm-uevent.h"
1213

@@ -116,8 +117,6 @@ struct dm_mpath_io {
116117

117118
typedef int (*action_fn) (struct pgpath *pgpath);
118119

119-
#define MIN_IOS 256 /* Mempool size */
120-
121120
static struct kmem_cache *_mpio_cache;
122121

123122
static struct workqueue_struct *kmultipathd, *kmpath_handlerd;
@@ -190,6 +189,7 @@ static void free_priority_group(struct priority_group *pg,
190189
static struct multipath *alloc_multipath(struct dm_target *ti)
191190
{
192191
struct multipath *m;
192+
unsigned min_ios = dm_get_reserved_rq_based_ios();
193193

194194
m = kzalloc(sizeof(*m), GFP_KERNEL);
195195
if (m) {
@@ -202,7 +202,7 @@ static struct multipath *alloc_multipath(struct dm_target *ti)
202202
INIT_WORK(&m->trigger_event, trigger_event);
203203
init_waitqueue_head(&m->pg_init_wait);
204204
mutex_init(&m->work_mutex);
205-
m->mpio_pool = mempool_create_slab_pool(MIN_IOS, _mpio_cache);
205+
m->mpio_pool = mempool_create_slab_pool(min_ios, _mpio_cache);
206206
if (!m->mpio_pool) {
207207
kfree(m);
208208
return NULL;
@@ -1268,6 +1268,7 @@ static int noretry_error(int error)
12681268
case -EREMOTEIO:
12691269
case -EILSEQ:
12701270
case -ENODATA:
1271+
case -ENOSPC:
12711272
return 1;
12721273
}
12731274

@@ -1298,8 +1299,17 @@ static int do_end_io(struct multipath *m, struct request *clone,
12981299
if (!error && !clone->errors)
12991300
return 0; /* I/O complete */
13001301

1301-
if (noretry_error(error))
1302+
if (noretry_error(error)) {
1303+
if ((clone->cmd_flags & REQ_WRITE_SAME) &&
1304+
!clone->q->limits.max_write_same_sectors) {
1305+
struct queue_limits *limits;
1306+
1307+
/* device doesn't really support WRITE SAME, disable it */
1308+
limits = dm_get_queue_limits(dm_table_get_md(m->ti->table));
1309+
limits->max_write_same_sectors = 0;
1310+
}
13021311
return error;
1312+
}
13031313

13041314
if (mpio->pgpath)
13051315
fail_path(mpio->pgpath);

drivers/md/dm-snap-persistent.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int rw,
256256
*/
257257
INIT_WORK_ONSTACK(&req.work, do_metadata);
258258
queue_work(ps->metadata_wq, &req.work);
259-
flush_work(&req.work);
259+
flush_workqueue(ps->metadata_wq);
260260

261261
return req.result;
262262
}

drivers/md/dm-snap.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -725,17 +725,16 @@ static int calc_max_buckets(void)
725725
*/
726726
static int init_hash_tables(struct dm_snapshot *s)
727727
{
728-
sector_t hash_size, cow_dev_size, origin_dev_size, max_buckets;
728+
sector_t hash_size, cow_dev_size, max_buckets;
729729

730730
/*
731731
* Calculate based on the size of the original volume or
732732
* the COW volume...
733733
*/
734734
cow_dev_size = get_dev_size(s->cow->bdev);
735-
origin_dev_size = get_dev_size(s->origin->bdev);
736735
max_buckets = calc_max_buckets();
737736

738-
hash_size = min(origin_dev_size, cow_dev_size) >> s->store->chunk_shift;
737+
hash_size = cow_dev_size >> s->store->chunk_shift;
739738
hash_size = min(hash_size, max_buckets);
740739

741740
if (hash_size < 64)

drivers/md/dm-stats.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -451,19 +451,26 @@ static void dm_stat_for_entry(struct dm_stat *s, size_t entry,
451451
struct dm_stat_percpu *p;
452452

453453
/*
454-
* For strict correctness we should use local_irq_disable/enable
454+
* For strict correctness we should use local_irq_save/restore
455455
* instead of preempt_disable/enable.
456456
*
457-
* This is racy if the driver finishes bios from non-interrupt
458-
* context as well as from interrupt context or from more different
459-
* interrupts.
457+
* preempt_disable/enable is racy if the driver finishes bios
458+
* from non-interrupt context as well as from interrupt context
459+
* or from more different interrupts.
460460
*
461-
* However, the race only results in not counting some events,
462-
* so it is acceptable.
461+
* On 64-bit architectures the race only results in not counting some
462+
* events, so it is acceptable. On 32-bit architectures the race could
463+
* cause the counter going off by 2^32, so we need to do proper locking
464+
* there.
463465
*
464466
* part_stat_lock()/part_stat_unlock() have this race too.
465467
*/
468+
#if BITS_PER_LONG == 32
469+
unsigned long flags;
470+
local_irq_save(flags);
471+
#else
466472
preempt_disable();
473+
#endif
467474
p = &s->stat_percpu[smp_processor_id()][entry];
468475

469476
if (!end) {
@@ -478,7 +485,11 @@ static void dm_stat_for_entry(struct dm_stat *s, size_t entry,
478485
p->ticks[idx] += duration;
479486
}
480487

488+
#if BITS_PER_LONG == 32
489+
local_irq_restore(flags);
490+
#else
481491
preempt_enable();
492+
#endif
482493
}
483494

484495
static void __dm_stat_bio(struct dm_stat *s, unsigned long bi_rw,

drivers/md/dm-thin.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2095,6 +2095,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
20952095
* them down to the data device. The thin device's discard
20962096
* processing will cause mappings to be removed from the btree.
20972097
*/
2098+
ti->discard_zeroes_data_unsupported = true;
20982099
if (pf.discard_enabled && pf.discard_passdown) {
20992100
ti->num_discard_bios = 1;
21002101

@@ -2104,7 +2105,6 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
21042105
* thin devices' discard limits consistent).
21052106
*/
21062107
ti->discards_supported = true;
2107-
ti->discard_zeroes_data_unsupported = true;
21082108
}
21092109
ti->private = pt;
21102110

@@ -2689,8 +2689,16 @@ static void pool_io_hints(struct dm_target *ti, struct queue_limits *limits)
26892689
* They get transferred to the live pool in bind_control_target()
26902690
* called from pool_preresume().
26912691
*/
2692-
if (!pt->adjusted_pf.discard_enabled)
2692+
if (!pt->adjusted_pf.discard_enabled) {
2693+
/*
2694+
* Must explicitly disallow stacking discard limits otherwise the
2695+
* block layer will stack them if pool's data device has support.
2696+
* QUEUE_FLAG_DISCARD wouldn't be set but there is no way for the
2697+
* user to see that, so make sure to set all discard limits to 0.
2698+
*/
2699+
limits->discard_granularity = 0;
26932700
return;
2701+
}
26942702

26952703
disable_passdown_if_not_supported(pt);
26962704

@@ -2826,10 +2834,10 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
28262834
ti->per_bio_data_size = sizeof(struct dm_thin_endio_hook);
28272835

28282836
/* In case the pool supports discards, pass them on. */
2837+
ti->discard_zeroes_data_unsupported = true;
28292838
if (tc->pool->pf.discard_enabled) {
28302839
ti->discards_supported = true;
28312840
ti->num_discard_bios = 1;
2832-
ti->discard_zeroes_data_unsupported = true;
28332841
/* Discard bios must be split on a block boundary */
28342842
ti->split_discard_bios = true;
28352843
}

drivers/md/dm.c

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,55 @@ struct dm_md_mempools {
211211
struct bio_set *bs;
212212
};
213213

214-
#define MIN_IOS 256
214+
#define RESERVED_BIO_BASED_IOS 16
215+
#define RESERVED_REQUEST_BASED_IOS 256
216+
#define RESERVED_MAX_IOS 1024
215217
static struct kmem_cache *_io_cache;
216218
static struct kmem_cache *_rq_tio_cache;
217219

220+
/*
221+
* Bio-based DM's mempools' reserved IOs set by the user.
222+
*/
223+
static unsigned reserved_bio_based_ios = RESERVED_BIO_BASED_IOS;
224+
225+
/*
226+
* Request-based DM's mempools' reserved IOs set by the user.
227+
*/
228+
static unsigned reserved_rq_based_ios = RESERVED_REQUEST_BASED_IOS;
229+
230+
static unsigned __dm_get_reserved_ios(unsigned *reserved_ios,
231+
unsigned def, unsigned max)
232+
{
233+
unsigned ios = ACCESS_ONCE(*reserved_ios);
234+
unsigned modified_ios = 0;
235+
236+
if (!ios)
237+
modified_ios = def;
238+
else if (ios > max)
239+
modified_ios = max;
240+
241+
if (modified_ios) {
242+
(void)cmpxchg(reserved_ios, ios, modified_ios);
243+
ios = modified_ios;
244+
}
245+
246+
return ios;
247+
}
248+
249+
unsigned dm_get_reserved_bio_based_ios(void)
250+
{
251+
return __dm_get_reserved_ios(&reserved_bio_based_ios,
252+
RESERVED_BIO_BASED_IOS, RESERVED_MAX_IOS);
253+
}
254+
EXPORT_SYMBOL_GPL(dm_get_reserved_bio_based_ios);
255+
256+
unsigned dm_get_reserved_rq_based_ios(void)
257+
{
258+
return __dm_get_reserved_ios(&reserved_rq_based_ios,
259+
RESERVED_REQUEST_BASED_IOS, RESERVED_MAX_IOS);
260+
}
261+
EXPORT_SYMBOL_GPL(dm_get_reserved_rq_based_ios);
262+
218263
static int __init local_init(void)
219264
{
220265
int r = -ENOMEM;
@@ -2277,6 +2322,17 @@ struct target_type *dm_get_immutable_target_type(struct mapped_device *md)
22772322
return md->immutable_target_type;
22782323
}
22792324

2325+
/*
2326+
* The queue_limits are only valid as long as you have a reference
2327+
* count on 'md'.
2328+
*/
2329+
struct queue_limits *dm_get_queue_limits(struct mapped_device *md)
2330+
{
2331+
BUG_ON(!atomic_read(&md->holders));
2332+
return &md->queue->limits;
2333+
}
2334+
EXPORT_SYMBOL_GPL(dm_get_queue_limits);
2335+
22802336
/*
22812337
* Fully initialize a request-based queue (->elevator, ->request_fn, etc).
22822338
*/
@@ -2862,18 +2918,18 @@ struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity, u
28622918

28632919
if (type == DM_TYPE_BIO_BASED) {
28642920
cachep = _io_cache;
2865-
pool_size = 16;
2921+
pool_size = dm_get_reserved_bio_based_ios();
28662922
front_pad = roundup(per_bio_data_size, __alignof__(struct dm_target_io)) + offsetof(struct dm_target_io, clone);
28672923
} else if (type == DM_TYPE_REQUEST_BASED) {
28682924
cachep = _rq_tio_cache;
2869-
pool_size = MIN_IOS;
2925+
pool_size = dm_get_reserved_rq_based_ios();
28702926
front_pad = offsetof(struct dm_rq_clone_bio_info, clone);
28712927
/* per_bio_data_size is not used. See __bind_mempools(). */
28722928
WARN_ON(per_bio_data_size != 0);
28732929
} else
28742930
goto out;
28752931

2876-
pools->io_pool = mempool_create_slab_pool(MIN_IOS, cachep);
2932+
pools->io_pool = mempool_create_slab_pool(pool_size, cachep);
28772933
if (!pools->io_pool)
28782934
goto out;
28792935

@@ -2924,6 +2980,13 @@ module_exit(dm_exit);
29242980

29252981
module_param(major, uint, 0);
29262982
MODULE_PARM_DESC(major, "The major number of the device mapper");
2983+
2984+
module_param(reserved_bio_based_ios, uint, S_IRUGO | S_IWUSR);
2985+
MODULE_PARM_DESC(reserved_bio_based_ios, "Reserved IOs in bio-based mempools");
2986+
2987+
module_param(reserved_rq_based_ios, uint, S_IRUGO | S_IWUSR);
2988+
MODULE_PARM_DESC(reserved_rq_based_ios, "Reserved IOs in request-based mempools");
2989+
29272990
MODULE_DESCRIPTION(DM_NAME " driver");
29282991
MODULE_AUTHOR("Joe Thornber <[email protected]>");
29292992
MODULE_LICENSE("GPL");

drivers/md/dm.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ void dm_free_md_mempools(struct dm_md_mempools *pools);
184184
/*
185185
* Helpers that are used by DM core
186186
*/
187+
unsigned dm_get_reserved_bio_based_ios(void);
188+
unsigned dm_get_reserved_rq_based_ios(void);
189+
187190
static inline bool dm_message_test_buffer_overflow(char *result, unsigned maxlen)
188191
{
189192
return !maxlen || strlen(result) + 1 >= maxlen;

include/linux/device-mapper.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,13 +406,14 @@ int dm_noflush_suspending(struct dm_target *ti);
406406
union map_info *dm_get_mapinfo(struct bio *bio);
407407
union map_info *dm_get_rq_mapinfo(struct request *rq);
408408

409+
struct queue_limits *dm_get_queue_limits(struct mapped_device *md);
410+
409411
/*
410412
* Geometry functions.
411413
*/
412414
int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo);
413415
int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo);
414416

415-
416417
/*-----------------------------------------------------------------
417418
* Functions for manipulating device-mapper tables.
418419
*---------------------------------------------------------------*/

0 commit comments

Comments
 (0)