161145dc2SMartin Matuska // SPDX-License-Identifier: CDDL-1.0
27a7741afSMartin Matuska /*
37a7741afSMartin Matuska * CDDL HEADER START
47a7741afSMartin Matuska *
57a7741afSMartin Matuska * The contents of this file are subject to the terms of the
67a7741afSMartin Matuska * Common Development and Distribution License (the "License").
77a7741afSMartin Matuska * You may not use this file except in compliance with the License.
87a7741afSMartin Matuska *
97a7741afSMartin Matuska * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107a7741afSMartin Matuska * or https://opensource.org/licenses/CDDL-1.0.
117a7741afSMartin Matuska * See the License for the specific language governing permissions
127a7741afSMartin Matuska * and limitations under the License.
137a7741afSMartin Matuska *
147a7741afSMartin Matuska * When distributing Covered Code, include this CDDL HEADER in each
157a7741afSMartin Matuska * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167a7741afSMartin Matuska * If applicable, add the following below this CDDL HEADER, with the
177a7741afSMartin Matuska * fields enclosed by brackets "[]" replaced with your own identifying
187a7741afSMartin Matuska * information: Portions Copyright [yyyy] [name of copyright owner]
197a7741afSMartin Matuska *
207a7741afSMartin Matuska * CDDL HEADER END
217a7741afSMartin Matuska */
227a7741afSMartin Matuska
237a7741afSMartin Matuska
247a7741afSMartin Matuska #include <sys/dmu.h>
257a7741afSMartin Matuska #include <sys/dmu_impl.h>
267a7741afSMartin Matuska #include <sys/dbuf.h>
277a7741afSMartin Matuska #include <sys/dnode.h>
287a7741afSMartin Matuska #include <sys/zfs_context.h>
297a7741afSMartin Matuska #include <sys/zfs_racct.h>
307a7741afSMartin Matuska #include <sys/dsl_dataset.h>
317a7741afSMartin Matuska #include <sys/dmu_objset.h>
327a7741afSMartin Matuska
337a7741afSMartin Matuska static abd_t *
make_abd_for_dbuf(dmu_buf_impl_t * db,abd_t * data,uint64_t offset,uint64_t size)347a7741afSMartin Matuska make_abd_for_dbuf(dmu_buf_impl_t *db, abd_t *data, uint64_t offset,
357a7741afSMartin Matuska uint64_t size)
367a7741afSMartin Matuska {
377a7741afSMartin Matuska size_t buf_size = db->db.db_size;
387a7741afSMartin Matuska abd_t *pre_buf = NULL, *post_buf = NULL, *mbuf = NULL;
397a7741afSMartin Matuska size_t buf_off = 0;
407a7741afSMartin Matuska
417a7741afSMartin Matuska ASSERT(MUTEX_HELD(&db->db_mtx));
427a7741afSMartin Matuska
437a7741afSMartin Matuska if (offset > db->db.db_offset) {
447a7741afSMartin Matuska size_t pre_size = offset - db->db.db_offset;
457a7741afSMartin Matuska pre_buf = abd_alloc_for_io(pre_size, B_TRUE);
467a7741afSMartin Matuska buf_size -= pre_size;
477a7741afSMartin Matuska buf_off = 0;
487a7741afSMartin Matuska } else {
497a7741afSMartin Matuska buf_off = db->db.db_offset - offset;
507a7741afSMartin Matuska size -= buf_off;
517a7741afSMartin Matuska }
527a7741afSMartin Matuska
537a7741afSMartin Matuska if (size < buf_size) {
547a7741afSMartin Matuska size_t post_size = buf_size - size;
557a7741afSMartin Matuska post_buf = abd_alloc_for_io(post_size, B_TRUE);
567a7741afSMartin Matuska buf_size -= post_size;
577a7741afSMartin Matuska }
587a7741afSMartin Matuska
597a7741afSMartin Matuska ASSERT3U(buf_size, >, 0);
607a7741afSMartin Matuska abd_t *buf = abd_get_offset_size(data, buf_off, buf_size);
617a7741afSMartin Matuska
627a7741afSMartin Matuska if (pre_buf || post_buf) {
637a7741afSMartin Matuska mbuf = abd_alloc_gang();
647a7741afSMartin Matuska if (pre_buf)
657a7741afSMartin Matuska abd_gang_add(mbuf, pre_buf, B_TRUE);
667a7741afSMartin Matuska abd_gang_add(mbuf, buf, B_TRUE);
677a7741afSMartin Matuska if (post_buf)
687a7741afSMartin Matuska abd_gang_add(mbuf, post_buf, B_TRUE);
697a7741afSMartin Matuska } else {
707a7741afSMartin Matuska mbuf = buf;
717a7741afSMartin Matuska }
727a7741afSMartin Matuska
737a7741afSMartin Matuska return (mbuf);
747a7741afSMartin Matuska }
757a7741afSMartin Matuska
767a7741afSMartin Matuska static void
dmu_read_abd_done(zio_t * zio)777a7741afSMartin Matuska dmu_read_abd_done(zio_t *zio)
787a7741afSMartin Matuska {
797a7741afSMartin Matuska abd_free(zio->io_abd);
807a7741afSMartin Matuska }
817a7741afSMartin Matuska
827a7741afSMartin Matuska static void
dmu_write_direct_ready(zio_t * zio)837a7741afSMartin Matuska dmu_write_direct_ready(zio_t *zio)
847a7741afSMartin Matuska {
857a7741afSMartin Matuska dmu_sync_ready(zio, NULL, zio->io_private);
867a7741afSMartin Matuska }
877a7741afSMartin Matuska
887a7741afSMartin Matuska static void
dmu_write_direct_done(zio_t * zio)897a7741afSMartin Matuska dmu_write_direct_done(zio_t *zio)
907a7741afSMartin Matuska {
917a7741afSMartin Matuska dmu_sync_arg_t *dsa = zio->io_private;
927a7741afSMartin Matuska dbuf_dirty_record_t *dr = dsa->dsa_dr;
937a7741afSMartin Matuska dmu_buf_impl_t *db = dr->dr_dbuf;
947a7741afSMartin Matuska
957a7741afSMartin Matuska abd_free(zio->io_abd);
967a7741afSMartin Matuska
977a7741afSMartin Matuska mutex_enter(&db->db_mtx);
987a7741afSMartin Matuska ASSERT3P(db->db_buf, ==, NULL);
997a7741afSMartin Matuska ASSERT3P(dr->dt.dl.dr_data, ==, NULL);
1007a7741afSMartin Matuska ASSERT3P(db->db.db_data, ==, NULL);
1017a7741afSMartin Matuska db->db_state = DB_UNCACHED;
1027a7741afSMartin Matuska mutex_exit(&db->db_mtx);
1037a7741afSMartin Matuska
1047a7741afSMartin Matuska dmu_sync_done(zio, NULL, zio->io_private);
1057a7741afSMartin Matuska
1067a7741afSMartin Matuska if (zio->io_error != 0) {
1077a7741afSMartin Matuska if (zio->io_flags & ZIO_FLAG_DIO_CHKSUM_ERR)
1087a7741afSMartin Matuska ASSERT3U(zio->io_error, ==, EIO);
1097a7741afSMartin Matuska
1107a7741afSMartin Matuska /*
1117a7741afSMartin Matuska * In the event of an I/O error this block has been freed in
1127a7741afSMartin Matuska * zio_done() through zio_dva_unallocate(). Calling
1137a7741afSMartin Matuska * dmu_sync_done() above set dr_override_state to
1147a7741afSMartin Matuska * DR_NOT_OVERRIDDEN. In this case when dbuf_undirty() calls
1157a7741afSMartin Matuska * dbuf_unoverride(), it will skip doing zio_free() to free
1167a7741afSMartin Matuska * this block as that was already taken care of.
1177a7741afSMartin Matuska *
1187a7741afSMartin Matuska * Since we are undirtying the record in open-context, we must
1197a7741afSMartin Matuska * have a hold on the db, so it should never be evicted after
1207a7741afSMartin Matuska * calling dbuf_undirty().
1217a7741afSMartin Matuska */
1227a7741afSMartin Matuska mutex_enter(&db->db_mtx);
1237a7741afSMartin Matuska VERIFY3B(dbuf_undirty(db, dsa->dsa_tx), ==, B_FALSE);
1247a7741afSMartin Matuska mutex_exit(&db->db_mtx);
1257a7741afSMartin Matuska }
1267a7741afSMartin Matuska
1277a7741afSMartin Matuska kmem_free(zio->io_bp, sizeof (blkptr_t));
1287a7741afSMartin Matuska zio->io_bp = NULL;
1297a7741afSMartin Matuska }
1307a7741afSMartin Matuska
1317a7741afSMartin Matuska int
dmu_write_direct(zio_t * pio,dmu_buf_impl_t * db,abd_t * data,dmu_tx_t * tx)1327a7741afSMartin Matuska dmu_write_direct(zio_t *pio, dmu_buf_impl_t *db, abd_t *data, dmu_tx_t *tx)
1337a7741afSMartin Matuska {
1347a7741afSMartin Matuska objset_t *os = db->db_objset;
1357a7741afSMartin Matuska dsl_dataset_t *ds = dmu_objset_ds(os);
1367a7741afSMartin Matuska zbookmark_phys_t zb;
1377a7741afSMartin Matuska dbuf_dirty_record_t *dr_head;
1387a7741afSMartin Matuska
1397a7741afSMartin Matuska SET_BOOKMARK(&zb, ds->ds_object,
1407a7741afSMartin Matuska db->db.db_object, db->db_level, db->db_blkid);
1417a7741afSMartin Matuska
1427a7741afSMartin Matuska DB_DNODE_ENTER(db);
1437a7741afSMartin Matuska zio_prop_t zp;
1447a7741afSMartin Matuska dmu_write_policy(os, DB_DNODE(db), db->db_level,
1457a7741afSMartin Matuska WP_DMU_SYNC | WP_DIRECT_WR, &zp);
1467a7741afSMartin Matuska DB_DNODE_EXIT(db);
1477a7741afSMartin Matuska
1487a7741afSMartin Matuska /*
1497a7741afSMartin Matuska * Dirty this dbuf with DB_NOFILL since we will not have any data
1507a7741afSMartin Matuska * associated with the dbuf.
1517a7741afSMartin Matuska */
1527a7741afSMartin Matuska dmu_buf_will_clone_or_dio(&db->db, tx);
1537a7741afSMartin Matuska
1547a7741afSMartin Matuska mutex_enter(&db->db_mtx);
1557a7741afSMartin Matuska
1567a7741afSMartin Matuska uint64_t txg = dmu_tx_get_txg(tx);
1577a7741afSMartin Matuska ASSERT3U(txg, >, spa_last_synced_txg(os->os_spa));
1587a7741afSMartin Matuska ASSERT3U(txg, >, spa_syncing_txg(os->os_spa));
1597a7741afSMartin Matuska
1607a7741afSMartin Matuska dr_head = list_head(&db->db_dirty_records);
1617a7741afSMartin Matuska ASSERT3U(dr_head->dr_txg, ==, txg);
1627a7741afSMartin Matuska dr_head->dt.dl.dr_diowrite = B_TRUE;
1637a7741afSMartin Matuska dr_head->dr_accounted = db->db.db_size;
1647a7741afSMartin Matuska
1657a7741afSMartin Matuska blkptr_t *bp = kmem_alloc(sizeof (blkptr_t), KM_SLEEP);
1667a7741afSMartin Matuska if (db->db_blkptr != NULL) {
1677a7741afSMartin Matuska /*
1687a7741afSMartin Matuska * Fill in bp with the current block pointer so that
1697a7741afSMartin Matuska * the nopwrite code can check if we're writing the same
1707a7741afSMartin Matuska * data that's already on disk.
1717a7741afSMartin Matuska */
1727a7741afSMartin Matuska *bp = *db->db_blkptr;
1737a7741afSMartin Matuska } else {
1747a7741afSMartin Matuska memset(bp, 0, sizeof (blkptr_t));
1757a7741afSMartin Matuska }
1767a7741afSMartin Matuska
1777a7741afSMartin Matuska /*
1787a7741afSMartin Matuska * Disable nopwrite if the current block pointer could change
1797a7741afSMartin Matuska * before this TXG syncs.
1807a7741afSMartin Matuska */
1817a7741afSMartin Matuska if (list_next(&db->db_dirty_records, dr_head) != NULL)
1827a7741afSMartin Matuska zp.zp_nopwrite = B_FALSE;
1837a7741afSMartin Matuska
1845c65a0a9SMartin Matuska ASSERT0(dr_head->dt.dl.dr_has_raw_params);
1857a7741afSMartin Matuska ASSERT3S(dr_head->dt.dl.dr_override_state, ==, DR_NOT_OVERRIDDEN);
1867a7741afSMartin Matuska dr_head->dt.dl.dr_override_state = DR_IN_DMU_SYNC;
1877a7741afSMartin Matuska
1887a7741afSMartin Matuska mutex_exit(&db->db_mtx);
1897a7741afSMartin Matuska
1907a7741afSMartin Matuska dmu_objset_willuse_space(os, dr_head->dr_accounted, tx);
1917a7741afSMartin Matuska
1927a7741afSMartin Matuska dmu_sync_arg_t *dsa = kmem_zalloc(sizeof (dmu_sync_arg_t), KM_SLEEP);
1937a7741afSMartin Matuska dsa->dsa_dr = dr_head;
1947a7741afSMartin Matuska dsa->dsa_tx = tx;
1957a7741afSMartin Matuska
1967a7741afSMartin Matuska zio_t *zio = zio_write(pio, os->os_spa, txg, bp, data,
1977a7741afSMartin Matuska db->db.db_size, db->db.db_size, &zp,
1987a7741afSMartin Matuska dmu_write_direct_ready, NULL, dmu_write_direct_done, dsa,
1997a7741afSMartin Matuska ZIO_PRIORITY_SYNC_WRITE, ZIO_FLAG_CANFAIL, &zb);
2007a7741afSMartin Matuska
2017a7741afSMartin Matuska if (pio == NULL)
2027a7741afSMartin Matuska return (zio_wait(zio));
2037a7741afSMartin Matuska
2047a7741afSMartin Matuska zio_nowait(zio);
2057a7741afSMartin Matuska
2067a7741afSMartin Matuska return (0);
2077a7741afSMartin Matuska }
2087a7741afSMartin Matuska
2097a7741afSMartin Matuska int
dmu_write_abd(dnode_t * dn,uint64_t offset,uint64_t size,abd_t * data,dmu_flags_t flags,dmu_tx_t * tx)2107a7741afSMartin Matuska dmu_write_abd(dnode_t *dn, uint64_t offset, uint64_t size,
211*b1c1ee44SMartin Matuska abd_t *data, dmu_flags_t flags, dmu_tx_t *tx)
2127a7741afSMartin Matuska {
2137a7741afSMartin Matuska dmu_buf_t **dbp;
2147a7741afSMartin Matuska spa_t *spa = dn->dn_objset->os_spa;
2157a7741afSMartin Matuska int numbufs, err;
2167a7741afSMartin Matuska
2177a7741afSMartin Matuska ASSERT(flags & DMU_DIRECTIO);
2187a7741afSMartin Matuska
2197a7741afSMartin Matuska err = dmu_buf_hold_array_by_dnode(dn, offset,
2207a7741afSMartin Matuska size, B_FALSE, FTAG, &numbufs, &dbp, flags);
2217a7741afSMartin Matuska if (err)
2227a7741afSMartin Matuska return (err);
2237a7741afSMartin Matuska
2247a7741afSMartin Matuska zio_t *pio = zio_root(spa, NULL, NULL, ZIO_FLAG_CANFAIL);
2257a7741afSMartin Matuska
2267a7741afSMartin Matuska for (int i = 0; i < numbufs && err == 0; i++) {
2277a7741afSMartin Matuska dmu_buf_impl_t *db = (dmu_buf_impl_t *)dbp[i];
2287a7741afSMartin Matuska
2297a7741afSMartin Matuska abd_t *abd = abd_get_offset_size(data,
2307a7741afSMartin Matuska db->db.db_offset - offset, dn->dn_datablksz);
2317a7741afSMartin Matuska
2327a7741afSMartin Matuska zfs_racct_write(spa, db->db.db_size, 1, flags);
2337a7741afSMartin Matuska err = dmu_write_direct(pio, db, abd, tx);
2347a7741afSMartin Matuska ASSERT0(err);
2357a7741afSMartin Matuska }
2367a7741afSMartin Matuska
2377a7741afSMartin Matuska err = zio_wait(pio);
2387a7741afSMartin Matuska
2397a7741afSMartin Matuska /*
2407a7741afSMartin Matuska * The dbuf must be held until the Direct I/O write has completed in
2417a7741afSMartin Matuska * the event there was any errors and dbuf_undirty() was called.
2427a7741afSMartin Matuska */
2437a7741afSMartin Matuska dmu_buf_rele_array(dbp, numbufs, FTAG);
2447a7741afSMartin Matuska
2457a7741afSMartin Matuska return (err);
2467a7741afSMartin Matuska }
2477a7741afSMartin Matuska
2487a7741afSMartin Matuska int
dmu_read_abd(dnode_t * dn,uint64_t offset,uint64_t size,abd_t * data,dmu_flags_t flags)2497a7741afSMartin Matuska dmu_read_abd(dnode_t *dn, uint64_t offset, uint64_t size,
250*b1c1ee44SMartin Matuska abd_t *data, dmu_flags_t flags)
2517a7741afSMartin Matuska {
2527a7741afSMartin Matuska objset_t *os = dn->dn_objset;
2537a7741afSMartin Matuska spa_t *spa = os->os_spa;
2547a7741afSMartin Matuska dmu_buf_t **dbp;
2557a7741afSMartin Matuska int numbufs, err;
2567a7741afSMartin Matuska
2577a7741afSMartin Matuska ASSERT(flags & DMU_DIRECTIO);
2587a7741afSMartin Matuska
2597a7741afSMartin Matuska err = dmu_buf_hold_array_by_dnode(dn, offset,
2607a7741afSMartin Matuska size, B_FALSE, FTAG, &numbufs, &dbp, flags);
2617a7741afSMartin Matuska if (err)
2627a7741afSMartin Matuska return (err);
2637a7741afSMartin Matuska
2647a7741afSMartin Matuska zio_t *rio = zio_root(spa, NULL, NULL, ZIO_FLAG_CANFAIL);
2657a7741afSMartin Matuska
2667a7741afSMartin Matuska for (int i = 0; i < numbufs; i++) {
2677a7741afSMartin Matuska dmu_buf_impl_t *db = (dmu_buf_impl_t *)dbp[i];
2687a7741afSMartin Matuska abd_t *mbuf;
2697a7741afSMartin Matuska zbookmark_phys_t zb;
2707a7741afSMartin Matuska blkptr_t *bp;
2717a7741afSMartin Matuska
2727a7741afSMartin Matuska mutex_enter(&db->db_mtx);
2737a7741afSMartin Matuska
2747a7741afSMartin Matuska SET_BOOKMARK(&zb, dmu_objset_ds(os)->ds_object,
2757a7741afSMartin Matuska db->db.db_object, db->db_level, db->db_blkid);
2767a7741afSMartin Matuska
2777a7741afSMartin Matuska /*
2787a7741afSMartin Matuska * If there is another read for this dbuf, we will wait for
2797a7741afSMartin Matuska * that to complete first before checking the db_state below.
2807a7741afSMartin Matuska */
2817a7741afSMartin Matuska while (db->db_state == DB_READ)
2827a7741afSMartin Matuska cv_wait(&db->db_changed, &db->db_mtx);
2837a7741afSMartin Matuska
2847a7741afSMartin Matuska err = dmu_buf_get_bp_from_dbuf(db, &bp);
2857a7741afSMartin Matuska if (err) {
2867a7741afSMartin Matuska mutex_exit(&db->db_mtx);
2877a7741afSMartin Matuska goto error;
2887a7741afSMartin Matuska }
2897a7741afSMartin Matuska
2907a7741afSMartin Matuska /*
2917a7741afSMartin Matuska * There is no need to read if this is a hole or the data is
2927a7741afSMartin Matuska * cached. This will not be considered a direct read for IO
2937a7741afSMartin Matuska * accounting in the same way that an ARC hit is not counted.
2947a7741afSMartin Matuska */
2957a7741afSMartin Matuska if (bp == NULL || BP_IS_HOLE(bp) || db->db_state == DB_CACHED) {
2967a7741afSMartin Matuska size_t aoff = offset < db->db.db_offset ?
2977a7741afSMartin Matuska db->db.db_offset - offset : 0;
2987a7741afSMartin Matuska size_t boff = offset > db->db.db_offset ?
2997a7741afSMartin Matuska offset - db->db.db_offset : 0;
3007a7741afSMartin Matuska size_t len = MIN(size - aoff, db->db.db_size - boff);
3017a7741afSMartin Matuska
3027a7741afSMartin Matuska if (db->db_state == DB_CACHED) {
3037a7741afSMartin Matuska /*
3047a7741afSMartin Matuska * We need to untransformed the ARC buf data
3057a7741afSMartin Matuska * before we copy it over.
3067a7741afSMartin Matuska */
3077a7741afSMartin Matuska err = dmu_buf_untransform_direct(db, spa);
3087a7741afSMartin Matuska ASSERT0(err);
3097a7741afSMartin Matuska abd_copy_from_buf_off(data,
3107a7741afSMartin Matuska (char *)db->db.db_data + boff, aoff, len);
3117a7741afSMartin Matuska } else {
3127a7741afSMartin Matuska abd_zero_off(data, aoff, len);
3137a7741afSMartin Matuska }
3147a7741afSMartin Matuska
3157a7741afSMartin Matuska mutex_exit(&db->db_mtx);
3167a7741afSMartin Matuska continue;
3177a7741afSMartin Matuska }
3187a7741afSMartin Matuska
3197a7741afSMartin Matuska mbuf = make_abd_for_dbuf(db, data, offset, size);
3207a7741afSMartin Matuska ASSERT3P(mbuf, !=, NULL);
3217a7741afSMartin Matuska
3227a7741afSMartin Matuska /*
3237a7741afSMartin Matuska * The dbuf mutex (db_mtx) must be held when creating the ZIO
3247a7741afSMartin Matuska * for the read. The BP returned from
3257a7741afSMartin Matuska * dmu_buf_get_bp_from_dbuf() could be from a pending block
3267a7741afSMartin Matuska * clone or a yet to be synced Direct I/O write that is in the
3277a7741afSMartin Matuska * dbuf's dirty record. When zio_read() is called, zio_create()
3287a7741afSMartin Matuska * will make a copy of the BP. However, if zio_read() is called
3297a7741afSMartin Matuska * without the mutex being held then the dirty record from the
3307a7741afSMartin Matuska * dbuf could be freed in dbuf_write_done() resulting in garbage
3317a7741afSMartin Matuska * being set for the zio BP.
3327a7741afSMartin Matuska */
3337a7741afSMartin Matuska zio_t *cio = zio_read(rio, spa, bp, mbuf, db->db.db_size,
3347a7741afSMartin Matuska dmu_read_abd_done, NULL, ZIO_PRIORITY_SYNC_READ,
33587bf66d4SMartin Matuska ZIO_FLAG_CANFAIL | ZIO_FLAG_DIO_READ, &zb);
3367a7741afSMartin Matuska mutex_exit(&db->db_mtx);
3377a7741afSMartin Matuska
3387a7741afSMartin Matuska zfs_racct_read(spa, db->db.db_size, 1, flags);
3397a7741afSMartin Matuska zio_nowait(cio);
3407a7741afSMartin Matuska }
3417a7741afSMartin Matuska
3427a7741afSMartin Matuska dmu_buf_rele_array(dbp, numbufs, FTAG);
3437a7741afSMartin Matuska
3447a7741afSMartin Matuska return (zio_wait(rio));
3457a7741afSMartin Matuska
3467a7741afSMartin Matuska error:
3477a7741afSMartin Matuska dmu_buf_rele_array(dbp, numbufs, FTAG);
3487a7741afSMartin Matuska (void) zio_wait(rio);
3497a7741afSMartin Matuska return (err);
3507a7741afSMartin Matuska }
3517a7741afSMartin Matuska
3527a7741afSMartin Matuska #ifdef _KERNEL
3537a7741afSMartin Matuska int
dmu_read_uio_direct(dnode_t * dn,zfs_uio_t * uio,uint64_t size,dmu_flags_t flags)354*b1c1ee44SMartin Matuska dmu_read_uio_direct(dnode_t *dn, zfs_uio_t *uio, uint64_t size,
355*b1c1ee44SMartin Matuska dmu_flags_t flags)
3567a7741afSMartin Matuska {
3577a7741afSMartin Matuska offset_t offset = zfs_uio_offset(uio);
3587a7741afSMartin Matuska offset_t page_index = (offset - zfs_uio_soffset(uio)) >> PAGESHIFT;
3597a7741afSMartin Matuska int err;
3607a7741afSMartin Matuska
3617a7741afSMartin Matuska ASSERT(uio->uio_extflg & UIO_DIRECT);
3627a7741afSMartin Matuska ASSERT3U(page_index, <, uio->uio_dio.npages);
3637a7741afSMartin Matuska
3647a7741afSMartin Matuska abd_t *data = abd_alloc_from_pages(&uio->uio_dio.pages[page_index],
3657a7741afSMartin Matuska offset & (PAGESIZE - 1), size);
366*b1c1ee44SMartin Matuska err = dmu_read_abd(dn, offset, size, data, flags);
3677a7741afSMartin Matuska abd_free(data);
3687a7741afSMartin Matuska
3697a7741afSMartin Matuska if (err == 0)
3707a7741afSMartin Matuska zfs_uioskip(uio, size);
3717a7741afSMartin Matuska
3727a7741afSMartin Matuska return (err);
3737a7741afSMartin Matuska }
3747a7741afSMartin Matuska
3757a7741afSMartin Matuska int
dmu_write_uio_direct(dnode_t * dn,zfs_uio_t * uio,uint64_t size,dmu_flags_t flags,dmu_tx_t * tx)376*b1c1ee44SMartin Matuska dmu_write_uio_direct(dnode_t *dn, zfs_uio_t *uio, uint64_t size,
377*b1c1ee44SMartin Matuska dmu_flags_t flags, dmu_tx_t *tx)
3787a7741afSMartin Matuska {
3797a7741afSMartin Matuska offset_t offset = zfs_uio_offset(uio);
3807a7741afSMartin Matuska offset_t page_index = (offset - zfs_uio_soffset(uio)) >> PAGESHIFT;
3817a7741afSMartin Matuska int err;
3827a7741afSMartin Matuska
3837a7741afSMartin Matuska ASSERT(uio->uio_extflg & UIO_DIRECT);
3847a7741afSMartin Matuska ASSERT3U(page_index, <, uio->uio_dio.npages);
3857a7741afSMartin Matuska
3867a7741afSMartin Matuska abd_t *data = abd_alloc_from_pages(&uio->uio_dio.pages[page_index],
3877a7741afSMartin Matuska offset & (PAGESIZE - 1), size);
388*b1c1ee44SMartin Matuska err = dmu_write_abd(dn, offset, size, data, flags, tx);
3897a7741afSMartin Matuska abd_free(data);
3907a7741afSMartin Matuska
3917a7741afSMartin Matuska if (err == 0)
3927a7741afSMartin Matuska zfs_uioskip(uio, size);
3937a7741afSMartin Matuska
3947a7741afSMartin Matuska return (err);
3957a7741afSMartin Matuska }
3967a7741afSMartin Matuska #endif /* _KERNEL */
3977a7741afSMartin Matuska
398071ab5a1SMartin Matuska EXPORT_SYMBOL(dmu_read_abd);
399071ab5a1SMartin Matuska EXPORT_SYMBOL(dmu_write_abd);
400