Skip to content

Commit

Permalink
Merge tag 'for-4.21/dm-changes' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/kernel/git/device-mapper/linux-dm

Pull device mapper updates from Mike Snitzer:

 - Eliminate a couple indirect calls from bio-based DM core.

 - Fix DM to allow reads that exceed readahead limits by setting
   io_pages in the backing_dev_info.

 - A couple code cleanups in request-based DM.

 - Fix various DM targets to check for device sector overflow if
   CONFIG_LBDAF is not set.

 - Use u64 instead of sector_t to store iv_offset in DM crypt; sector_t
   isn't large enough on 32bit when CONFIG_LBDAF is not set.

 - Performance fixes to DM's kcopyd and the snapshot target focused on
   limiting memory use and workqueue stalls.

 - Fix typos in the integrity and writecache targets.

 - Log which algorithm is used for dm-crypt's encryption and
   dm-integrity's hashing.

 - Fix false -EBUSY errors in DM raid target's handling of check/repair
   messages.

 - Fix DM flakey target's corrupt_bio_byte feature to reliably corrupt
   the Nth byte in a bio's payload.

* tag 'for-4.21/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
  dm: do not allow readahead to limit IO size
  dm raid: fix false -EBUSY when handling check/repair message
  dm rq: cleanup leftover code from recently removed q->mq_ops branching
  dm verity: log the hash algorithm implementation
  dm crypt: log the encryption algorithm implementation
  dm integrity: fix spelling mistake in workqueue name
  dm flakey: Properly corrupt multi-page bios.
  dm: Check for device sector overflow if CONFIG_LBDAF is not set
  dm crypt: use u64 instead of sector_t to store iv_offset
  dm kcopyd: Fix bug causing workqueue stalls
  dm snapshot: Fix excessive memory usage and workqueue stalls
  dm bufio: update comment in dm-bufio.c
  dm writecache: fix typo in error msg for creating writecache_flush_thread
  dm: remove indirect calls from __send_changing_extent_only()
  dm mpath: only flush workqueue when needed
  dm rq: remove unused arguments from rq_completed()
  dm: avoid indirect call in __dm_make_request
  • Loading branch information
torvalds committed Dec 28, 2018
2 parents 5d24ae6 + c6d6e9b commit 4ed7bdc
Show file tree
Hide file tree
Showing 17 changed files with 121 additions and 82 deletions.
12 changes: 6 additions & 6 deletions drivers/md/dm-bufio.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@

/*
* Linking of buffers:
* All buffers are linked to cache_hash with their hash_list field.
* All buffers are linked to buffer_tree with their node field.
*
* Clean buffers that are not being written (B_WRITING not set)
* are linked to lru[LIST_CLEAN] with their lru_list field.
Expand Down Expand Up @@ -457,7 +457,7 @@ static void free_buffer(struct dm_buffer *b)
}

/*
* Link buffer to the hash list and clean or dirty queue.
* Link buffer to the buffer tree and clean or dirty queue.
*/
static void __link_buffer(struct dm_buffer *b, sector_t block, int dirty)
{
Expand All @@ -472,7 +472,7 @@ static void __link_buffer(struct dm_buffer *b, sector_t block, int dirty)
}

/*
* Unlink buffer from the hash list and dirty or clean queue.
* Unlink buffer from the buffer tree and dirty or clean queue.
*/
static void __unlink_buffer(struct dm_buffer *b)
{
Expand Down Expand Up @@ -993,7 +993,7 @@ static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,

/*
* We've had a period where the mutex was unlocked, so need to
* recheck the hash table.
* recheck the buffer tree.
*/
b = __find(c, block);
if (b) {
Expand Down Expand Up @@ -1327,7 +1327,7 @@ int dm_bufio_write_dirty_buffers(struct dm_bufio_client *c)
EXPORT_SYMBOL_GPL(dm_bufio_write_dirty_buffers);

/*
* Use dm-io to send and empty barrier flush the device.
* Use dm-io to send an empty barrier to flush the device.
*/
int dm_bufio_issue_flush(struct dm_bufio_client *c)
{
Expand Down Expand Up @@ -1356,7 +1356,7 @@ EXPORT_SYMBOL_GPL(dm_bufio_issue_flush);
* Then, we write the buffer to the original location if it was dirty.
*
* Then, if we are the only one who is holding the buffer, relink the buffer
* in the hash queue for the new location.
* in the buffer tree for the new location.
*
* If there was someone else holding the buffer, we write it to the new
* location but not relink it, because that other user needs to have the buffer
Expand Down
17 changes: 13 additions & 4 deletions drivers/md/dm-crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ struct convert_context {
struct bio *bio_out;
struct bvec_iter iter_in;
struct bvec_iter iter_out;
sector_t cc_sector;
u64 cc_sector;
atomic_t cc_pending;
union {
struct skcipher_request *req;
Expand Down Expand Up @@ -81,7 +81,7 @@ struct dm_crypt_request {
struct convert_context *ctx;
struct scatterlist sg_in[4];
struct scatterlist sg_out[4];
sector_t iv_sector;
u64 iv_sector;
};

struct crypt_config;
Expand Down Expand Up @@ -160,7 +160,7 @@ struct crypt_config {
struct iv_lmk_private lmk;
struct iv_tcw_private tcw;
} iv_gen_private;
sector_t iv_offset;
u64 iv_offset;
unsigned int iv_size;
unsigned short int sector_size;
unsigned char sector_shift;
Expand Down Expand Up @@ -1885,6 +1885,13 @@ static int crypt_alloc_tfms_skcipher(struct crypt_config *cc, char *ciphermode)
}
}

/*
* dm-crypt performance can vary greatly depending on which crypto
* algorithm implementation is used. Help people debug performance
* problems by logging the ->cra_driver_name.
*/
DMINFO("%s using implementation \"%s\"", ciphermode,
crypto_skcipher_alg(any_tfm(cc))->base.cra_driver_name);
return 0;
}

Expand All @@ -1903,6 +1910,8 @@ static int crypt_alloc_tfms_aead(struct crypt_config *cc, char *ciphermode)
return err;
}

DMINFO("%s using implementation \"%s\"", ciphermode,
crypto_aead_alg(any_tfm_aead(cc))->base.cra_driver_name);
return 0;
}

Expand Down Expand Up @@ -2781,7 +2790,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}

ret = -EINVAL;
if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1 || tmpll != (sector_t)tmpll) {
ti->error = "Invalid device sector";
goto bad;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/md/dm-delay.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ static int delay_class_ctr(struct dm_target *ti, struct delay_class *c, char **a
unsigned long long tmpll;
char dummy;

if (sscanf(argv[1], "%llu%c", &tmpll, &dummy) != 1) {
if (sscanf(argv[1], "%llu%c", &tmpll, &dummy) != 1 || tmpll != (sector_t)tmpll) {
ti->error = "Invalid device sector";
return -EINVAL;
}
Expand Down
35 changes: 23 additions & 12 deletions drivers/md/dm-flakey.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
devname = dm_shift_arg(&as);

r = -EINVAL;
if (sscanf(dm_shift_arg(&as), "%llu%c", &tmpll, &dummy) != 1) {
if (sscanf(dm_shift_arg(&as), "%llu%c", &tmpll, &dummy) != 1 || tmpll != (sector_t)tmpll) {
ti->error = "Invalid device sector";
goto bad;
}
Expand Down Expand Up @@ -287,20 +287,31 @@ static void flakey_map_bio(struct dm_target *ti, struct bio *bio)

static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc)
{
unsigned bio_bytes = bio_cur_bytes(bio);
char *data = bio_data(bio);
unsigned int corrupt_bio_byte = fc->corrupt_bio_byte - 1;

struct bvec_iter iter;
struct bio_vec bvec;

if (!bio_has_data(bio))
return;

/*
* Overwrite the Nth byte of the data returned.
* Overwrite the Nth byte of the bio's data, on whichever page
* it falls.
*/
if (data && bio_bytes >= fc->corrupt_bio_byte) {
data[fc->corrupt_bio_byte - 1] = fc->corrupt_bio_value;

DMDEBUG("Corrupting data bio=%p by writing %u to byte %u "
"(rw=%c bi_opf=%u bi_sector=%llu cur_bytes=%u)\n",
bio, fc->corrupt_bio_value, fc->corrupt_bio_byte,
(bio_data_dir(bio) == WRITE) ? 'w' : 'r', bio->bi_opf,
(unsigned long long)bio->bi_iter.bi_sector, bio_bytes);
bio_for_each_segment(bvec, bio, iter) {
if (bio_iter_len(bio, iter) > corrupt_bio_byte) {
char *segment = (page_address(bio_iter_page(bio, iter))
+ bio_iter_offset(bio, iter));
segment[corrupt_bio_byte] = fc->corrupt_bio_value;
DMDEBUG("Corrupting data bio=%p by writing %u to byte %u "
"(rw=%c bi_opf=%u bi_sector=%llu size=%u)\n",
bio, fc->corrupt_bio_value, fc->corrupt_bio_byte,
(bio_data_dir(bio) == WRITE) ? 'w' : 'r', bio->bi_opf,
(unsigned long long)bio->bi_iter.bi_sector, bio->bi_iter.bi_size);
break;
}
corrupt_bio_byte -= bio_iter_len(bio, iter);
}
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/md/dm-integrity.c
Original file line number Diff line number Diff line change
Expand Up @@ -3460,7 +3460,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
ti->error = "Recalculate is only valid with internal hash";
goto bad;
}
ic->recalc_wq = alloc_workqueue("dm-intergrity-recalc", WQ_MEM_RECLAIM, 1);
ic->recalc_wq = alloc_workqueue("dm-integrity-recalc", WQ_MEM_RECLAIM, 1);
if (!ic->recalc_wq ) {
ti->error = "Cannot allocate workqueue";
r = -ENOMEM;
Expand Down
19 changes: 14 additions & 5 deletions drivers/md/dm-kcopyd.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,17 @@ struct dm_kcopyd_client {
atomic_t nr_jobs;

/*
* We maintain three lists of jobs:
* We maintain four lists of jobs:
*
* i) jobs waiting for pages
* ii) jobs that have pages, and are waiting for the io to be issued.
* iii) jobs that have completed.
* iii) jobs that don't need to do any IO and just run a callback
* iv) jobs that have completed.
*
* All three of these are protected by job_lock.
* All four of these are protected by job_lock.
*/
spinlock_t job_lock;
struct list_head callback_jobs;
struct list_head complete_jobs;
struct list_head io_jobs;
struct list_head pages_jobs;
Expand Down Expand Up @@ -625,6 +627,7 @@ static void do_work(struct work_struct *work)
struct dm_kcopyd_client *kc = container_of(work,
struct dm_kcopyd_client, kcopyd_work);
struct blk_plug plug;
unsigned long flags;

/*
* The order that these are called is *very* important.
Expand All @@ -633,6 +636,10 @@ static void do_work(struct work_struct *work)
* list. io jobs call wake when they complete and it all
* starts again.
*/
spin_lock_irqsave(&kc->job_lock, flags);
list_splice_tail_init(&kc->callback_jobs, &kc->complete_jobs);
spin_unlock_irqrestore(&kc->job_lock, flags);

blk_start_plug(&plug);
process_jobs(&kc->complete_jobs, kc, run_complete_job);
process_jobs(&kc->pages_jobs, kc, run_pages_job);
Expand All @@ -650,7 +657,7 @@ static void dispatch_job(struct kcopyd_job *job)
struct dm_kcopyd_client *kc = job->kc;
atomic_inc(&kc->nr_jobs);
if (unlikely(!job->source.count))
push(&kc->complete_jobs, job);
push(&kc->callback_jobs, job);
else if (job->pages == &zero_page_list)
push(&kc->io_jobs, job);
else
Expand Down Expand Up @@ -858,7 +865,7 @@ void dm_kcopyd_do_callback(void *j, int read_err, unsigned long write_err)
job->read_err = read_err;
job->write_err = write_err;

push(&kc->complete_jobs, job);
push(&kc->callback_jobs, job);
wake(kc);
}
EXPORT_SYMBOL(dm_kcopyd_do_callback);
Expand Down Expand Up @@ -888,6 +895,7 @@ struct dm_kcopyd_client *dm_kcopyd_client_create(struct dm_kcopyd_throttle *thro
return ERR_PTR(-ENOMEM);

spin_lock_init(&kc->job_lock);
INIT_LIST_HEAD(&kc->callback_jobs);
INIT_LIST_HEAD(&kc->complete_jobs);
INIT_LIST_HEAD(&kc->io_jobs);
INIT_LIST_HEAD(&kc->pages_jobs);
Expand Down Expand Up @@ -939,6 +947,7 @@ void dm_kcopyd_client_destroy(struct dm_kcopyd_client *kc)
/* Wait for completion of all jobs submitted by this client. */
wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs));

BUG_ON(!list_empty(&kc->callback_jobs));
BUG_ON(!list_empty(&kc->complete_jobs));
BUG_ON(!list_empty(&kc->io_jobs));
BUG_ON(!list_empty(&kc->pages_jobs));
Expand Down
2 changes: 1 addition & 1 deletion drivers/md/dm-linear.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}

ret = -EINVAL;
if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1) {
if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1 || tmp != (sector_t)tmp) {
ti->error = "Invalid device sector";
goto bad;
}
Expand Down
6 changes: 4 additions & 2 deletions drivers/md/dm-mpath.c
Original file line number Diff line number Diff line change
Expand Up @@ -1211,14 +1211,16 @@ static void flush_multipath_work(struct multipath *m)
set_bit(MPATHF_PG_INIT_DISABLED, &m->flags);
smp_mb__after_atomic();

flush_workqueue(kmpath_handlerd);
if (atomic_read(&m->pg_init_in_progress))
flush_workqueue(kmpath_handlerd);
multipath_wait_for_pg_init_completion(m);

clear_bit(MPATHF_PG_INIT_DISABLED, &m->flags);
smp_mb__after_atomic();
}

flush_workqueue(kmultipathd);
if (m->queue_mode == DM_TYPE_BIO_BASED)
flush_work(&m->process_queued_bios);
flush_work(&m->trigger_event);
}

Expand Down
3 changes: 1 addition & 2 deletions drivers/md/dm-raid.c
Original file line number Diff line number Diff line change
Expand Up @@ -3690,8 +3690,7 @@ static int raid_message(struct dm_target *ti, unsigned int argc, char **argv,
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
md_reap_sync_thread(mddev);
}
} else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
} else if (decipher_sync_action(mddev, mddev->recovery) != st_idle)
return -EBUSY;
else if (!strcasecmp(argv[0], "resync"))
; /* MD_RECOVERY_NEEDED set below */
Expand Down
3 changes: 2 additions & 1 deletion drivers/md/dm-raid1.c
Original file line number Diff line number Diff line change
Expand Up @@ -943,7 +943,8 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
char dummy;
int ret;

if (sscanf(argv[1], "%llu%c", &offset, &dummy) != 1) {
if (sscanf(argv[1], "%llu%c", &offset, &dummy) != 1 ||
offset != (sector_t)offset) {
ti->error = "Invalid offset";
return -EINVAL;
}
Expand Down
18 changes: 6 additions & 12 deletions drivers/md/dm-rq.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ static void rq_end_stats(struct mapped_device *md, struct request *orig)
* the md may be freed in dm_put() at the end of this function.
* Or do dm_get() before calling this function and dm_put() later.
*/
static void rq_completed(struct mapped_device *md, int rw, bool run_queue)
static void rq_completed(struct mapped_device *md)
{
/* nudge anyone waiting on suspend queue */
if (unlikely(waitqueue_active(&md->wait)))
Expand All @@ -147,7 +147,6 @@ static void rq_completed(struct mapped_device *md, int rw, bool run_queue)
*/
static void dm_end_request(struct request *clone, blk_status_t error)
{
int rw = rq_data_dir(clone);
struct dm_rq_target_io *tio = clone->end_io_data;
struct mapped_device *md = tio->md;
struct request *rq = tio->orig;
Expand All @@ -157,7 +156,7 @@ static void dm_end_request(struct request *clone, blk_status_t error)

rq_end_stats(md, rq);
blk_mq_end_request(rq, error);
rq_completed(md, rw, true);
rq_completed(md);
}

static void __dm_mq_kick_requeue_list(struct request_queue *q, unsigned long msecs)
Expand All @@ -181,7 +180,6 @@ static void dm_requeue_original_request(struct dm_rq_target_io *tio, bool delay_
{
struct mapped_device *md = tio->md;
struct request *rq = tio->orig;
int rw = rq_data_dir(rq);
unsigned long delay_ms = delay_requeue ? 100 : 0;

rq_end_stats(md, rq);
Expand All @@ -191,7 +189,7 @@ static void dm_requeue_original_request(struct dm_rq_target_io *tio, bool delay_
}

dm_mq_delay_requeue_request(rq, delay_ms);
rq_completed(md, rw, false);
rq_completed(md);
}

static void dm_done(struct request *clone, blk_status_t error, bool mapped)
Expand Down Expand Up @@ -246,15 +244,13 @@ static void dm_softirq_done(struct request *rq)
bool mapped = true;
struct dm_rq_target_io *tio = tio_from_request(rq);
struct request *clone = tio->clone;
int rw;

if (!clone) {
struct mapped_device *md = tio->md;

rq_end_stats(md, rq);
rw = rq_data_dir(rq);
blk_mq_end_request(rq, tio->error);
rq_completed(md, rw, false);
rq_completed(md);
return;
}

Expand Down Expand Up @@ -376,7 +372,6 @@ static int map_request(struct dm_rq_target_io *tio)
blk_status_t ret;

r = ti->type->clone_and_map_rq(ti, rq, &tio->info, &clone);
check_again:
switch (r) {
case DM_MAPIO_SUBMITTED:
/* The target has taken the I/O to submit by itself later */
Expand All @@ -396,8 +391,7 @@ static int map_request(struct dm_rq_target_io *tio)
blk_rq_unprep_clone(clone);
tio->ti->type->release_clone_rq(clone);
tio->clone = NULL;
r = DM_MAPIO_REQUEUE;
goto check_again;
return DM_MAPIO_REQUEUE;
}
break;
case DM_MAPIO_REQUEUE:
Expand Down Expand Up @@ -507,7 +501,7 @@ static blk_status_t dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
if (map_request(tio) == DM_MAPIO_REQUEUE) {
/* Undo dm_start_request() before requeuing */
rq_end_stats(md, rq);
rq_completed(md, rq_data_dir(rq), false);
rq_completed(md);
return BLK_STS_RESOURCE;
}

Expand Down
Loading

0 comments on commit 4ed7bdc

Please sign in to comment.