13fb517f7SJames Moore /*
23fb517f7SJames Moore * CDDL HEADER START
33fb517f7SJames Moore *
43fb517f7SJames Moore * The contents of this file are subject to the terms of the
53fb517f7SJames Moore * Common Development and Distribution License (the "License").
63fb517f7SJames Moore * You may not use this file except in compliance with the License.
73fb517f7SJames Moore *
83fb517f7SJames Moore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93fb517f7SJames Moore * or http://www.opensolaris.org/os/licensing.
103fb517f7SJames Moore * See the License for the specific language governing permissions
113fb517f7SJames Moore * and limitations under the License.
123fb517f7SJames Moore *
133fb517f7SJames Moore * When distributing Covered Code, include this CDDL HEADER in each
143fb517f7SJames Moore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153fb517f7SJames Moore * If applicable, add the following below this CDDL HEADER, with the
163fb517f7SJames Moore * fields enclosed by brackets "[]" replaced with your own identifying
173fb517f7SJames Moore * information: Portions Copyright [yyyy] [name of copyright owner]
183fb517f7SJames Moore *
193fb517f7SJames Moore * CDDL HEADER END
203fb517f7SJames Moore */
213fb517f7SJames Moore /*
223fb517f7SJames Moore * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2379315247SMatthew Ahrens * Copyright (c) 2014, 2018 by Delphix. All rights reserved.
243fb517f7SJames Moore */
253fb517f7SJames Moore
263fb517f7SJames Moore #include <sys/conf.h>
273fb517f7SJames Moore #include <sys/file.h>
283fb517f7SJames Moore #include <sys/ddi.h>
293fb517f7SJames Moore #include <sys/sunddi.h>
303fb517f7SJames Moore #include <sys/modctl.h>
313fb517f7SJames Moore #include <sys/scsi/scsi.h>
323fb517f7SJames Moore #include <sys/scsi/impl/scsi_reset_notify.h>
333fb517f7SJames Moore #include <sys/scsi/generic/mode.h>
343fb517f7SJames Moore #include <sys/disp.h>
353fb517f7SJames Moore #include <sys/byteorder.h>
363fb517f7SJames Moore #include <sys/atomic.h>
373fb517f7SJames Moore #include <sys/sdt.h>
383fb517f7SJames Moore #include <sys/dkio.h>
393fb517f7SJames Moore #include <sys/dmu.h>
403fb517f7SJames Moore #include <sys/arc.h>
413fb517f7SJames Moore #include <sys/zvol.h>
423fb517f7SJames Moore #include <sys/zfs_rlock.h>
4379315247SMatthew Ahrens #include <sys/zil.h>
443fb517f7SJames Moore
454558d122SViswanathan Kannappan #include <sys/stmf.h>
464558d122SViswanathan Kannappan #include <sys/lpif.h>
474558d122SViswanathan Kannappan #include <sys/portif.h>
484558d122SViswanathan Kannappan #include <sys/stmf_ioctl.h>
494558d122SViswanathan Kannappan #include <sys/stmf_sbd_ioctl.h>
504558d122SViswanathan Kannappan
514558d122SViswanathan Kannappan #include "stmf_sbd.h"
524558d122SViswanathan Kannappan #include "sbd_impl.h"
533fb517f7SJames Moore
543fb517f7SJames Moore
553fb517f7SJames Moore /*
563fb517f7SJames Moore * This file contains direct calls into the zfs module.
573fb517f7SJames Moore * These functions mimic zvol_read and zvol_write except pointers
583fb517f7SJames Moore * to the data buffers are passed instead of copying the data itself.
593fb517f7SJames Moore *
603fb517f7SJames Moore * zfs internal interfaces referenced here:
613fb517f7SJames Moore *
623fb517f7SJames Moore * FUNCTIONS
638dfe5547SRichard Yao * dmu_buf_hold_array_by_dnode()
643fb517f7SJames Moore * dmu_buf_rele_array()
653fb517f7SJames Moore *
668dfe5547SRichard Yao * arc_loan_buf()
673fb517f7SJames Moore * dmu_assign_arcbuf()
688dfe5547SRichard Yao * dmu_return_arcbuf()
693fb517f7SJames Moore * arc_buf_size()
703fb517f7SJames Moore *
713fb517f7SJames Moore * dmu_tx_create()
723fb517f7SJames Moore * dmu_tx_hold_write()
733fb517f7SJames Moore * dmu_tx_assign()
743fb517f7SJames Moore * dmu_tx_commit(tx)
753fb517f7SJames Moore * dmu_tx_abort(tx)
763fb517f7SJames Moore * zil_commit()
773fb517f7SJames Moore *
7879315247SMatthew Ahrens * rangelock_enter()
7979315247SMatthew Ahrens * rangelock_exit()
803fb517f7SJames Moore *
813fb517f7SJames Moore * zvol_log_write()
823fb517f7SJames Moore *
833fb517f7SJames Moore * dmu_read_uio()
843fb517f7SJames Moore * dmu_write_uio()
853fb517f7SJames Moore * MINOR DATA
863fb517f7SJames Moore * zv_volsize
873fb517f7SJames Moore * zv_volblocksize
883fb517f7SJames Moore * zv_flags - for WCE
893fb517f7SJames Moore * zv_objset - dmu_tx_create
903fb517f7SJames Moore * zv_zilog - zil_commit
9179315247SMatthew Ahrens * zv_znode - rangelock_enter
928dfe5547SRichard Yao * zv_dn - dmu_buf_hold_array_by_bonus, dmu_request_arcbuf
933fb517f7SJames Moore * GLOBAL DATA
943fb517f7SJames Moore * zvol_maxphys
953fb517f7SJames Moore */
963fb517f7SJames Moore
973fb517f7SJames Moore /*
983fb517f7SJames Moore * Take direct control of the volume instead of using the driver
993fb517f7SJames Moore * interfaces provided by zvol.c. Gather parameters and handles
1003fb517f7SJames Moore * needed to make direct calls into zfs/dmu/zvol. The driver is
1013fb517f7SJames Moore * opened exclusively at this point, so these parameters cannot change.
1023fb517f7SJames Moore *
1033fb517f7SJames Moore * NOTE: the object size and WCE can change while the device
1043fb517f7SJames Moore * is open, so they must be fetched for every operation.
1053fb517f7SJames Moore */
1063fb517f7SJames Moore int
sbd_zvol_get_volume_params(sbd_lu_t * sl)1073fb517f7SJames Moore sbd_zvol_get_volume_params(sbd_lu_t *sl)
1083fb517f7SJames Moore {
1093fb517f7SJames Moore int ret;
1103fb517f7SJames Moore
1113fb517f7SJames Moore ret = zvol_get_volume_params(sl->sl_zvol_minor,
1123fb517f7SJames Moore &sl->sl_blksize, /* volume block size */
1133fb517f7SJames Moore &sl->sl_max_xfer_len, /* max data chunk size */
1143fb517f7SJames Moore &sl->sl_zvol_minor_hdl, /* minor soft state */
1153fb517f7SJames Moore &sl->sl_zvol_objset_hdl, /* dmu_tx_create */
1163fb517f7SJames Moore &sl->sl_zvol_zil_hdl, /* zil_commit */
11779315247SMatthew Ahrens &sl->sl_zvol_rl_hdl, /* locked_range_t */
1188dfe5547SRichard Yao &sl->sl_zvol_dn_hdl); /* dmu_buf_hold_array_by_dnode, */
1193fb517f7SJames Moore /* dmu_request_arcbuf, */
1203fb517f7SJames Moore /* dmu_assign_arcbuf */
1213fb517f7SJames Moore
1223fb517f7SJames Moore if (ret == 0 && sl->sl_blksize < MMU_PAGESIZE) {
1233fb517f7SJames Moore cmn_err(CE_NOTE, "COMSTAR reduced copy disabled due to "
1243fb517f7SJames Moore "small zvol blocksize (%d)\n", (int)sl->sl_blksize);
1253fb517f7SJames Moore ret = ENOTSUP;
1263fb517f7SJames Moore }
1273fb517f7SJames Moore
1283fb517f7SJames Moore return (ret);
1293fb517f7SJames Moore }
1303fb517f7SJames Moore
1313fb517f7SJames Moore /*
1323fb517f7SJames Moore * Return the number of elements in a scatter/gather list required for
1333fb517f7SJames Moore * the given span in the zvol. Elements are 1:1 with zvol blocks.
1343fb517f7SJames Moore */
1353fb517f7SJames Moore uint32_t
sbd_zvol_numsegs(sbd_lu_t * sl,uint64_t off,uint32_t len)1363fb517f7SJames Moore sbd_zvol_numsegs(sbd_lu_t *sl, uint64_t off, uint32_t len)
1373fb517f7SJames Moore {
1383fb517f7SJames Moore uint64_t blksz = sl->sl_blksize;
1393fb517f7SJames Moore uint64_t endoff = off + len;
1403fb517f7SJames Moore uint64_t numsegs;
1413fb517f7SJames Moore
1423fb517f7SJames Moore numsegs = (P2ROUNDUP(endoff, blksz) - P2ALIGN(off, blksz)) / blksz;
1433fb517f7SJames Moore return ((uint32_t)numsegs);
1443fb517f7SJames Moore }
1453fb517f7SJames Moore
1463fb517f7SJames Moore /*
1473fb517f7SJames Moore * Return an array of dmu_buf_t pointers for the requested range.
1483fb517f7SJames Moore * The dmu buffers are either in cache or read in synchronously.
1493fb517f7SJames Moore * Fill in the dbuf sglist from the dmu_buf_t array.
1503fb517f7SJames Moore */
1513fb517f7SJames Moore static void *RDTAG = "sbd_zvol_read";
1523fb517f7SJames Moore
1533fb517f7SJames Moore int
sbd_zvol_alloc_read_bufs(sbd_lu_t * sl,stmf_data_buf_t * dbuf)1543fb517f7SJames Moore sbd_zvol_alloc_read_bufs(sbd_lu_t *sl, stmf_data_buf_t *dbuf)
1553fb517f7SJames Moore {
1563fb517f7SJames Moore sbd_zvol_io_t *zvio = dbuf->db_lu_private;
15779315247SMatthew Ahrens locked_range_t *lr;
1583fb517f7SJames Moore int numbufs, error;
1593fb517f7SJames Moore uint64_t len = dbuf->db_data_size;
1603fb517f7SJames Moore uint64_t offset = zvio->zvio_offset;
1613fb517f7SJames Moore dmu_buf_t **dbpp, *dbp;
1623fb517f7SJames Moore
1633fb517f7SJames Moore /* Make sure request is reasonable */
1643fb517f7SJames Moore if (len > sl->sl_max_xfer_len)
1653fb517f7SJames Moore return (E2BIG);
1663fb517f7SJames Moore if (offset + len > zvol_get_volume_size(sl->sl_zvol_minor_hdl))
1673fb517f7SJames Moore return (EIO);
1683fb517f7SJames Moore
1693fb517f7SJames Moore /*
1703fb517f7SJames Moore * The range lock is only held until the dmu buffers read in and
1713fb517f7SJames Moore * held; not during the callers use of the data.
1723fb517f7SJames Moore */
17379315247SMatthew Ahrens lr = rangelock_enter(sl->sl_zvol_rl_hdl, offset, len, RL_READER);
1743fb517f7SJames Moore
1758dfe5547SRichard Yao error = dmu_buf_hold_array_by_dnode(sl->sl_zvol_dn_hdl,
1768dfe5547SRichard Yao offset, len, TRUE, RDTAG, &numbufs, &dbpp,
1778dfe5547SRichard Yao DMU_READ_PREFETCH);
1783fb517f7SJames Moore
17979315247SMatthew Ahrens rangelock_exit(lr);
1803fb517f7SJames Moore
1813fb517f7SJames Moore if (error == ECKSUM)
1823fb517f7SJames Moore error = EIO;
1833fb517f7SJames Moore
1843fb517f7SJames Moore if (error == 0) {
1853fb517f7SJames Moore /*
1863fb517f7SJames Moore * Fill in db_sglist from the dmu_buf_t array.
1873fb517f7SJames Moore */
1883fb517f7SJames Moore int i;
1893fb517f7SJames Moore stmf_sglist_ent_t *sgl;
1903fb517f7SJames Moore uint64_t odiff, seglen;
1913fb517f7SJames Moore
1923fb517f7SJames Moore zvio->zvio_dbp = dbpp;
1933fb517f7SJames Moore /* make sure db_sglist is large enough */
1943fb517f7SJames Moore if (dbuf->db_sglist_length != numbufs) {
1953fb517f7SJames Moore cmn_err(CE_PANIC, "wrong size sglist: dbuf %d != %d\n",
1963fb517f7SJames Moore dbuf->db_sglist_length, numbufs);
1973fb517f7SJames Moore }
1983fb517f7SJames Moore
1993fb517f7SJames Moore sgl = &dbuf->db_sglist[0];
2003fb517f7SJames Moore for (i = 0; i < numbufs; i++) {
2013fb517f7SJames Moore dbp = dbpp[i];
2023fb517f7SJames Moore odiff = offset - dbp->db_offset;
2033fb517f7SJames Moore ASSERT(odiff == 0 || i == 0);
2043fb517f7SJames Moore sgl->seg_addr = (uint8_t *)dbp->db_data + odiff;
2053fb517f7SJames Moore seglen = MIN(len, dbp->db_size - odiff);
2063fb517f7SJames Moore sgl->seg_length = (uint32_t)seglen;
2073fb517f7SJames Moore offset += seglen;
2083fb517f7SJames Moore len -= seglen;
2093fb517f7SJames Moore sgl++;
2103fb517f7SJames Moore }
2113fb517f7SJames Moore ASSERT(len == 0);
2123fb517f7SJames Moore
2133fb517f7SJames Moore }
2143fb517f7SJames Moore return (error);
2153fb517f7SJames Moore }
2163fb517f7SJames Moore
2173fb517f7SJames Moore /*
2183fb517f7SJames Moore * Release a dmu_buf_t array.
2193fb517f7SJames Moore */
2203fb517f7SJames Moore /*ARGSUSED*/
2213fb517f7SJames Moore void
sbd_zvol_rele_read_bufs(sbd_lu_t * sl,stmf_data_buf_t * dbuf)2223fb517f7SJames Moore sbd_zvol_rele_read_bufs(sbd_lu_t *sl, stmf_data_buf_t *dbuf)
2233fb517f7SJames Moore {
2243fb517f7SJames Moore sbd_zvol_io_t *zvio = dbuf->db_lu_private;
2253fb517f7SJames Moore
2263fb517f7SJames Moore ASSERT(zvio->zvio_dbp);
2273fb517f7SJames Moore ASSERT(dbuf->db_sglist_length);
2283fb517f7SJames Moore
2293fb517f7SJames Moore dmu_buf_rele_array(zvio->zvio_dbp, (int)dbuf->db_sglist_length, RDTAG);
2303fb517f7SJames Moore }
2313fb517f7SJames Moore
2323fb517f7SJames Moore /*
2333fb517f7SJames Moore * Allocate enough loaned arc buffers for the requested region.
2343fb517f7SJames Moore * Mimic the handling of the dmu_buf_t array used for reads as closely
2353fb517f7SJames Moore * as possible even though the arc_buf_t's are anonymous until released.
2363fb517f7SJames Moore * The buffers will match the zvol object blocks sizes and alignments
2373fb517f7SJames Moore * such that a data copy may be avoided when the buffers are assigned.
2383fb517f7SJames Moore */
2393fb517f7SJames Moore int
sbd_zvol_alloc_write_bufs(sbd_lu_t * sl,stmf_data_buf_t * dbuf)2403fb517f7SJames Moore sbd_zvol_alloc_write_bufs(sbd_lu_t *sl, stmf_data_buf_t *dbuf)
2413fb517f7SJames Moore {
2423fb517f7SJames Moore sbd_zvol_io_t *zvio = dbuf->db_lu_private;
2433fb517f7SJames Moore int blkshift, numbufs, i;
2443fb517f7SJames Moore uint64_t blksize;
2453fb517f7SJames Moore arc_buf_t **abp;
2463fb517f7SJames Moore stmf_sglist_ent_t *sgl;
2473fb517f7SJames Moore uint64_t len = dbuf->db_data_size;
2483fb517f7SJames Moore uint64_t offset = zvio->zvio_offset;
2493fb517f7SJames Moore
2503fb517f7SJames Moore /* Make sure request is reasonable */
2513fb517f7SJames Moore if (len > sl->sl_max_xfer_len)
2523fb517f7SJames Moore return (E2BIG);
2533fb517f7SJames Moore if (offset + len > zvol_get_volume_size(sl->sl_zvol_minor_hdl))
2543fb517f7SJames Moore return (EIO);
2553fb517f7SJames Moore
2563fb517f7SJames Moore /*
2573fb517f7SJames Moore * Break up the request into chunks to match
2583fb517f7SJames Moore * the volume block size. Only full, and aligned
2593fb517f7SJames Moore * buffers will avoid the data copy in the dmu.
2603fb517f7SJames Moore */
2613fb517f7SJames Moore /*
2623fb517f7SJames Moore * calculate how may dbufs are needed
2633fb517f7SJames Moore */
2643fb517f7SJames Moore blksize = sl->sl_blksize;
2653fb517f7SJames Moore ASSERT(ISP2(blksize));
2663fb517f7SJames Moore blkshift = highbit(blksize - 1);
2673fb517f7SJames Moore /*
2683fb517f7SJames Moore * taken from dmu_buf_hold_array_by_dnode()
2693fb517f7SJames Moore */
2703fb517f7SJames Moore numbufs = (P2ROUNDUP(offset+len, 1ULL<<blkshift) -
2713fb517f7SJames Moore P2ALIGN(offset, 1ULL<<blkshift)) >> blkshift;
2723fb517f7SJames Moore if (dbuf->db_sglist_length != numbufs) {
2733fb517f7SJames Moore cmn_err(CE_PANIC, "wrong size sglist: dbuf %d != %d\n",
2743fb517f7SJames Moore dbuf->db_sglist_length, numbufs);
2753fb517f7SJames Moore }
2763fb517f7SJames Moore /*
2773fb517f7SJames Moore * allocate a holder for the needed arc_buf pointers
2783fb517f7SJames Moore */
2793fb517f7SJames Moore abp = kmem_alloc(sizeof (arc_buf_t *) * numbufs, KM_SLEEP);
2803fb517f7SJames Moore /*
2813fb517f7SJames Moore * The write operation uses loaned arc buffers so that
2823fb517f7SJames Moore * the xfer_data is done outside of a dmu transaction.
2833fb517f7SJames Moore * These buffers will exactly match the request unlike
2843fb517f7SJames Moore * the dmu buffers obtained from the read operation.
2853fb517f7SJames Moore */
2863fb517f7SJames Moore /*
2873fb517f7SJames Moore * allocate the arc buffers and fill in the stmf sglist
2883fb517f7SJames Moore */
2893fb517f7SJames Moore sgl = &dbuf->db_sglist[0];
2903fb517f7SJames Moore for (i = 0; i < numbufs; i++) {
2913fb517f7SJames Moore uint64_t seglen;
2923fb517f7SJames Moore
2933fb517f7SJames Moore /* first block may not be aligned */
2943fb517f7SJames Moore seglen = P2NPHASE(offset, blksize);
2953fb517f7SJames Moore if (seglen == 0)
2963fb517f7SJames Moore seglen = blksize;
2973fb517f7SJames Moore seglen = MIN(seglen, len);
2988dfe5547SRichard Yao abp[i] = arc_loan_buf(dmu_objset_spa(sl->sl_zvol_objset_hdl),
2998dfe5547SRichard Yao B_FALSE, (int)seglen);
3003fb517f7SJames Moore ASSERT(arc_buf_size(abp[i]) == (int)seglen);
3013fb517f7SJames Moore sgl->seg_addr = abp[i]->b_data;
3023fb517f7SJames Moore sgl->seg_length = (uint32_t)seglen;
3033fb517f7SJames Moore sgl++;
3043fb517f7SJames Moore offset += seglen;
3053fb517f7SJames Moore len -= seglen;
3063fb517f7SJames Moore }
3073fb517f7SJames Moore ASSERT(len == 0);
3083fb517f7SJames Moore
3093fb517f7SJames Moore zvio->zvio_abp = abp;
3103fb517f7SJames Moore return (0);
3113fb517f7SJames Moore }
3123fb517f7SJames Moore
3133fb517f7SJames Moore /*ARGSUSED*/
3143fb517f7SJames Moore void
sbd_zvol_rele_write_bufs_abort(sbd_lu_t * sl,stmf_data_buf_t * dbuf)3153fb517f7SJames Moore sbd_zvol_rele_write_bufs_abort(sbd_lu_t *sl, stmf_data_buf_t *dbuf)
3163fb517f7SJames Moore {
3173fb517f7SJames Moore sbd_zvol_io_t *zvio = dbuf->db_lu_private;
3183fb517f7SJames Moore int i;
3193fb517f7SJames Moore arc_buf_t **abp = zvio->zvio_abp;
3203fb517f7SJames Moore
3213fb517f7SJames Moore /* free arcbufs */
3223fb517f7SJames Moore for (i = 0; i < dbuf->db_sglist_length; i++)
3233fb517f7SJames Moore dmu_return_arcbuf(*abp++);
3243fb517f7SJames Moore kmem_free(zvio->zvio_abp,
3253fb517f7SJames Moore sizeof (arc_buf_t *) * dbuf->db_sglist_length);
3263fb517f7SJames Moore zvio->zvio_abp = NULL;
3273fb517f7SJames Moore }
3283fb517f7SJames Moore
3293fb517f7SJames Moore /*
3303fb517f7SJames Moore * Release the arc_buf_t array allocated above and handle these cases :
3313fb517f7SJames Moore *
3323fb517f7SJames Moore * flags == 0 - create transaction and assign all arc bufs to offsets
3333fb517f7SJames Moore * flags == ZVIO_COMMIT - same as above and commit to zil on sync devices
3343fb517f7SJames Moore */
3353fb517f7SJames Moore int
sbd_zvol_rele_write_bufs(sbd_lu_t * sl,stmf_data_buf_t * dbuf)3363fb517f7SJames Moore sbd_zvol_rele_write_bufs(sbd_lu_t *sl, stmf_data_buf_t *dbuf)
3373fb517f7SJames Moore {
3383fb517f7SJames Moore sbd_zvol_io_t *zvio = dbuf->db_lu_private;
3393fb517f7SJames Moore dmu_tx_t *tx;
3403fb517f7SJames Moore int sync, i, error;
34179315247SMatthew Ahrens locked_range_t *lr;
3423fb517f7SJames Moore arc_buf_t **abp = zvio->zvio_abp;
3433fb517f7SJames Moore int flags = zvio->zvio_flags;
3443fb517f7SJames Moore uint64_t toffset, offset = zvio->zvio_offset;
3453fb517f7SJames Moore uint64_t resid, len = dbuf->db_data_size;
3463fb517f7SJames Moore
3473fb517f7SJames Moore ASSERT(flags == 0 || flags == ZVIO_COMMIT || flags == ZVIO_ABORT);
3483fb517f7SJames Moore
34979315247SMatthew Ahrens lr = rangelock_enter(sl->sl_zvol_rl_hdl, offset, len, RL_WRITER);
3503fb517f7SJames Moore
3513fb517f7SJames Moore tx = dmu_tx_create(sl->sl_zvol_objset_hdl);
3523fb517f7SJames Moore dmu_tx_hold_write(tx, ZVOL_OBJ, offset, (int)len);
3533fb517f7SJames Moore error = dmu_tx_assign(tx, TXG_WAIT);
3543fb517f7SJames Moore
3553fb517f7SJames Moore if (error) {
3563fb517f7SJames Moore dmu_tx_abort(tx);
35779315247SMatthew Ahrens rangelock_exit(lr);
3583fb517f7SJames Moore sbd_zvol_rele_write_bufs_abort(sl, dbuf);
3593fb517f7SJames Moore return (error);
3603fb517f7SJames Moore }
3613fb517f7SJames Moore
3623fb517f7SJames Moore toffset = offset;
3633fb517f7SJames Moore resid = len;
3643fb517f7SJames Moore for (i = 0; i < dbuf->db_sglist_length; i++) {
3653fb517f7SJames Moore arc_buf_t *abuf;
3663fb517f7SJames Moore int size;
3673fb517f7SJames Moore
3683fb517f7SJames Moore abuf = abp[i];
3693fb517f7SJames Moore size = arc_buf_size(abuf);
370*eb633035STom Caputi (void) dmu_assign_arcbuf_by_dnode(sl->sl_zvol_dn_hdl,
371*eb633035STom Caputi toffset, abuf, tx);
3723fb517f7SJames Moore toffset += size;
3733fb517f7SJames Moore resid -= size;
3743fb517f7SJames Moore }
3753fb517f7SJames Moore ASSERT(resid == 0);
3763fb517f7SJames Moore
3773fb517f7SJames Moore sync = !zvol_get_volume_wce(sl->sl_zvol_minor_hdl);
3783fb517f7SJames Moore zvol_log_write_minor(sl->sl_zvol_minor_hdl, tx, offset,
3793fb517f7SJames Moore (ssize_t)len, sync);
3803fb517f7SJames Moore dmu_tx_commit(tx);
38179315247SMatthew Ahrens rangelock_exit(lr);
3823fb517f7SJames Moore kmem_free(zvio->zvio_abp,
3833fb517f7SJames Moore sizeof (arc_buf_t *) * dbuf->db_sglist_length);
3843fb517f7SJames Moore zvio->zvio_abp = NULL;
3853fb517f7SJames Moore if (sync && (flags & ZVIO_COMMIT))
3865002558fSNeil Perrin zil_commit(sl->sl_zvol_zil_hdl, ZVOL_OBJ);
3873fb517f7SJames Moore return (0);
3883fb517f7SJames Moore }
3893fb517f7SJames Moore
3903fb517f7SJames Moore /*
3913fb517f7SJames Moore * Copy interface for callers using direct zvol access.
3923fb517f7SJames Moore * Very similar to zvol_read but the uio may have multiple iovec entries.
3933fb517f7SJames Moore */
3943fb517f7SJames Moore int
sbd_zvol_copy_read(sbd_lu_t * sl,uio_t * uio)3953fb517f7SJames Moore sbd_zvol_copy_read(sbd_lu_t *sl, uio_t *uio)
3963fb517f7SJames Moore {
3973fb517f7SJames Moore uint64_t len = (uint64_t)uio->uio_resid;
3983fb517f7SJames Moore uint64_t offset = (uint64_t)uio->uio_loffset;
3993fb517f7SJames Moore
4003fb517f7SJames Moore /* Make sure request is reasonable */
4013fb517f7SJames Moore if (len > sl->sl_max_xfer_len)
4023fb517f7SJames Moore return (E2BIG);
4033fb517f7SJames Moore if (offset + len > zvol_get_volume_size(sl->sl_zvol_minor_hdl))
4043fb517f7SJames Moore return (EIO);
4053fb517f7SJames Moore
40679315247SMatthew Ahrens locked_range_t *lr = rangelock_enter(sl->sl_zvol_rl_hdl, offset, len,
40779315247SMatthew Ahrens RL_READER);
40879315247SMatthew Ahrens int error = dmu_read_uio_dnode(sl->sl_zvol_dn_hdl, uio, len);
40979315247SMatthew Ahrens rangelock_exit(lr);
4103fb517f7SJames Moore
4113fb517f7SJames Moore if (error == ECKSUM)
4123fb517f7SJames Moore error = EIO;
4133fb517f7SJames Moore return (error);
4143fb517f7SJames Moore }
4153fb517f7SJames Moore
4163fb517f7SJames Moore /*
4173fb517f7SJames Moore * Copy interface for callers using direct zvol access.
4183fb517f7SJames Moore * Very similar to zvol_write but the uio may have multiple iovec entries.
4193fb517f7SJames Moore */
4203fb517f7SJames Moore int
sbd_zvol_copy_write(sbd_lu_t * sl,uio_t * uio,int flags)4213fb517f7SJames Moore sbd_zvol_copy_write(sbd_lu_t *sl, uio_t *uio, int flags)
4223fb517f7SJames Moore {
4233fb517f7SJames Moore dmu_tx_t *tx;
4243fb517f7SJames Moore int error, sync;
4253fb517f7SJames Moore uint64_t len = (uint64_t)uio->uio_resid;
4263fb517f7SJames Moore uint64_t offset = (uint64_t)uio->uio_loffset;
4273fb517f7SJames Moore
4283fb517f7SJames Moore ASSERT(flags == 0 || flags == ZVIO_COMMIT);
4293fb517f7SJames Moore
4303fb517f7SJames Moore /* Make sure request is reasonable */
4313fb517f7SJames Moore if (len > sl->sl_max_xfer_len)
4323fb517f7SJames Moore return (E2BIG);
4333fb517f7SJames Moore if (offset + len > zvol_get_volume_size(sl->sl_zvol_minor_hdl))
4343fb517f7SJames Moore return (EIO);
4353fb517f7SJames Moore
43679315247SMatthew Ahrens locked_range_t *lr = rangelock_enter(sl->sl_zvol_rl_hdl, offset, len,
43779315247SMatthew Ahrens RL_WRITER);
4383fb517f7SJames Moore sync = !zvol_get_volume_wce(sl->sl_zvol_minor_hdl);
4393fb517f7SJames Moore
4403fb517f7SJames Moore tx = dmu_tx_create(sl->sl_zvol_objset_hdl);
4413fb517f7SJames Moore dmu_tx_hold_write(tx, ZVOL_OBJ, offset, (int)uio->uio_resid);
4423fb517f7SJames Moore error = dmu_tx_assign(tx, TXG_WAIT);
4433fb517f7SJames Moore if (error) {
4443fb517f7SJames Moore dmu_tx_abort(tx);
4453fb517f7SJames Moore } else {
4468dfe5547SRichard Yao error = dmu_write_uio_dnode(sl->sl_zvol_dn_hdl, uio, len, tx);
4473fb517f7SJames Moore if (error == 0) {
4483fb517f7SJames Moore zvol_log_write_minor(sl->sl_zvol_minor_hdl, tx, offset,
4493fb517f7SJames Moore (ssize_t)len, sync);
4503fb517f7SJames Moore }
4513fb517f7SJames Moore dmu_tx_commit(tx);
4523fb517f7SJames Moore }
45379315247SMatthew Ahrens rangelock_exit(lr);
45479315247SMatthew Ahrens
4553fb517f7SJames Moore if (sync && (flags & ZVIO_COMMIT))
4565002558fSNeil Perrin zil_commit(sl->sl_zvol_zil_hdl, ZVOL_OBJ);
4573fb517f7SJames Moore if (error == ECKSUM)
4583fb517f7SJames Moore error = EIO;
4593fb517f7SJames Moore return (error);
4603fb517f7SJames Moore }
461