Skip to content

Commit

Permalink
Improvements and taskq enablement
Browse files Browse the repository at this point in the history
Signed-off-by: Ameer Hamza <[email protected]>
  • Loading branch information
ixhamza committed Nov 28, 2024
1 parent 9cdc045 commit 9c82f04
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 75 deletions.
156 changes: 85 additions & 71 deletions module/os/linux/zfs/zvol_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -503,50 +503,52 @@ zvol_read_task(void *arg)
zv_request_task_free(task);
}

static int zvol_setup_copy(zv_request_t *zvr) {
struct bio *bio;
static void zvol_setup_copy_offload(zv_request_t *zvr)
{
zvol_state_t *zv_src = zvr->zv, *zv_dst = zvr->zv;
struct request *req = zvr->rq;
zvol_state_t *zv_src = zvr->zv;
zvol_state_t *zv_dst = zvr->zv;
zilog_t *zilog_dst;
struct bio *bio;
zilog_t *zilog_dst;
zfs_uio_t uio_src, uio_dst;
dmu_tx_t *tx;
zfs_locked_range_t *inlr, *outlr;
blkptr_t *bps;
objset_t *inos, *outos;
size_t maxblocks, nbps;
uint64_t inoff, outoff, len, size, last_synced_txg;
objset_t *inos, *outos;
dmu_tx_t *tx;
blkptr_t *bps;
size_t maxblocks;
uint64_t inoff, outoff, len = 0;
int error = 0, seg = 1;

memset(&uio_src, 0, sizeof (zfs_uio_t));
memset(&uio_dst, 0, sizeof (zfs_uio_t));

/*
* First bio contains information about destination and last bio
* contains information about source.
* First bio contains information about destination and
* the second contains information about the source
*/
__rq_for_each_bio(bio, req) {
/*
* Last bio, SOURCE
*/
if (seg == blk_rq_nr_phys_segments(req)) {
struct blkdev_copy_offload_io_zvol *offload_io =
bio->bi_private;
zfs_uio_bvec_init(&uio_src, bio, NULL);
if (len != bio->bi_iter.bi_size) {
error = -EIO;
goto out;
rw_exit(&zv_src->zv_suspend_lock);
zvol_end_io(bio, req, -SET_ERROR(error));
return;
}
if (offload_io && offload_io->driver_private)
zv_dst = offload_io->driver_private;
}

/*
* First bio, DEST
*/
else {
} else {
zfs_uio_bvec_init(&uio_dst, bio, NULL);
len = bio->bi_iter.bi_size;
}
seg++;
}

if (!zv_src || !zv_dst) {
rw_exit(&zv_src->zv_suspend_lock);
zvol_end_io(bio, req, -SET_ERROR(error));
return;
}
if (zv_src != zv_dst)
rw_enter(&zv_dst->zv_suspend_lock, RW_READER);

Expand All @@ -556,47 +558,42 @@ static int zvol_setup_copy(zv_request_t *zvr) {
outos = zv_dst->zv_objset;

/*
* Both source and destination have to belong to the same storage pool.
*/
if (dmu_objset_spa(inos) != dmu_objset_spa(outos)) {
error = EXDEV;
goto out;
}

/*
* outos and inos belongs to the same storage pool.
* see a few lines above, only one check.
* Sanity checks
*/
if (!spa_feature_is_enabled(dmu_objset_spa(outos),
SPA_FEATURE_BLOCK_CLONING)) {
error = EOPNOTSUPP;
goto out;
}

/*
* Block cloning from an unencrypted dataset into an encrypted
* dataset and vice versa is not supported.
*/
if (dmu_objset_spa(inos) != dmu_objset_spa(outos)) {
error = EXDEV;
goto out;
}
if (inos->os_encrypted != outos->os_encrypted) {
error = EXDEV;
goto out;
}

if (inoff >= zv_src->zv_volsize) {
if (zv_src->zv_volblocksize != zv_dst->zv_volblocksize) {
error = EINVAL;
goto out;
}
if (inoff >= zv_src->zv_volsize || outoff >= zv_dst->zv_volsize) {
error = 0;
goto out;
}

if (len > zv_src->zv_volsize - inoff) {
/*
* Do not read beyond source boundary
*/
if (len > zv_src->zv_volsize - inoff)
len = zv_src->zv_volsize - inoff;
}
if (len == 0) {
error = 0;
goto out;
}

/*
* No overlapping if we are cloning within the same file.
* No overlapping if we are cloning within the same file
*/
if (zv_src == zv_dst) {
if (inoff < outoff + len && outoff < inoff + len) {
Expand All @@ -605,10 +602,6 @@ static int zvol_setup_copy(zv_request_t *zvr) {
}
}

if (zv_src->zv_volblocksize != zv_dst->zv_volblocksize) {
error = EINVAL;
goto out;
}
/*
* Block size must be power-of-2 if destination offset != 0.
* There can be no multiple blocks of non-power-of-2 size.
Expand All @@ -619,7 +612,7 @@ static int zvol_setup_copy(zv_request_t *zvr) {
}

/*
* Offsets and len must be at block boundries.
* Offsets and length must be at block boundaries
*/
if ((inoff % zv_src->zv_volblocksize) != 0 ||
(outoff % zv_dst->zv_volblocksize) != 0) {
Expand All @@ -628,22 +621,24 @@ static int zvol_setup_copy(zv_request_t *zvr) {
}

/*
* Length must be multipe of blksz, except for the end of the file.
* Length must be multiple of block size, except for the end of the file
*/
if ((len % zv_src->zv_volblocksize) != 0 && (len < zv_src->zv_volsize -
inoff || len < zv_dst->zv_volsize - outoff)) {
error = EINVAL;
goto out;
}

/*
* ZIL Lock
*/
if (zv_dst->zv_zilog == NULL) {
rw_exit(&zv_dst->zv_suspend_lock);
rw_enter(&zv_dst->zv_suspend_lock, RW_WRITER);
if (zv_dst->zv_zilog == NULL) {
zv_dst->zv_zilog = zil_open(zv_dst->zv_objset,
zvol_get_data, &zv_dst->zv_kstat.dk_zil_sums);
zv_dst->zv_flags |= ZVOL_WRITTEN_TO;
/* replay / destroy done in zvol_create_minor */
VERIFY0((zv_dst->zv_zilog->zl_header->zh_flags &
ZIL_REPLAY_NEEDED));
}
Expand All @@ -659,8 +654,9 @@ static int zvol_setup_copy(zv_request_t *zvr) {
outlr = zfs_rangelock_enter(&zv_dst->zv_rangelock, outoff, len,
RL_WRITER);
while (len > 0) {
uint64_t size, last_synced_txg;
size_t nbps = maxblocks;
size = MIN(zv_src->zv_volblocksize * maxblocks, len);
nbps = maxblocks;
last_synced_txg = spa_last_synced_txg(
dmu_objset_spa(zv_src->zv_objset));
error = dmu_read_l0_bps(zv_src->zv_objset, ZVOL_OBJ, inoff,
Expand All @@ -676,16 +672,13 @@ static int zvol_setup_copy(zv_request_t *zvr) {
if (error == EAGAIN && zfs_bclone_wait_dirty) {
txg_wait_synced(dmu_objset_pool
(zv_src->zv_objset), last_synced_txg + 1);
continue;
continue;
}
break;
}
/*
* Start a transaction.
*/

tx = dmu_tx_create(zv_dst->zv_objset);
dmu_tx_hold_clone_by_dnode(tx, zv_dst->zv_dn, outoff, size);

error = dmu_tx_assign(tx, TXG_WAIT);
if (error != 0) {
dmu_tx_abort(tx);
Expand Down Expand Up @@ -713,7 +706,17 @@ static int zvol_setup_copy(zv_request_t *zvr) {
out:
if (zv_src != zv_dst)
rw_exit(&zv_dst->zv_suspend_lock);
return (error);

rw_exit(&zv_src->zv_suspend_lock);
zvol_end_io(bio, req, -SET_ERROR(error));
}

static void
zvol_copy_offload_task(void *arg)
{
zv_request_task_t *task = arg;
zvol_setup_copy_offload(&task->zvr);
zv_request_task_free(task);
}

/*
Expand Down Expand Up @@ -748,18 +751,6 @@ zvol_request_impl(zvol_state_t *zv, struct bio *bio, struct request *rq,
.rq = rq,
};

if (zv->zv_zso->use_blk_mq && rq && op_is_copy(req_op(rq))) {
int status;
rw_enter(&zv->zv_suspend_lock, RW_READER);
status = zvol_setup_copy(&zvr);
rw_exit(&zv->zv_suspend_lock);
zvol_end_io(bio, rq, -SET_ERROR(status));
return;
} else if (bio && op_is_copy(bio_op(bio))) {
zvol_end_io(bio, rq, -SET_ERROR(EOPNOTSUPP));
return;
}

if (io_has_data(bio, rq) && offset + size > zv->zv_volsize) {
printk(KERN_INFO "%s: bad access: offset=%llu, size=%lu\n",
zv->zv_zso->zvo_disk->disk_name,
Expand All @@ -786,6 +777,26 @@ zvol_request_impl(zvol_state_t *zv, struct bio *bio, struct request *rq,
blk_mq_hw_queue);
tq_idx = taskq_hash % ztqs->tqs_cnt;

if (zv->zv_zso->use_blk_mq && rq && op_is_copy(req_op(rq))) {
if (unlikely(zv->zv_flags & ZVOL_RDONLY)) {
zvol_end_io(bio, rq, -SET_ERROR(EROFS));
goto out;
}
rw_enter(&zv->zv_suspend_lock, RW_READER);

if (force_sync) {
zvol_setup_copy_offload(&zvr);
} else {
task = zv_request_task_create(zvr);
taskq_dispatch_ent(ztqs->tqs_taskq[tq_idx],
zvol_copy_offload_task, task, 0, &task->ent);
}
goto out;
} else if (bio && op_is_copy(bio_op(bio))) {
zvol_end_io(bio, rq, -SET_ERROR(EOPNOTSUPP));
goto out;
}

if (rw == WRITE) {
if (unlikely(zv->zv_flags & ZVOL_RDONLY)) {
zvol_end_io(bio, rq, -SET_ERROR(EROFS));
Expand Down Expand Up @@ -1900,9 +1911,12 @@ zvol_os_create_minor(const char *name)
set_capacity(zv->zv_zso->zvo_disk, zv->zv_volsize >> 9);

if (zv->zv_zso->use_blk_mq) {
/*
* We've seen SCST sending 256 MB XCOPY request for large IOs
*/
lim = &zv->zv_zso->zvo_queue->limits;
lim->max_copy_hw_sectors = (DMU_MAX_ACCESS / 4) >> 9;
lim->max_copy_sectors = (DMU_MAX_ACCESS / 4) >> 9;
lim->max_copy_hw_sectors = (256 * 1024 * 1024) >> 9;
lim->max_copy_sectors = (256 * 1024 * 1024) >> 9;
}

#ifdef QUEUE_FLAG_DISCARD
Expand Down
7 changes: 3 additions & 4 deletions module/zfs/zfs_log.c
Original file line number Diff line number Diff line change
Expand Up @@ -921,11 +921,10 @@ zfs_log_clone_range(zilog_t *zilog, dmu_tx_t *tx, int txtype, znode_t *zp,
lr->lr_nbps = partnbps;
memcpy(lr->lr_bps, bps, sizeof (bps[0]) * partnbps);

if (zp) {
if (zp)
itx->itx_sync = (zp->z_sync_cnt != 0);
} else {
itx->itx_sync = 0;
}
else
itx->itx_sync = 0; /* TODO: Is this OK? */

zil_itx_assign(zilog, itx, tx);

Expand Down

0 comments on commit 9c82f04

Please sign in to comment.