Skip to content

Commit

Permalink
Align DISCARD requests on zvols.
Browse files Browse the repository at this point in the history
Currently, when processing DISCARD requests, zvol_discard() calls
dmu_free_long_range() with the precise offset and size of the request.

Unfortunately, this is not optimal for requests that are not aligned to
the zvol block boundaries. Indeed, in the case of an unaligned range,
dnode_free_range() will zero out the unaligned parts. Not only is this
useless since we are not freeing any space by doing so, it is also slow
because it translates to a read-modify-write operation.

This patch fixes the issue by rounding up the discard start offset to
the next volume block boundary, and rounding down the discard end
offset to the previous volume block boundary.

Signed-off-by: Brian Behlendorf <[email protected]>
Closes openzfs#1010
  • Loading branch information
dechamps authored and behlendorf committed Oct 4, 2012
1 parent 31ab194 commit 089fa91
Showing 1 changed file with 18 additions and 9 deletions.
27 changes: 18 additions & 9 deletions module/zfs/zvol.c
Original file line number Diff line number Diff line change
Expand Up @@ -597,8 +597,8 @@ zvol_discard(void *arg)
struct request *req = (struct request *)arg;
struct request_queue *q = req->q;
zvol_state_t *zv = q->queuedata;
uint64_t offset = blk_rq_pos(req) << 9;
uint64_t size = blk_rq_bytes(req);
uint64_t start = blk_rq_pos(req) << 9;
uint64_t end = start + blk_rq_bytes(req);
int error;
rl_t *rl;

Expand All @@ -610,27 +610,36 @@ zvol_discard(void *arg)
ASSERT(!(current->flags & PF_NOFS));
current->flags |= PF_NOFS;

if (offset + size > zv->zv_volsize) {
blk_end_request(req, -EIO, size);
if (end > zv->zv_volsize) {
blk_end_request(req, -EIO, blk_rq_bytes(req));
goto out;
}

if (size == 0) {
blk_end_request(req, 0, size);
/*
* Align the request to volume block boundaries. If we don't,
* then this will force dnode_free_range() to zero out the
* unaligned parts, which is slow (read-modify-write) and
* useless since we are not freeing any space by doing so.
*/
start = P2ROUNDUP(start, zv->zv_volblocksize);
end = P2ALIGN(end, zv->zv_volblocksize);

if (start >= end) {
blk_end_request(req, 0, blk_rq_bytes(req));
goto out;
}

rl = zfs_range_lock(&zv->zv_znode, offset, size, RL_WRITER);
rl = zfs_range_lock(&zv->zv_znode, start, end - start, RL_WRITER);

error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, offset, size);
error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, start, end - start);

/*
* TODO: maybe we should add the operation to the log.
*/

zfs_range_unlock(rl);

blk_end_request(req, -error, size);
blk_end_request(req, -error, blk_rq_bytes(req));
out:
current->flags &= ~PF_NOFS;
}
Expand Down

0 comments on commit 089fa91

Please sign in to comment.