aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorMartin K. Petersen <martin.petersen@oracle.com>2015-01-20 20:06:30 -0500
committerJens Axboe <axboe@fb.com>2015-01-21 12:41:46 -0500
commitd93ba7a5a97c9f315bacdcdb8de4e5f368e7b396 (patch)
tree08ed637d3982f9c87e5334d42e2f7a3670867876 /block
parentc6ce194325cef342313e3d27620411ce90a89c50 (diff)
block: Add discard flag to blkdev_issue_zeroout() function
blkdev_issue_discard() will zero a given block range. This is done by way of explicit writing, thus provisioning or allocating the blocks on disk. There are use cases where the desired behavior is to zero the blocks but unprovision them if possible. The blocks must deterministically contain zeroes when they are subsequently read back. This patch adds a flag to blkdev_issue_zeroout() that provides this variant. If the discard flag is set and a block device guarantees discard_zeroes_data we will use REQ_DISCARD to clear the block range. If the device does not support discard_zeroes_data or if the discard request fails we will fall back to first REQ_WRITE_SAME and then a regular REQ_WRITE. Also update the callers of blkdev_issue_zero() to reflect the new flag and make sb_issue_zeroout() prefer the discard approach. Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block')
-rw-r--r--block/blk-lib.c30
-rw-r--r--block/ioctl.c2
2 files changed, 27 insertions, 5 deletions
diff --git a/block/blk-lib.c b/block/blk-lib.c
index 8411be3c19d3..715e948f58a4 100644
--- a/block/blk-lib.c
+++ b/block/blk-lib.c
@@ -283,23 +283,45 @@ static int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
283 * @sector: start sector 283 * @sector: start sector
284 * @nr_sects: number of sectors to write 284 * @nr_sects: number of sectors to write
285 * @gfp_mask: memory allocation flags (for bio_alloc) 285 * @gfp_mask: memory allocation flags (for bio_alloc)
286 * @discard: whether to discard the block range
286 * 287 *
287 * Description: 288 * Description:
288 * Generate and issue number of bios with zerofiled pages. 289
290 * Zero-fill a block range. If the discard flag is set and the block
291 * device guarantees that subsequent READ operations to the block range
292 * in question will return zeroes, the blocks will be discarded. Should
293 * the discard request fail, if the discard flag is not set, or if
294 * discard_zeroes_data is not supported, this function will resort to
295 * zeroing the blocks manually, thus provisioning (allocating,
296 * anchoring) them. If the block device supports the WRITE SAME command
297 * blkdev_issue_zeroout() will use it to optimize the process of
298 * clearing the block range. Otherwise the zeroing will be performed
299 * using regular WRITE calls.
289 */ 300 */
290 301
291int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, 302int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
292 sector_t nr_sects, gfp_t gfp_mask) 303 sector_t nr_sects, gfp_t gfp_mask, bool discard)
293{ 304{
305 struct request_queue *q = bdev_get_queue(bdev);
306 unsigned char bdn[BDEVNAME_SIZE];
307
308 if (discard && blk_queue_discard(q) && q->limits.discard_zeroes_data) {
309
310 if (!blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask, 0))
311 return 0;
312
313 bdevname(bdev, bdn);
314 pr_warn("%s: DISCARD failed. Manually zeroing.\n", bdn);
315 }
316
294 if (bdev_write_same(bdev)) { 317 if (bdev_write_same(bdev)) {
295 unsigned char bdn[BDEVNAME_SIZE];
296 318
297 if (!blkdev_issue_write_same(bdev, sector, nr_sects, gfp_mask, 319 if (!blkdev_issue_write_same(bdev, sector, nr_sects, gfp_mask,
298 ZERO_PAGE(0))) 320 ZERO_PAGE(0)))
299 return 0; 321 return 0;
300 322
301 bdevname(bdev, bdn); 323 bdevname(bdev, bdn);
302 pr_err("%s: WRITE SAME failed. Manually zeroing.\n", bdn); 324 pr_warn("%s: WRITE SAME failed. Manually zeroing.\n", bdn);
303 } 325 }
304 326
305 return __blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask); 327 return __blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask);
diff --git a/block/ioctl.c b/block/ioctl.c
index 6c7bf903742f..7d8befde2aca 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -198,7 +198,7 @@ static int blk_ioctl_zeroout(struct block_device *bdev, uint64_t start,
198 if (start + len > (i_size_read(bdev->bd_inode) >> 9)) 198 if (start + len > (i_size_read(bdev->bd_inode) >> 9))
199 return -EINVAL; 199 return -EINVAL;
200 200
201 return blkdev_issue_zeroout(bdev, start, len, GFP_KERNEL); 201 return blkdev_issue_zeroout(bdev, start, len, GFP_KERNEL, false);
202} 202}
203 203
204static int put_ushort(unsigned long arg, unsigned short val) 204static int put_ushort(unsigned long arg, unsigned short val)