Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e93dd910 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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 75afb352
  "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
parents b4820416 e8603136
Loading
Loading
Loading
Loading
+3 −4
Original line number Original line Diff line number Diff line
@@ -19,8 +19,6 @@
#define DM_MSG_PREFIX "io"
#define DM_MSG_PREFIX "io"


#define DM_IO_MAX_REGIONS	BITS_PER_LONG
#define DM_IO_MAX_REGIONS	BITS_PER_LONG
#define MIN_IOS		16
#define MIN_BIOS	16


struct dm_io_client {
struct dm_io_client {
	mempool_t *pool;
	mempool_t *pool;
@@ -50,16 +48,17 @@ static struct kmem_cache *_dm_io_cache;
struct dm_io_client *dm_io_client_create(void)
struct dm_io_client *dm_io_client_create(void)
{
{
	struct dm_io_client *client;
	struct dm_io_client *client;
	unsigned min_ios = dm_get_reserved_bio_based_ios();


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


	client->pool = mempool_create_slab_pool(MIN_IOS, _dm_io_cache);
	client->pool = mempool_create_slab_pool(min_ios, _dm_io_cache);
	if (!client->pool)
	if (!client->pool)
		goto bad;
		goto bad;


	client->bios = bioset_create(MIN_BIOS, 0);
	client->bios = bioset_create(min_ios, 0);
	if (!client->bios)
	if (!client->bios)
		goto bad;
		goto bad;


+14 −4
Original line number Original line Diff line number Diff line
@@ -7,6 +7,7 @@


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


#include "dm.h"
#include "dm-path-selector.h"
#include "dm-path-selector.h"
#include "dm-uevent.h"
#include "dm-uevent.h"


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


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


#define MIN_IOS 256	/* Mempool size */

static struct kmem_cache *_mpio_cache;
static struct kmem_cache *_mpio_cache;


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


	m = kzalloc(sizeof(*m), GFP_KERNEL);
	m = kzalloc(sizeof(*m), GFP_KERNEL);
	if (m) {
	if (m) {
@@ -202,7 +202,7 @@ static struct multipath *alloc_multipath(struct dm_target *ti)
		INIT_WORK(&m->trigger_event, trigger_event);
		INIT_WORK(&m->trigger_event, trigger_event);
		init_waitqueue_head(&m->pg_init_wait);
		init_waitqueue_head(&m->pg_init_wait);
		mutex_init(&m->work_mutex);
		mutex_init(&m->work_mutex);
		m->mpio_pool = mempool_create_slab_pool(MIN_IOS, _mpio_cache);
		m->mpio_pool = mempool_create_slab_pool(min_ios, _mpio_cache);
		if (!m->mpio_pool) {
		if (!m->mpio_pool) {
			kfree(m);
			kfree(m);
			return NULL;
			return NULL;
@@ -1268,6 +1268,7 @@ static int noretry_error(int error)
	case -EREMOTEIO:
	case -EREMOTEIO:
	case -EILSEQ:
	case -EILSEQ:
	case -ENODATA:
	case -ENODATA:
	case -ENOSPC:
		return 1;
		return 1;
	}
	}


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


	if (noretry_error(error))
	if (noretry_error(error)) {
		if ((clone->cmd_flags & REQ_WRITE_SAME) &&
		    !clone->q->limits.max_write_same_sectors) {
			struct queue_limits *limits;

			/* device doesn't really support WRITE SAME, disable it */
			limits = dm_get_queue_limits(dm_table_get_md(m->ti->table));
			limits->max_write_same_sectors = 0;
		}
		return error;
		return error;
	}


	if (mpio->pgpath)
	if (mpio->pgpath)
		fail_path(mpio->pgpath);
		fail_path(mpio->pgpath);
+1 −1
Original line number Original line Diff line number Diff line
@@ -256,7 +256,7 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int rw,
	 */
	 */
	INIT_WORK_ONSTACK(&req.work, do_metadata);
	INIT_WORK_ONSTACK(&req.work, do_metadata);
	queue_work(ps->metadata_wq, &req.work);
	queue_work(ps->metadata_wq, &req.work);
	flush_work(&req.work);
	flush_workqueue(ps->metadata_wq);


	return req.result;
	return req.result;
}
}
+2 −3
Original line number Original line Diff line number Diff line
@@ -725,17 +725,16 @@ static int calc_max_buckets(void)
 */
 */
static int init_hash_tables(struct dm_snapshot *s)
static int init_hash_tables(struct dm_snapshot *s)
{
{
	sector_t hash_size, cow_dev_size, origin_dev_size, max_buckets;
	sector_t hash_size, cow_dev_size, max_buckets;


	/*
	/*
	 * Calculate based on the size of the original volume or
	 * Calculate based on the size of the original volume or
	 * the COW volume...
	 * the COW volume...
	 */
	 */
	cow_dev_size = get_dev_size(s->cow->bdev);
	cow_dev_size = get_dev_size(s->cow->bdev);
	origin_dev_size = get_dev_size(s->origin->bdev);
	max_buckets = calc_max_buckets();
	max_buckets = calc_max_buckets();


	hash_size = min(origin_dev_size, cow_dev_size) >> s->store->chunk_shift;
	hash_size = cow_dev_size >> s->store->chunk_shift;
	hash_size = min(hash_size, max_buckets);
	hash_size = min(hash_size, max_buckets);


	if (hash_size < 64)
	if (hash_size < 64)
+17 −6
Original line number Original line Diff line number Diff line
@@ -451,19 +451,26 @@ static void dm_stat_for_entry(struct dm_stat *s, size_t entry,
	struct dm_stat_percpu *p;
	struct dm_stat_percpu *p;


	/*
	/*
	 * For strict correctness we should use local_irq_disable/enable
	 * For strict correctness we should use local_irq_save/restore
	 * instead of preempt_disable/enable.
	 * instead of preempt_disable/enable.
	 *
	 *
	 * This is racy if the driver finishes bios from non-interrupt
	 * preempt_disable/enable is racy if the driver finishes bios
	 * context as well as from interrupt context or from more different
	 * from non-interrupt context as well as from interrupt context
	 * interrupts.
	 * or from more different interrupts.
	 *
	 *
	 * However, the race only results in not counting some events,
	 * On 64-bit architectures the race only results in not counting some
	 * so it is acceptable.
	 * events, so it is acceptable.  On 32-bit architectures the race could
	 * cause the counter going off by 2^32, so we need to do proper locking
	 * there.
	 *
	 *
	 * part_stat_lock()/part_stat_unlock() have this race too.
	 * part_stat_lock()/part_stat_unlock() have this race too.
	 */
	 */
#if BITS_PER_LONG == 32
	unsigned long flags;
	local_irq_save(flags);
#else
	preempt_disable();
	preempt_disable();
#endif
	p = &s->stat_percpu[smp_processor_id()][entry];
	p = &s->stat_percpu[smp_processor_id()][entry];


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


#if BITS_PER_LONG == 32
	local_irq_restore(flags);
#else
	preempt_enable();
	preempt_enable();
#endif
}
}


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