| From d11b82faede4a11fb4c38cc9f6db89eda2780788 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 30 Oct 2019 20:29:48 -0700 |
| Subject: loop: fix no-unmap write-zeroes request behavior |
| |
| From: Darrick J. Wong <darrick.wong@oracle.com> |
| |
| [ Upstream commit efcfec579f6139528c9e6925eca2bc4a36da65c6 ] |
| |
| Currently, if the loop device receives a WRITE_ZEROES request, it asks |
| the underlying filesystem to punch out the range. This behavior is |
| correct if unmapping is allowed. However, a NOUNMAP request means that |
| the caller doesn't want us to free the storage backing the range, so |
| punching out the range is incorrect behavior. |
| |
| To satisfy a NOUNMAP | WRITE_ZEROES request, loop should ask the |
| underlying filesystem to FALLOC_FL_ZERO_RANGE, which is (according to |
| the fallocate documentation) required to ensure that the entire range is |
| backed by real storage, which suffices for our purposes. |
| |
| Fixes: 19372e2769179dd ("loop: implement REQ_OP_WRITE_ZEROES") |
| Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> |
| Reviewed-by: Christoph Hellwig <hch@lst.de> |
| Signed-off-by: Jens Axboe <axboe@kernel.dk> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/block/loop.c | 26 ++++++++++++++++++-------- |
| 1 file changed, 18 insertions(+), 8 deletions(-) |
| |
| diff --git a/drivers/block/loop.c b/drivers/block/loop.c |
| index 126c2c514673..9cd231a27328 100644 |
| --- a/drivers/block/loop.c |
| +++ b/drivers/block/loop.c |
| @@ -416,18 +416,20 @@ out_free_page: |
| return ret; |
| } |
| |
| -static int lo_discard(struct loop_device *lo, struct request *rq, loff_t pos) |
| +static int lo_fallocate(struct loop_device *lo, struct request *rq, loff_t pos, |
| + int mode) |
| { |
| /* |
| - * We use punch hole to reclaim the free space used by the |
| - * image a.k.a. discard. However we do not support discard if |
| - * encryption is enabled, because it may give an attacker |
| - * useful information. |
| + * We use fallocate to manipulate the space mappings used by the image |
| + * a.k.a. discard/zerorange. However we do not support this if |
| + * encryption is enabled, because it may give an attacker useful |
| + * information. |
| */ |
| struct file *file = lo->lo_backing_file; |
| - int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE; |
| int ret; |
| |
| + mode |= FALLOC_FL_KEEP_SIZE; |
| + |
| if ((!file->f_op->fallocate) || lo->lo_encrypt_key_size) { |
| ret = -EOPNOTSUPP; |
| goto out; |
| @@ -596,9 +598,17 @@ static int do_req_filebacked(struct loop_device *lo, struct request *rq) |
| switch (req_op(rq)) { |
| case REQ_OP_FLUSH: |
| return lo_req_flush(lo, rq); |
| - case REQ_OP_DISCARD: |
| case REQ_OP_WRITE_ZEROES: |
| - return lo_discard(lo, rq, pos); |
| + /* |
| + * If the caller doesn't want deallocation, call zeroout to |
| + * write zeroes the range. Otherwise, punch them out. |
| + */ |
| + return lo_fallocate(lo, rq, pos, |
| + (rq->cmd_flags & REQ_NOUNMAP) ? |
| + FALLOC_FL_ZERO_RANGE : |
| + FALLOC_FL_PUNCH_HOLE); |
| + case REQ_OP_DISCARD: |
| + return lo_fallocate(lo, rq, pos, FALLOC_FL_PUNCH_HOLE); |
| case REQ_OP_WRITE: |
| if (lo->transfer) |
| return lo_write_transfer(lo, rq, pos); |
| -- |
| 2.20.1 |
| |