aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/dm-io.c23
-rw-r--r--drivers/md/dm-kcopyd.c18
-rw-r--r--drivers/md/dm-thin.c2
3 files changed, 33 insertions, 10 deletions
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index 1c46f97d6664..ea49834377c8 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -287,7 +287,8 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
287 unsigned num_bvecs; 287 unsigned num_bvecs;
288 sector_t remaining = where->count; 288 sector_t remaining = where->count;
289 struct request_queue *q = bdev_get_queue(where->bdev); 289 struct request_queue *q = bdev_get_queue(where->bdev);
290 sector_t discard_sectors; 290 unsigned short logical_block_size = queue_logical_block_size(q);
291 sector_t num_sectors;
291 292
292 /* 293 /*
293 * where->count may be zero if rw holds a flush and we need to 294 * where->count may be zero if rw holds a flush and we need to
@@ -297,7 +298,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
297 /* 298 /*
298 * Allocate a suitably sized-bio. 299 * Allocate a suitably sized-bio.
299 */ 300 */
300 if (rw & REQ_DISCARD) 301 if ((rw & REQ_DISCARD) || (rw & REQ_WRITE_SAME))
301 num_bvecs = 1; 302 num_bvecs = 1;
302 else 303 else
303 num_bvecs = min_t(int, bio_get_nr_vecs(where->bdev), 304 num_bvecs = min_t(int, bio_get_nr_vecs(where->bdev),
@@ -310,9 +311,21 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
310 store_io_and_region_in_bio(bio, io, region); 311 store_io_and_region_in_bio(bio, io, region);
311 312
312 if (rw & REQ_DISCARD) { 313 if (rw & REQ_DISCARD) {
313 discard_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining); 314 num_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining);
314 bio->bi_size = discard_sectors << SECTOR_SHIFT; 315 bio->bi_size = num_sectors << SECTOR_SHIFT;
315 remaining -= discard_sectors; 316 remaining -= num_sectors;
317 } else if (rw & REQ_WRITE_SAME) {
318 /*
319 * WRITE SAME only uses a single page.
320 */
321 dp->get_page(dp, &page, &len, &offset);
322 bio_add_page(bio, page, logical_block_size, offset);
323 num_sectors = min_t(sector_t, q->limits.max_write_same_sectors, remaining);
324 bio->bi_size = num_sectors << SECTOR_SHIFT;
325
326 offset = 0;
327 remaining -= num_sectors;
328 dp->next_page(dp);
316 } else while (remaining) { 329 } else while (remaining) {
317 /* 330 /*
318 * Try and add as many pages as possible. 331 * Try and add as many pages as possible.
diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c
index bed444c93d8d..68c02673263b 100644
--- a/drivers/md/dm-kcopyd.c
+++ b/drivers/md/dm-kcopyd.c
@@ -349,7 +349,7 @@ static void complete_io(unsigned long error, void *context)
349 struct dm_kcopyd_client *kc = job->kc; 349 struct dm_kcopyd_client *kc = job->kc;
350 350
351 if (error) { 351 if (error) {
352 if (job->rw == WRITE) 352 if (job->rw & WRITE)
353 job->write_err |= error; 353 job->write_err |= error;
354 else 354 else
355 job->read_err = 1; 355 job->read_err = 1;
@@ -361,7 +361,7 @@ static void complete_io(unsigned long error, void *context)
361 } 361 }
362 } 362 }
363 363
364 if (job->rw == WRITE) 364 if (job->rw & WRITE)
365 push(&kc->complete_jobs, job); 365 push(&kc->complete_jobs, job);
366 366
367 else { 367 else {
@@ -432,7 +432,7 @@ static int process_jobs(struct list_head *jobs, struct dm_kcopyd_client *kc,
432 432
433 if (r < 0) { 433 if (r < 0) {
434 /* error this rogue job */ 434 /* error this rogue job */
435 if (job->rw == WRITE) 435 if (job->rw & WRITE)
436 job->write_err = (unsigned long) -1L; 436 job->write_err = (unsigned long) -1L;
437 else 437 else
438 job->read_err = 1; 438 job->read_err = 1;
@@ -585,6 +585,7 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
585 unsigned int flags, dm_kcopyd_notify_fn fn, void *context) 585 unsigned int flags, dm_kcopyd_notify_fn fn, void *context)
586{ 586{
587 struct kcopyd_job *job; 587 struct kcopyd_job *job;
588 int i;
588 589
589 /* 590 /*
590 * Allocate an array of jobs consisting of one master job 591 * Allocate an array of jobs consisting of one master job
@@ -611,7 +612,16 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
611 memset(&job->source, 0, sizeof job->source); 612 memset(&job->source, 0, sizeof job->source);
612 job->source.count = job->dests[0].count; 613 job->source.count = job->dests[0].count;
613 job->pages = &zero_page_list; 614 job->pages = &zero_page_list;
614 job->rw = WRITE; 615
616 /*
617 * Use WRITE SAME to optimize zeroing if all dests support it.
618 */
619 job->rw = WRITE | REQ_WRITE_SAME;
620 for (i = 0; i < job->num_dests; i++)
621 if (!bdev_write_same(job->dests[i].bdev)) {
622 job->rw = WRITE;
623 break;
624 }
615 } 625 }
616 626
617 job->fn = fn; 627 job->fn = fn;
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index fba378f234a5..4b940745ba9e 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -2779,7 +2779,7 @@ static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
2779 2779
2780static struct target_type thin_target = { 2780static struct target_type thin_target = {
2781 .name = "thin", 2781 .name = "thin",
2782 .version = {1, 5, 0}, 2782 .version = {1, 6, 0},
2783 .module = THIS_MODULE, 2783 .module = THIS_MODULE,
2784 .ctr = thin_ctr, 2784 .ctr = thin_ctr,
2785 .dtr = thin_dtr, 2785 .dtr = thin_dtr,