aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMike Snitzer <snitzer@redhat.com>2012-12-21 15:23:37 -0500
committerAlasdair G Kergon <agk@redhat.com>2012-12-21 15:23:37 -0500
commit70d6c400acc386ea910c77318688541fc32e7ce8 (patch)
tree6ab32a9b9699656c8d9147b38a776f615c1c737a /drivers
parent4f0b70b0479101522b8645ddc1f5ee7137821db3 (diff)
dm kcopyd: add WRITE SAME support to dm_kcopyd_zero
Add WRITE SAME support to dm-io and make it accessible to dm_kcopyd_zero(). dm_kcopyd_zero() provides an asynchronous interface whereas the blkdev_issue_write_same() interface is synchronous. WRITE SAME is a SCSI command that can be leveraged for more efficient zeroing of a specified logical extent of a device which supports it. Only a single zeroed logical block is transfered to the target for each WRITE SAME and the target then writes that same block across the specified extent. The dm thin target uses this. Signed-off-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
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,