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