Skip to content

Commit 70d6c40

Browse files
snitmkergon
authored andcommitted
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 <[email protected]> Signed-off-by: Alasdair G Kergon <[email protected]>
1 parent 4f0b70b commit 70d6c40

File tree

3 files changed

+33
-10
lines changed

3 files changed

+33
-10
lines changed

drivers/md/dm-io.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,8 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
287287
unsigned num_bvecs;
288288
sector_t remaining = where->count;
289289
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;
291292

292293
/*
293294
* 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,
297298
/*
298299
* Allocate a suitably sized-bio.
299300
*/
300-
if (rw & REQ_DISCARD)
301+
if ((rw & REQ_DISCARD) || (rw & REQ_WRITE_SAME))
301302
num_bvecs = 1;
302303
else
303304
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,
310311
store_io_and_region_in_bio(bio, io, region);
311312

312313
if (rw & REQ_DISCARD) {
313-
discard_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining);
314-
bio->bi_size = discard_sectors << SECTOR_SHIFT;
315-
remaining -= discard_sectors;
314+
num_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining);
315+
bio->bi_size = num_sectors << SECTOR_SHIFT;
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);
316329
} else while (remaining) {
317330
/*
318331
* Try and add as many pages as possible.

drivers/md/dm-kcopyd.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ static void complete_io(unsigned long error, void *context)
349349
struct dm_kcopyd_client *kc = job->kc;
350350

351351
if (error) {
352-
if (job->rw == WRITE)
352+
if (job->rw & WRITE)
353353
job->write_err |= error;
354354
else
355355
job->read_err = 1;
@@ -361,7 +361,7 @@ static void complete_io(unsigned long error, void *context)
361361
}
362362
}
363363

364-
if (job->rw == WRITE)
364+
if (job->rw & WRITE)
365365
push(&kc->complete_jobs, job);
366366

367367
else {
@@ -432,7 +432,7 @@ static int process_jobs(struct list_head *jobs, struct dm_kcopyd_client *kc,
432432

433433
if (r < 0) {
434434
/* error this rogue job */
435-
if (job->rw == WRITE)
435+
if (job->rw & WRITE)
436436
job->write_err = (unsigned long) -1L;
437437
else
438438
job->read_err = 1;
@@ -585,6 +585,7 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
585585
unsigned int flags, dm_kcopyd_notify_fn fn, void *context)
586586
{
587587
struct kcopyd_job *job;
588+
int i;
588589

589590
/*
590591
* 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,
611612
memset(&job->source, 0, sizeof job->source);
612613
job->source.count = job->dests[0].count;
613614
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+
}
615625
}
616626

617627
job->fn = fn;

drivers/md/dm-thin.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2779,7 +2779,7 @@ static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
27792779

27802780
static struct target_type thin_target = {
27812781
.name = "thin",
2782-
.version = {1, 5, 0},
2782+
.version = {1, 6, 0},
27832783
.module = THIS_MODULE,
27842784
.ctr = thin_ctr,
27852785
.dtr = thin_dtr,

0 commit comments

Comments
 (0)