]> granicus.if.org Git - zfs/commitdiff
Add *_by-dnode routines
authorbzzz77 <bzzz.tomas@gmail.com>
Fri, 13 Jan 2017 22:58:41 +0000 (01:58 +0300)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 13 Jan 2017 22:58:41 +0000 (14:58 -0800)
Add *_by_dnode() routines for accessing objects given their
dnode_t *, this is more efficient than accessing the object by
(objset_t *, uint64_t object).  This change converts some but
not all of the existing consumers.  As performance-sensitive
code paths are discovered they should be converted to use
these routines.

Reviewed-by: Matthew Ahrens <mahrens@delphix.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Alex Zhuravlev <bzzz@whamcloud.com>
Closes #5534
Issue #4802

include/sys/dmu.h
include/sys/dmu_tx.h
include/sys/zap.h
module/zfs/dmu.c
module/zfs/dmu_object.c
module/zfs/dmu_tx.c
module/zfs/zap_micro.c

index 9d61d94ee02b7e26669a6af9f6e962b15a3a06b6..3c57de32e192b960a549598f2cca22808abd5a65 100644 (file)
@@ -674,10 +674,17 @@ boolean_t dmu_buf_freeable(dmu_buf_t *);
 
 dmu_tx_t *dmu_tx_create(objset_t *os);
 void dmu_tx_hold_write(dmu_tx_t *tx, uint64_t object, uint64_t off, int len);
+void dmu_tx_hold_write_by_dnode(dmu_tx_t *tx, dnode_t *dn, uint64_t off,
+    int len);
 void dmu_tx_hold_free(dmu_tx_t *tx, uint64_t object, uint64_t off,
     uint64_t len);
+void dmu_tx_hold_free_by_dnode(dmu_tx_t *tx, dnode_t *dn, uint64_t off,
+    uint64_t len);
 void dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name);
+void dmu_tx_hold_zap_by_dnode(dmu_tx_t *tx, dnode_t *dn, int add,
+    const char *name);
 void dmu_tx_hold_bonus(dmu_tx_t *tx, uint64_t object);
+void dmu_tx_hold_bonus_by_dnode(dmu_tx_t *tx, dnode_t *dn);
 void dmu_tx_hold_spill(dmu_tx_t *tx, uint64_t object);
 void dmu_tx_hold_sa(dmu_tx_t *tx, struct sa_handle *hdl, boolean_t may_grow);
 void dmu_tx_hold_sa_create(dmu_tx_t *tx, int total_size);
@@ -727,8 +734,12 @@ int dmu_free_long_object(objset_t *os, uint64_t object);
 #define        DMU_READ_NO_PREFETCH    1 /* don't prefetch */
 int dmu_read(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
        void *buf, uint32_t flags);
+int dmu_read_by_dnode(dnode_t *dn, uint64_t offset, uint64_t size, void *buf,
+    uint32_t flags);
 void dmu_write(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
        const void *buf, dmu_tx_t *tx);
+void dmu_write_by_dnode(dnode_t *dn, uint64_t offset, uint64_t size,
+    const void *buf, dmu_tx_t *tx);
 void dmu_prealloc(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
        dmu_tx_t *tx);
 #ifdef _KERNEL
index c70c97da03f2806dfcd894dfce02eb76b9aebd3f..308b1eaa7aec124bd21a82f27fcd7bb77091bc0d 100644 (file)
@@ -171,7 +171,7 @@ extern dmu_tx_t *dmu_tx_create_assigned(struct dsl_pool *dp, uint64_t txg);
 dmu_tx_t *dmu_tx_create_dd(dsl_dir_t *dd);
 int dmu_tx_is_syncing(dmu_tx_t *tx);
 int dmu_tx_private_ok(dmu_tx_t *tx);
-void dmu_tx_add_new_object(dmu_tx_t *tx, objset_t *os, uint64_t object);
+void dmu_tx_add_new_object(dmu_tx_t *tx, objset_t *os, dnode_t *dn);
 void dmu_tx_willuse_space(dmu_tx_t *tx, int64_t delta);
 void dmu_tx_dirty_buf(dmu_tx_t *tx, struct dmu_buf_impl *db);
 int dmu_tx_holds(dmu_tx_t *tx, uint64_t object);
index c4169029adf8eee131fe8e3ac978ae0f24fe1fa3..ba75ac58f52f9234e835405a3315725b60324421 100644 (file)
@@ -255,6 +255,9 @@ int zap_count_write_by_dnode(dnode_t *dn, const char *name,
 int zap_add(objset_t *ds, uint64_t zapobj, const char *key,
     int integer_size, uint64_t num_integers,
     const void *val, dmu_tx_t *tx);
+int zap_add_by_dnode(dnode_t *dn, const char *key,
+    int integer_size, uint64_t num_integers,
+    const void *val, dmu_tx_t *tx);
 int zap_add_uint64(objset_t *ds, uint64_t zapobj, const uint64_t *key,
     int key_numints, int integer_size, uint64_t num_integers,
     const void *val, dmu_tx_t *tx);
@@ -294,6 +297,7 @@ int zap_length_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
 int zap_remove(objset_t *ds, uint64_t zapobj, const char *name, dmu_tx_t *tx);
 int zap_remove_norm(objset_t *ds, uint64_t zapobj, const char *name,
     matchtype_t mt, dmu_tx_t *tx);
+int zap_remove_by_dnode(dnode_t *dn, const char *name, dmu_tx_t *tx);
 int zap_remove_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
     int key_numints, dmu_tx_t *tx);
 
index b5ddec2d9e8b92aa5d678cdef96b4af1731ff39e..82bcedf0d56884a070199b78fefcee7bdc6dcd3e 100644 (file)
@@ -822,17 +822,12 @@ dmu_free_range(objset_t *os, uint64_t object, uint64_t offset,
        return (0);
 }
 
-int
-dmu_read(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
+static int
+dmu_read_impl(dnode_t *dn, uint64_t offset, uint64_t size,
     void *buf, uint32_t flags)
 {
-       dnode_t *dn;
        dmu_buf_t **dbp;
-       int numbufs, err;
-
-       err = dnode_hold(os, object, FTAG, &dn);
-       if (err)
-               return (err);
+       int numbufs, err = 0;
 
        /*
         * Deal with odd block sizes, where there can't be data past the first
@@ -877,22 +872,37 @@ dmu_read(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
                }
                dmu_buf_rele_array(dbp, numbufs, FTAG);
        }
-       dnode_rele(dn, FTAG);
        return (err);
 }
 
-void
-dmu_write(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
-    const void *buf, dmu_tx_t *tx)
+int
+dmu_read(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
+    void *buf, uint32_t flags)
 {
-       dmu_buf_t **dbp;
-       int numbufs, i;
+       dnode_t *dn;
+       int err;
 
-       if (size == 0)
-               return;
+       err = dnode_hold(os, object, FTAG, &dn);
+       if (err != 0)
+               return (err);
 
-       VERIFY0(dmu_buf_hold_array(os, object, offset, size,
-           FALSE, FTAG, &numbufs, &dbp));
+       err = dmu_read_impl(dn, offset, size, buf, flags);
+       dnode_rele(dn, FTAG);
+       return (err);
+}
+
+int
+dmu_read_by_dnode(dnode_t *dn, uint64_t offset, uint64_t size, void *buf,
+    uint32_t flags)
+{
+       return (dmu_read_impl(dn, offset, size, buf, flags));
+}
+
+static void
+dmu_write_impl(dmu_buf_t **dbp, int numbufs, uint64_t offset, uint64_t size,
+    const void *buf, dmu_tx_t *tx)
+{
+       int i;
 
        for (i = 0; i < numbufs; i++) {
                uint64_t tocpy;
@@ -920,6 +930,37 @@ dmu_write(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
                size -= tocpy;
                buf = (char *)buf + tocpy;
        }
+}
+
+void
+dmu_write(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
+    const void *buf, dmu_tx_t *tx)
+{
+       dmu_buf_t **dbp;
+       int numbufs;
+
+       if (size == 0)
+               return;
+
+       VERIFY0(dmu_buf_hold_array(os, object, offset, size,
+           FALSE, FTAG, &numbufs, &dbp));
+       dmu_write_impl(dbp, numbufs, offset, size, buf, tx);
+       dmu_buf_rele_array(dbp, numbufs, FTAG);
+}
+
+void
+dmu_write_by_dnode(dnode_t *dn, uint64_t offset, uint64_t size,
+    const void *buf, dmu_tx_t *tx)
+{
+       dmu_buf_t **dbp;
+       int numbufs;
+
+       if (size == 0)
+               return;
+
+       VERIFY0(dmu_buf_hold_array_by_dnode(dn, offset, size,
+           FALSE, FTAG, &numbufs, &dbp, DMU_READ_PREFETCH));
+       dmu_write_impl(dbp, numbufs, offset, size, buf, tx);
        dmu_buf_rele_array(dbp, numbufs, FTAG);
 }
 
@@ -2102,7 +2143,9 @@ EXPORT_SYMBOL(dmu_free_range);
 EXPORT_SYMBOL(dmu_free_long_range);
 EXPORT_SYMBOL(dmu_free_long_object);
 EXPORT_SYMBOL(dmu_read);
+EXPORT_SYMBOL(dmu_read_by_dnode);
 EXPORT_SYMBOL(dmu_write);
+EXPORT_SYMBOL(dmu_write_by_dnode);
 EXPORT_SYMBOL(dmu_prealloc);
 EXPORT_SYMBOL(dmu_object_info);
 EXPORT_SYMBOL(dmu_object_info_from_dnode);
index e54043fc3e3a47a7ad78a2b65f8c5aeb3d64aa1a..488ca2155d4803d9c7486a5a2cf6c8f7d43f5ce5 100644 (file)
@@ -129,11 +129,11 @@ dmu_object_alloc_dnsize(objset_t *os, dmu_object_type_t ot, int blocksize,
        }
 
        dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, dn_slots, tx);
-       dnode_rele(dn, FTAG);
-
        mutex_exit(&os->os_obj_lock);
 
-       dmu_tx_add_new_object(tx, os, object);
+       dmu_tx_add_new_object(tx, os, dn);
+       dnode_rele(dn, FTAG);
+
        return (object);
 }
 
@@ -168,9 +168,10 @@ dmu_object_claim_dnsize(objset_t *os, uint64_t object, dmu_object_type_t ot,
                return (err);
 
        dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, dn_slots, tx);
+       dmu_tx_add_new_object(tx, os, dn);
+
        dnode_rele(dn, FTAG);
 
-       dmu_tx_add_new_object(tx, os, object);
        return (0);
 }
 
index f0119963ced493c802f83ca9174508d12fec946e..8462432d1b2ad309c5bc5adb32157054f40f814b 100644 (file)
@@ -113,21 +113,14 @@ dmu_tx_private_ok(dmu_tx_t *tx)
 }
 
 static dmu_tx_hold_t *
-dmu_tx_hold_object_impl(dmu_tx_t *tx, objset_t *os, uint64_t object,
-    enum dmu_tx_hold_type type, uint64_t arg1, uint64_t arg2)
+dmu_tx_hold_dnode_impl(dmu_tx_t *tx, dnode_t *dn, enum dmu_tx_hold_type type,
+    uint64_t arg1, uint64_t arg2)
 {
        dmu_tx_hold_t *txh;
-       dnode_t *dn = NULL;
-       int err;
-
-       if (object != DMU_NEW_OBJECT) {
-               err = dnode_hold(os, object, tx, &dn);
-               if (err) {
-                       tx->tx_err = err;
-                       return (NULL);
-               }
 
-               if (err == 0 && tx->tx_txg != 0) {
+       if (dn != NULL) {
+               refcount_add(&dn->dn_holds, tx);
+               if (tx->tx_txg != 0) {
                        mutex_enter(&dn->dn_mtx);
                        /*
                         * dn->dn_assigned_txg == tx->tx_txg doesn't pose a
@@ -154,17 +147,36 @@ dmu_tx_hold_object_impl(dmu_tx_t *tx, objset_t *os, uint64_t object,
        return (txh);
 }
 
+static dmu_tx_hold_t *
+dmu_tx_hold_object_impl(dmu_tx_t *tx, objset_t *os, uint64_t object,
+    enum dmu_tx_hold_type type, uint64_t arg1, uint64_t arg2)
+{
+       dnode_t *dn = NULL;
+       dmu_tx_hold_t *txh;
+       int err;
+
+       if (object != DMU_NEW_OBJECT) {
+               err = dnode_hold(os, object, FTAG, &dn);
+               if (err) {
+                       tx->tx_err = err;
+                       return (NULL);
+               }
+       }
+       txh = dmu_tx_hold_dnode_impl(tx, dn, type, arg1, arg2);
+       if (dn != NULL)
+               dnode_rele(dn, FTAG);
+       return (txh);
+}
+
 void
-dmu_tx_add_new_object(dmu_tx_t *tx, objset_t *os, uint64_t object)
+dmu_tx_add_new_object(dmu_tx_t *tx, objset_t *os, dnode_t *dn)
 {
        /*
         * If we're syncing, they can manipulate any object anyhow, and
         * the hold on the dnode_t can cause problems.
         */
-       if (!dmu_tx_is_syncing(tx)) {
-               (void) dmu_tx_hold_object_impl(tx, os,
-                   object, THT_NEWOBJECT, 0, 0);
-       }
+       if (!dmu_tx_is_syncing(tx))
+               (void) dmu_tx_hold_dnode_impl(tx, dn, THT_NEWOBJECT, 0, 0);
 }
 
 static int
@@ -441,6 +453,23 @@ dmu_tx_hold_write(dmu_tx_t *tx, uint64_t object, uint64_t off, int len)
        dmu_tx_count_dnode(txh);
 }
 
+void
+dmu_tx_hold_write_by_dnode(dmu_tx_t *tx, dnode_t *dn, uint64_t off, int len)
+{
+       dmu_tx_hold_t *txh;
+
+       ASSERT(tx->tx_txg == 0);
+       ASSERT(len <= DMU_MAX_ACCESS);
+       ASSERT(len == 0 || UINT64_MAX - off >= len - 1);
+
+       txh = dmu_tx_hold_dnode_impl(tx, dn, THT_WRITE, off, len);
+       if (txh == NULL)
+               return;
+
+       dmu_tx_count_write(txh, off, len);
+       dmu_tx_count_dnode(txh);
+}
+
 static void
 dmu_tx_count_free(dmu_tx_hold_t *txh, uint64_t off, uint64_t len)
 {
@@ -636,20 +665,17 @@ dmu_tx_mark_netfree(dmu_tx_t *tx)
        txh->txh_space_tofree = txh->txh_space_tounref = 1024 * 1024 * 1024;
 }
 
-void
-dmu_tx_hold_free(dmu_tx_t *tx, uint64_t object, uint64_t off, uint64_t len)
+static void
+dmu_tx_hold_free_impl(dmu_tx_hold_t *txh, uint64_t off, uint64_t len)
 {
-       dmu_tx_hold_t *txh;
+       dmu_tx_t *tx;
        dnode_t *dn;
        int err;
        zio_t *zio;
 
+       tx = txh->txh_tx;
        ASSERT(tx->tx_txg == 0);
 
-       txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
-           object, THT_FREE, off, len);
-       if (txh == NULL)
-               return;
        dn = txh->txh_dnode;
        dmu_tx_count_dnode(txh);
 
@@ -731,9 +757,32 @@ dmu_tx_hold_free(dmu_tx_t *tx, uint64_t object, uint64_t off, uint64_t len)
 }
 
 void
-dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name)
+dmu_tx_hold_free(dmu_tx_t *tx, uint64_t object, uint64_t off, uint64_t len)
+{
+       dmu_tx_hold_t *txh;
+
+       txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
+           object, THT_FREE, off, len);
+       if (txh == NULL)
+               return;
+       (void) dmu_tx_hold_free_impl(txh, off, len);
+}
+
+void
+dmu_tx_hold_free_by_dnode(dmu_tx_t *tx, dnode_t *dn, uint64_t off, uint64_t len)
 {
        dmu_tx_hold_t *txh;
+
+       txh = dmu_tx_hold_dnode_impl(tx, dn, THT_FREE, off, len);
+       if (txh == NULL)
+               return;
+       (void) dmu_tx_hold_free_impl(txh, off, len);
+}
+
+static void
+dmu_tx_hold_zap_impl(dmu_tx_hold_t *txh, int add, const char *name)
+{
+       dmu_tx_t *tx = txh->txh_tx;
        dnode_t *dn;
        dsl_dataset_phys_t *ds_phys;
        uint64_t nblocks;
@@ -741,10 +790,6 @@ dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name)
 
        ASSERT(tx->tx_txg == 0);
 
-       txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
-           object, THT_ZAP, add, (uintptr_t)name);
-       if (txh == NULL)
-               return;
        dn = txh->txh_dnode;
 
        dmu_tx_count_dnode(txh);
@@ -817,6 +862,34 @@ dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name)
                        txh->txh_space_tooverwrite += 3 << dn->dn_indblkshift;
 }
 
+void
+dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name)
+{
+       dmu_tx_hold_t *txh;
+
+       ASSERT(tx->tx_txg == 0);
+
+       txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
+           object, THT_ZAP, add, (uintptr_t)name);
+       if (txh == NULL)
+               return;
+       dmu_tx_hold_zap_impl(txh, add, name);
+}
+
+void
+dmu_tx_hold_zap_by_dnode(dmu_tx_t *tx, dnode_t *dn, int add, const char *name)
+{
+       dmu_tx_hold_t *txh;
+
+       ASSERT(tx->tx_txg == 0);
+       ASSERT(dn != NULL);
+
+       txh = dmu_tx_hold_dnode_impl(tx, dn, THT_ZAP, add, (uintptr_t)name);
+       if (txh == NULL)
+               return;
+       dmu_tx_hold_zap_impl(txh, add, name);
+}
+
 void
 dmu_tx_hold_bonus(dmu_tx_t *tx, uint64_t object)
 {
@@ -830,6 +903,18 @@ dmu_tx_hold_bonus(dmu_tx_t *tx, uint64_t object)
                dmu_tx_count_dnode(txh);
 }
 
+void
+dmu_tx_hold_bonus_by_dnode(dmu_tx_t *tx, dnode_t *dn)
+{
+       dmu_tx_hold_t *txh;
+
+       ASSERT(tx->tx_txg == 0);
+
+       txh = dmu_tx_hold_dnode_impl(tx, dn, THT_BONUS, 0, 0);
+       if (txh)
+               dmu_tx_count_dnode(txh);
+}
+
 void
 dmu_tx_hold_space(dmu_tx_t *tx, uint64_t space)
 {
@@ -1704,9 +1789,13 @@ dmu_tx_fini(void)
 #if defined(_KERNEL) && defined(HAVE_SPL)
 EXPORT_SYMBOL(dmu_tx_create);
 EXPORT_SYMBOL(dmu_tx_hold_write);
+EXPORT_SYMBOL(dmu_tx_hold_write_by_dnode);
 EXPORT_SYMBOL(dmu_tx_hold_free);
+EXPORT_SYMBOL(dmu_tx_hold_free_by_dnode);
 EXPORT_SYMBOL(dmu_tx_hold_zap);
+EXPORT_SYMBOL(dmu_tx_hold_zap_by_dnode);
 EXPORT_SYMBOL(dmu_tx_hold_bonus);
+EXPORT_SYMBOL(dmu_tx_hold_bonus_by_dnode);
 EXPORT_SYMBOL(dmu_tx_abort);
 EXPORT_SYMBOL(dmu_tx_assign);
 EXPORT_SYMBOL(dmu_tx_wait);
index 1ee990582bc5fb92ce245c6f236b685e2a53a361..7cf7e927ccf18c5df070f66e5fae2ae1bbe776e9 100644 (file)
@@ -1128,34 +1128,30 @@ again:
        cmn_err(CE_PANIC, "out of entries!");
 }
 
-int
-zap_add(objset_t *os, uint64_t zapobj, const char *key,
+static int
+zap_add_impl(zap_t *zap, const char *key,
     int integer_size, uint64_t num_integers,
-    const void *val, dmu_tx_t *tx)
+    const void *val, dmu_tx_t *tx, void *tag)
 {
-       zap_t *zap;
-       int err;
+       int err = 0;
        mzap_ent_t *mze;
        const uint64_t *intval = val;
        zap_name_t *zn;
 
-       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, FTAG, &zap);
-       if (err)
-               return (err);
        zn = zap_name_alloc(zap, key, MT_EXACT);
        if (zn == NULL) {
-               zap_unlockdir(zap, FTAG);
+               zap_unlockdir(zap, tag);
                return (SET_ERROR(ENOTSUP));
        }
        if (!zap->zap_ismicro) {
-               err = fzap_add(zn, integer_size, num_integers, val, FTAG, tx);
+               err = fzap_add(zn, integer_size, num_integers, val, tag, tx);
                zap = zn->zn_zap;       /* fzap_add() may change zap */
        } else if (integer_size != 8 || num_integers != 1 ||
            strlen(key) >= MZAP_NAME_LEN) {
-               err = mzap_upgrade(&zn->zn_zap, FTAG, tx, 0);
+               err = mzap_upgrade(&zn->zn_zap, tag, tx, 0);
                if (err == 0) {
                        err = fzap_add(zn, integer_size, num_integers, val,
-                           FTAG, tx);
+                           tag, tx);
                }
                zap = zn->zn_zap;       /* fzap_add() may change zap */
        } else {
@@ -1168,8 +1164,39 @@ zap_add(objset_t *os, uint64_t zapobj, const char *key,
        }
        ASSERT(zap == zn->zn_zap);
        zap_name_free(zn);
-       if (zap != NULL)        /* may be NULL if fzap_add() failed */
-               zap_unlockdir(zap, FTAG);
+       zap_unlockdir(zap, tag);
+       return (err);
+}
+
+int
+zap_add(objset_t *os, uint64_t zapobj, const char *key,
+    int integer_size, uint64_t num_integers,
+    const void *val, dmu_tx_t *tx)
+{
+       zap_t *zap;
+       int err;
+
+       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, FTAG, &zap);
+       if (err != 0)
+               return (err);
+       err = zap_add_impl(zap, key, integer_size, num_integers, val, tx, FTAG);
+       /* zap_add_impl() calls zap_unlockdir() */
+       return (err);
+}
+
+int
+zap_add_by_dnode(dnode_t *dn, const char *key,
+    int integer_size, uint64_t num_integers,
+    const void *val, dmu_tx_t *tx)
+{
+       zap_t *zap;
+       int err;
+
+       err = zap_lockdir_by_dnode(dn, tx, RW_WRITER, TRUE, TRUE, FTAG, &zap);
+       if (err != 0)
+               return (err);
+       err = zap_add_impl(zap, key, integer_size, num_integers, val, tx, FTAG);
+       /* zap_add_impl() calls zap_unlockdir() */
        return (err);
 }
 
@@ -1288,23 +1315,17 @@ zap_remove(objset_t *os, uint64_t zapobj, const char *name, dmu_tx_t *tx)
        return (zap_remove_norm(os, zapobj, name, MT_EXACT, tx));
 }
 
-int
-zap_remove_norm(objset_t *os, uint64_t zapobj, const char *name,
+static int
+zap_remove_impl(zap_t *zap, const char *name,
     matchtype_t mt, dmu_tx_t *tx)
 {
-       zap_t *zap;
-       int err;
        mzap_ent_t *mze;
        zap_name_t *zn;
+       int err = 0;
 
-       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, FALSE, FTAG, &zap);
-       if (err)
-               return (err);
        zn = zap_name_alloc(zap, name, mt);
-       if (zn == NULL) {
-               zap_unlockdir(zap, FTAG);
+       if (zn == NULL)
                return (SET_ERROR(ENOTSUP));
-       }
        if (!zap->zap_ismicro) {
                err = fzap_remove(zn, tx);
        } else {
@@ -1319,6 +1340,34 @@ zap_remove_norm(objset_t *os, uint64_t zapobj, const char *name,
                }
        }
        zap_name_free(zn);
+       return (err);
+}
+
+int
+zap_remove_norm(objset_t *os, uint64_t zapobj, const char *name,
+    matchtype_t mt, dmu_tx_t *tx)
+{
+       zap_t *zap;
+       int err;
+
+       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, FALSE, FTAG, &zap);
+       if (err)
+               return (err);
+       err = zap_remove_impl(zap, name, mt, tx);
+       zap_unlockdir(zap, FTAG);
+       return (err);
+}
+
+int
+zap_remove_by_dnode(dnode_t *dn, const char *name, dmu_tx_t *tx)
+{
+       zap_t *zap;
+       int err;
+
+       err = zap_lockdir_by_dnode(dn, tx, RW_WRITER, TRUE, FALSE, FTAG, &zap);
+       if (err)
+               return (err);
+       err = zap_remove_impl(zap, name, MT_EXACT, tx);
        zap_unlockdir(zap, FTAG);
        return (err);
 }
@@ -1589,6 +1638,7 @@ EXPORT_SYMBOL(zap_create_claim_norm);
 EXPORT_SYMBOL(zap_create_claim_norm_dnsize);
 EXPORT_SYMBOL(zap_destroy);
 EXPORT_SYMBOL(zap_lookup);
+EXPORT_SYMBOL(zap_lookup_by_dnode);
 EXPORT_SYMBOL(zap_lookup_norm);
 EXPORT_SYMBOL(zap_lookup_uint64);
 EXPORT_SYMBOL(zap_contains);
@@ -1596,12 +1646,14 @@ EXPORT_SYMBOL(zap_prefetch);
 EXPORT_SYMBOL(zap_prefetch_uint64);
 EXPORT_SYMBOL(zap_count_write_by_dnode);
 EXPORT_SYMBOL(zap_add);
+EXPORT_SYMBOL(zap_add_by_dnode);
 EXPORT_SYMBOL(zap_add_uint64);
 EXPORT_SYMBOL(zap_update);
 EXPORT_SYMBOL(zap_update_uint64);
 EXPORT_SYMBOL(zap_length);
 EXPORT_SYMBOL(zap_length_uint64);
 EXPORT_SYMBOL(zap_remove);
+EXPORT_SYMBOL(zap_remove_by_dnode);
 EXPORT_SYMBOL(zap_remove_norm);
 EXPORT_SYMBOL(zap_remove_uint64);
 EXPORT_SYMBOL(zap_count);