mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-26 19:19:32 +03:00
Align DISCARD requests on zvols.
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 <behlendorf1@llnl.gov> Closes #1010
This commit is contained in:
parent
31ab194297
commit
089fa91bc5
@ -597,8 +597,8 @@ zvol_discard(void *arg)
|
|||||||
struct request *req = (struct request *)arg;
|
struct request *req = (struct request *)arg;
|
||||||
struct request_queue *q = req->q;
|
struct request_queue *q = req->q;
|
||||||
zvol_state_t *zv = q->queuedata;
|
zvol_state_t *zv = q->queuedata;
|
||||||
uint64_t offset = blk_rq_pos(req) << 9;
|
uint64_t start = blk_rq_pos(req) << 9;
|
||||||
uint64_t size = blk_rq_bytes(req);
|
uint64_t end = start + blk_rq_bytes(req);
|
||||||
int error;
|
int error;
|
||||||
rl_t *rl;
|
rl_t *rl;
|
||||||
|
|
||||||
@ -610,19 +610,28 @@ zvol_discard(void *arg)
|
|||||||
ASSERT(!(current->flags & PF_NOFS));
|
ASSERT(!(current->flags & PF_NOFS));
|
||||||
current->flags |= PF_NOFS;
|
current->flags |= PF_NOFS;
|
||||||
|
|
||||||
if (offset + size > zv->zv_volsize) {
|
if (end > zv->zv_volsize) {
|
||||||
blk_end_request(req, -EIO, size);
|
blk_end_request(req, -EIO, blk_rq_bytes(req));
|
||||||
goto out;
|
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;
|
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.
|
* TODO: maybe we should add the operation to the log.
|
||||||
@ -630,7 +639,7 @@ zvol_discard(void *arg)
|
|||||||
|
|
||||||
zfs_range_unlock(rl);
|
zfs_range_unlock(rl);
|
||||||
|
|
||||||
blk_end_request(req, -error, size);
|
blk_end_request(req, -error, blk_rq_bytes(req));
|
||||||
out:
|
out:
|
||||||
current->flags &= ~PF_NOFS;
|
current->flags &= ~PF_NOFS;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user