1*61145dc2SMartin 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 * 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 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 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 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 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 2107a7741afSMartin Matuska dmu_write_abd(dnode_t *dn, uint64_t offset, uint64_t size, 2117a7741afSMartin Matuska abd_t *data, uint32_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 2497a7741afSMartin Matuska dmu_read_abd(dnode_t *dn, uint64_t offset, uint64_t size, 2507a7741afSMartin Matuska abd_t *data, uint32_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 3547a7741afSMartin Matuska dmu_read_uio_direct(dnode_t *dn, zfs_uio_t *uio, uint64_t size) 3557a7741afSMartin Matuska { 3567a7741afSMartin Matuska offset_t offset = zfs_uio_offset(uio); 3577a7741afSMartin Matuska offset_t page_index = (offset - zfs_uio_soffset(uio)) >> PAGESHIFT; 3587a7741afSMartin Matuska int err; 3597a7741afSMartin Matuska 3607a7741afSMartin Matuska ASSERT(uio->uio_extflg & UIO_DIRECT); 3617a7741afSMartin Matuska ASSERT3U(page_index, <, uio->uio_dio.npages); 3627a7741afSMartin Matuska 3637a7741afSMartin Matuska abd_t *data = abd_alloc_from_pages(&uio->uio_dio.pages[page_index], 3647a7741afSMartin Matuska offset & (PAGESIZE - 1), size); 3657a7741afSMartin Matuska err = dmu_read_abd(dn, offset, size, data, DMU_DIRECTIO); 3667a7741afSMartin Matuska abd_free(data); 3677a7741afSMartin Matuska 3687a7741afSMartin Matuska if (err == 0) 3697a7741afSMartin Matuska zfs_uioskip(uio, size); 3707a7741afSMartin Matuska 3717a7741afSMartin Matuska return (err); 3727a7741afSMartin Matuska } 3737a7741afSMartin Matuska 3747a7741afSMartin Matuska int 3757a7741afSMartin Matuska dmu_write_uio_direct(dnode_t *dn, zfs_uio_t *uio, uint64_t size, dmu_tx_t *tx) 3767a7741afSMartin Matuska { 3777a7741afSMartin Matuska offset_t offset = zfs_uio_offset(uio); 3787a7741afSMartin Matuska offset_t page_index = (offset - zfs_uio_soffset(uio)) >> PAGESHIFT; 3797a7741afSMartin Matuska int err; 3807a7741afSMartin Matuska 3817a7741afSMartin Matuska ASSERT(uio->uio_extflg & UIO_DIRECT); 3827a7741afSMartin Matuska ASSERT3U(page_index, <, uio->uio_dio.npages); 3837a7741afSMartin Matuska 3847a7741afSMartin Matuska abd_t *data = abd_alloc_from_pages(&uio->uio_dio.pages[page_index], 3857a7741afSMartin Matuska offset & (PAGESIZE - 1), size); 3867a7741afSMartin Matuska err = dmu_write_abd(dn, offset, size, data, DMU_DIRECTIO, tx); 3877a7741afSMartin Matuska abd_free(data); 3887a7741afSMartin Matuska 3897a7741afSMartin Matuska if (err == 0) 3907a7741afSMartin Matuska zfs_uioskip(uio, size); 3917a7741afSMartin Matuska 3927a7741afSMartin Matuska return (err); 3937a7741afSMartin Matuska } 3947a7741afSMartin Matuska #endif /* _KERNEL */ 3957a7741afSMartin Matuska 3967a7741afSMartin Matuska EXPORT_SYMBOL(dmu_read_uio_direct); 3977a7741afSMartin Matuska EXPORT_SYMBOL(dmu_write_uio_direct); 398