From e1a4e9c051900e71e308e0fb1399097505e72ee9 Mon Sep 17 00:00:00 2001 From: Matthew Ahrens Date: Wed, 20 Jul 2016 15:39:55 -0700 Subject: [PATCH 1/2] 7003 zap_lockdir() should tag hold zap_lockdir() / zap_unlockdir() should take a "void *tag" argument which tags the hold on the zap. This will help diagnose programming errors which misuse the hold on the ZAP. Sponsored by: Intel Corp. --- include/sys/dmu.h | 2 + include/sys/zap_impl.h | 12 ++- module/zfs/dbuf.c | 7 ++ module/zfs/zap.c | 33 ++++--- module/zfs/zap_micro.c | 205 ++++++++++++++++++++++++----------------- 5 files changed, 154 insertions(+), 105 deletions(-) diff --git a/include/sys/dmu.h b/include/sys/dmu.h index 87a8a40eb782..98da92890226 100644 --- a/include/sys/dmu.h +++ b/include/sys/dmu.h @@ -619,6 +619,8 @@ void *dmu_buf_remove_user(dmu_buf_t *db, dmu_buf_user_t *user); */ void *dmu_buf_get_user(dmu_buf_t *db); +objset_t *dmu_buf_get_objset(dmu_buf_t *db); + /* Block until any in-progress dmu buf user evictions complete. */ void dmu_buf_user_evict_wait(void); diff --git a/include/sys/zap_impl.h b/include/sys/zap_impl.h index bfd43e31da80..7b6d1b553b80 100644 --- a/include/sys/zap_impl.h +++ b/include/sys/zap_impl.h @@ -21,6 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. + * Copyright (c) 2013, 2016 by Delphix. All rights reserved. */ #ifndef _SYS_ZAP_IMPL_H @@ -195,8 +196,8 @@ typedef struct zap_name { boolean_t zap_match(zap_name_t *zn, const char *matchname); int zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx, - krw_t lti, boolean_t fatreader, boolean_t adding, zap_t **zapp); -void zap_unlockdir(zap_t *zap); + krw_t lti, boolean_t fatreader, boolean_t adding, void *tag, zap_t **zapp); +void zap_unlockdir(zap_t *zap, void *tag); void zap_evict(void *dbu); zap_name_t *zap_name_alloc(zap_t *zap, const char *key, matchtype_t mt); void zap_name_free(zap_name_t *zn); @@ -215,9 +216,10 @@ void fzap_prefetch(zap_name_t *zn); int fzap_count_write(zap_name_t *zn, int add, uint64_t *towrite, uint64_t *tooverwrite); int fzap_add(zap_name_t *zn, uint64_t integer_size, uint64_t num_integers, - const void *val, dmu_tx_t *tx); + const void *val, void *tag, dmu_tx_t *tx); int fzap_update(zap_name_t *zn, - int integer_size, uint64_t num_integers, const void *val, dmu_tx_t *tx); + int integer_size, uint64_t num_integers, const void *val, + void *tag, dmu_tx_t *tx); int fzap_length(zap_name_t *zn, uint64_t *integer_size, uint64_t *num_integers); int fzap_remove(zap_name_t *zn, dmu_tx_t *tx); @@ -227,7 +229,7 @@ void zap_put_leaf(struct zap_leaf *l); int fzap_add_cd(zap_name_t *zn, uint64_t integer_size, uint64_t num_integers, - const void *val, uint32_t cd, dmu_tx_t *tx); + const void *val, uint32_t cd, void *tag, dmu_tx_t *tx); void fzap_upgrade(zap_t *zap, dmu_tx_t *tx, zap_flags_t flags); #ifdef __cplusplus diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index af2f20d63b5c..5b3b4f016fa9 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -2808,6 +2808,13 @@ dmu_buf_get_blkptr(dmu_buf_t *db) return (dbi->db_blkptr); } +objset_t * +dmu_buf_get_objset(dmu_buf_t *db) +{ + dmu_buf_impl_t *dbi = (dmu_buf_impl_t *)db; + return (dbi->db_objset); +} + static void dbuf_check_blkptr(dnode_t *dn, dmu_buf_impl_t *db) { diff --git a/module/zfs/zap.c b/module/zfs/zap.c index 9e4f05049b21..d0d438fe39e4 100644 --- a/module/zfs/zap.c +++ b/module/zfs/zap.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 by Delphix. All rights reserved. + * Copyright (c) 2012, 2016 by Delphix. All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. */ @@ -605,7 +605,8 @@ zap_deref_leaf(zap_t *zap, uint64_t h, dmu_tx_t *tx, krw_t lt, zap_leaf_t **lp) } static int -zap_expand_leaf(zap_name_t *zn, zap_leaf_t *l, dmu_tx_t *tx, zap_leaf_t **lp) +zap_expand_leaf(zap_name_t *zn, zap_leaf_t *l, + void *tag, dmu_tx_t *tx, zap_leaf_t **lp) { zap_t *zap = zn->zn_zap; uint64_t hash = zn->zn_hash; @@ -627,9 +628,9 @@ zap_expand_leaf(zap_name_t *zn, zap_leaf_t *l, dmu_tx_t *tx, zap_leaf_t **lp) uint64_t object = zap->zap_object; zap_put_leaf(l); - zap_unlockdir(zap); + zap_unlockdir(zap, tag); err = zap_lockdir(os, object, tx, RW_WRITER, - FALSE, FALSE, &zn->zn_zap); + FALSE, FALSE, tag, &zn->zn_zap); zap = zn->zn_zap; if (err) return (err); @@ -692,7 +693,8 @@ zap_expand_leaf(zap_name_t *zn, zap_leaf_t *l, dmu_tx_t *tx, zap_leaf_t **lp) } static void -zap_put_leaf_maybe_grow_ptrtbl(zap_name_t *zn, zap_leaf_t *l, dmu_tx_t *tx) +zap_put_leaf_maybe_grow_ptrtbl(zap_name_t *zn, zap_leaf_t *l, + void *tag, dmu_tx_t *tx) { zap_t *zap = zn->zn_zap; int shift = zap_f_phys(zap)->zap_ptrtbl.zt_shift; @@ -712,9 +714,9 @@ zap_put_leaf_maybe_grow_ptrtbl(zap_name_t *zn, zap_leaf_t *l, dmu_tx_t *tx) objset_t *os = zap->zap_objset; uint64_t zapobj = zap->zap_object; - zap_unlockdir(zap); + zap_unlockdir(zap, tag); err = zap_lockdir(os, zapobj, tx, - RW_WRITER, FALSE, FALSE, &zn->zn_zap); + RW_WRITER, FALSE, FALSE, tag, &zn->zn_zap); zap = zn->zn_zap; if (err) return; @@ -804,7 +806,7 @@ fzap_lookup(zap_name_t *zn, int fzap_add_cd(zap_name_t *zn, uint64_t integer_size, uint64_t num_integers, - const void *val, uint32_t cd, dmu_tx_t *tx) + const void *val, uint32_t cd, void *tag, dmu_tx_t *tx) { zap_leaf_t *l; int err; @@ -833,7 +835,7 @@ fzap_add_cd(zap_name_t *zn, if (err == 0) { zap_increment_num_entries(zap, 1, tx); } else if (err == EAGAIN) { - err = zap_expand_leaf(zn, l, tx, &l); + err = zap_expand_leaf(zn, l, tag, tx, &l); zap = zn->zn_zap; /* zap_expand_leaf() may change zap */ if (err == 0) goto retry; @@ -841,26 +843,27 @@ fzap_add_cd(zap_name_t *zn, out: if (zap != NULL) - zap_put_leaf_maybe_grow_ptrtbl(zn, l, tx); + zap_put_leaf_maybe_grow_ptrtbl(zn, l, tag, tx); return (err); } int fzap_add(zap_name_t *zn, uint64_t integer_size, uint64_t num_integers, - const void *val, dmu_tx_t *tx) + const void *val, void *tag, dmu_tx_t *tx) { int err = fzap_check(zn, integer_size, num_integers); if (err != 0) return (err); return (fzap_add_cd(zn, integer_size, num_integers, - val, ZAP_NEED_CD, tx)); + val, ZAP_NEED_CD, tag, tx)); } int fzap_update(zap_name_t *zn, - int integer_size, uint64_t num_integers, const void *val, dmu_tx_t *tx) + int integer_size, uint64_t num_integers, const void *val, + void *tag, dmu_tx_t *tx) { zap_leaf_t *l; int err, create; @@ -890,14 +893,14 @@ fzap_update(zap_name_t *zn, } if (err == EAGAIN) { - err = zap_expand_leaf(zn, l, tx, &l); + err = zap_expand_leaf(zn, l, tag, tx, &l); zap = zn->zn_zap; /* zap_expand_leaf() may change zap */ if (err == 0) goto retry; } if (zap != NULL) - zap_put_leaf_maybe_grow_ptrtbl(zn, l, tx); + zap_put_leaf_maybe_grow_ptrtbl(zn, l, tag, tx); return (err); } diff --git a/module/zfs/zap_micro.c b/module/zfs/zap_micro.c index f3153cc18133..fcd33367db14 100644 --- a/module/zfs/zap_micro.c +++ b/module/zfs/zap_micro.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, 2014 by Delphix. All rights reserved. + * Copyright (c) 2011, 2016 by Delphix. All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. */ @@ -42,7 +42,8 @@ extern inline mzap_phys_t *zap_m_phys(zap_t *zap); -static int mzap_upgrade(zap_t **zapp, dmu_tx_t *tx, zap_flags_t flags); +static int mzap_upgrade(zap_t **zapp, + void *tag, dmu_tx_t *tx, zap_flags_t flags); uint64_t zap_getflags(zap_t *zap) @@ -456,21 +457,19 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db) return (winner); } -int -zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx, +static int +zap_lockdir_impl(dmu_buf_t *db, void *tag, dmu_tx_t *tx, krw_t lti, boolean_t fatreader, boolean_t adding, zap_t **zapp) { dmu_object_info_t doi; zap_t *zap; - dmu_buf_t *db; krw_t lt; - int err; - *zapp = NULL; + objset_t *os = dmu_buf_get_objset(db); + uint64_t obj = db->db_object; - err = dmu_buf_hold(os, obj, 0, NULL, &db, DMU_READ_NO_PREFETCH); - if (err) - return (err); + ASSERT0(db->db_offset); + *zapp = NULL; dmu_object_info_from_db(db, &doi); if (DMU_OT_BYTESWAP(doi.doi_type) != DMU_BSWAP_ZAP) @@ -520,13 +519,16 @@ zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx, zap->zap_m.zap_num_entries == zap->zap_m.zap_num_chunks) { uint64_t newsz = db->db_size + SPA_MINBLOCKSIZE; if (newsz > MZAP_MAX_BLKSZ) { + int err; dprintf("upgrading obj %llu: num_entries=%u\n", obj, zap->zap_m.zap_num_entries); *zapp = zap; - return (mzap_upgrade(zapp, tx, 0)); + err = mzap_upgrade(zapp, tag, tx, 0); + if (err != 0) + zap_unlockdir(zap, tag); + return (err); } - err = dmu_object_set_blocksize(os, obj, newsz, 0, tx); - ASSERT0(err); + VERIFY0(dmu_object_set_blocksize(os, obj, newsz, 0, tx)); zap->zap_m.zap_num_chunks = db->db_size / MZAP_ENT_LEN - 1; } @@ -535,15 +537,31 @@ zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx, return (0); } +int +zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx, + krw_t lti, boolean_t fatreader, boolean_t adding, void *tag, zap_t **zapp) +{ + dmu_buf_t *db; + int err; + + err = dmu_buf_hold(os, obj, 0, tag, &db, DMU_READ_NO_PREFETCH); + if (err != 0) + return (err); + err = zap_lockdir_impl(db, tag, tx, lti, fatreader, adding, zapp); + if (err != 0) + dmu_buf_rele(db, tag); + return (err); +} + void -zap_unlockdir(zap_t *zap) +zap_unlockdir(zap_t *zap, void *tag) { rw_exit(&zap->zap_rwlock); - dmu_buf_rele(zap->zap_dbuf, NULL); + dmu_buf_rele(zap->zap_dbuf, tag); } static int -mzap_upgrade(zap_t **zapp, dmu_tx_t *tx, zap_flags_t flags) +mzap_upgrade(zap_t **zapp, void *tag, dmu_tx_t *tx, zap_flags_t flags) { mzap_phys_t *mzp; int i, sz, nchunks; @@ -581,7 +599,8 @@ mzap_upgrade(zap_t **zapp, dmu_tx_t *tx, zap_flags_t flags) dprintf("adding %s=%llu\n", mze->mze_name, mze->mze_value); zn = zap_name_alloc(zap, mze->mze_name, MT_EXACT); - err = fzap_add_cd(zn, 8, 1, &mze->mze_value, mze->mze_cd, tx); + err = fzap_add_cd(zn, 8, 1, &mze->mze_value, mze->mze_cd, + tag, tx); zap = zn->zn_zap; /* fzap_add_cd() may change zap */ zap_name_free(zn); if (err) @@ -620,9 +639,9 @@ mzap_create_impl(objset_t *os, uint64_t obj, int normflags, zap_flags_t flags, zap_t *zap; /* Only fat zap supports flags; upgrade immediately. */ VERIFY(0 == zap_lockdir(os, obj, tx, RW_WRITER, - B_FALSE, B_FALSE, &zap)); - VERIFY3U(0, ==, mzap_upgrade(&zap, tx, flags)); - zap_unlockdir(zap); + B_FALSE, B_FALSE, FTAG, &zap)); + VERIFY3U(0, ==, mzap_upgrade(&zap, FTAG, tx, flags)); + zap_unlockdir(zap, FTAG); } } @@ -762,7 +781,7 @@ zap_count(objset_t *os, uint64_t zapobj, uint64_t *count) zap_t *zap; int err; - err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap); + err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap); if (err) return (err); if (!zap->zap_ismicro) { @@ -770,7 +789,7 @@ zap_count(objset_t *os, uint64_t zapobj, uint64_t *count) } else { *count = zap->zap_m.zap_num_entries; } - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (err); } @@ -827,25 +846,19 @@ zap_lookup(objset_t *os, uint64_t zapobj, const char *name, num_integers, buf, MT_EXACT, NULL, 0, NULL)); } -int -zap_lookup_norm(objset_t *os, uint64_t zapobj, const char *name, +static int +zap_lookup_impl(zap_t *zap, const char *name, uint64_t integer_size, uint64_t num_integers, void *buf, matchtype_t mt, char *realname, int rn_len, boolean_t *ncp) { - zap_t *zap; - int err; + int err = 0; mzap_ent_t *mze; zap_name_t *zn; - err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap); - if (err) - return (err); zn = zap_name_alloc(zap, name, mt); - if (zn == NULL) { - zap_unlockdir(zap); + if (zn == NULL) return (SET_ERROR(ENOTSUP)); - } if (!zap->zap_ismicro) { err = fzap_lookup(zn, integer_size, num_integers, buf, @@ -872,7 +885,24 @@ zap_lookup_norm(objset_t *os, uint64_t zapobj, const char *name, } } zap_name_free(zn); - zap_unlockdir(zap); + return (err); +} + +int +zap_lookup_norm(objset_t *os, uint64_t zapobj, const char *name, + uint64_t integer_size, uint64_t num_integers, void *buf, + matchtype_t mt, char *realname, int rn_len, + boolean_t *ncp) +{ + zap_t *zap; + int err; + + err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap); + if (err != 0) + return (err); + err = zap_lookup_impl(zap, name, integer_size, + num_integers, buf, mt, realname, rn_len, ncp); + zap_unlockdir(zap, FTAG); return (err); } @@ -883,18 +913,18 @@ zap_prefetch(objset_t *os, uint64_t zapobj, const char *name) int err; zap_name_t *zn; - err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap); + err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap); if (err) return (err); zn = zap_name_alloc(zap, name, MT_EXACT); if (zn == NULL) { - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (SET_ERROR(ENOTSUP)); } fzap_prefetch(zn); zap_name_free(zn); - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (err); } @@ -906,18 +936,18 @@ zap_prefetch_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key, int err; zap_name_t *zn; - err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap); + err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap); if (err) return (err); zn = zap_name_alloc_uint64(zap, key, key_numints); if (zn == NULL) { - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (SET_ERROR(ENOTSUP)); } fzap_prefetch(zn); zap_name_free(zn); - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (err); } @@ -929,19 +959,19 @@ zap_lookup_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key, int err; zap_name_t *zn; - err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap); + err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap); if (err) return (err); zn = zap_name_alloc_uint64(zap, key, key_numints); if (zn == NULL) { - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (SET_ERROR(ENOTSUP)); } err = fzap_lookup(zn, integer_size, num_integers, buf, NULL, 0, NULL); zap_name_free(zn); - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (err); } @@ -964,12 +994,12 @@ zap_length(objset_t *os, uint64_t zapobj, const char *name, mzap_ent_t *mze; zap_name_t *zn; - err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap); + err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap); if (err) return (err); zn = zap_name_alloc(zap, name, MT_EXACT); if (zn == NULL) { - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (SET_ERROR(ENOTSUP)); } if (!zap->zap_ismicro) { @@ -986,7 +1016,7 @@ zap_length(objset_t *os, uint64_t zapobj, const char *name, } } zap_name_free(zn); - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (err); } @@ -998,17 +1028,17 @@ zap_length_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key, int err; zap_name_t *zn; - err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap); + err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap); if (err) return (err); zn = zap_name_alloc_uint64(zap, key, key_numints); if (zn == NULL) { - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (SET_ERROR(ENOTSUP)); } err = fzap_length(zn, integer_size, num_integers); zap_name_free(zn); - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (err); } @@ -1068,22 +1098,24 @@ zap_add(objset_t *os, uint64_t zapobj, const char *key, const uint64_t *intval = val; zap_name_t *zn; - err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, &zap); + 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); + zap_unlockdir(zap, FTAG); return (SET_ERROR(ENOTSUP)); } if (!zap->zap_ismicro) { - err = fzap_add(zn, integer_size, num_integers, val, tx); + err = fzap_add(zn, integer_size, num_integers, val, FTAG, 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, tx, 0); - if (err == 0) - err = fzap_add(zn, integer_size, num_integers, val, tx); + err = mzap_upgrade(&zn->zn_zap, FTAG, tx, 0); + if (err == 0) { + err = fzap_add(zn, integer_size, num_integers, val, + FTAG, tx); + } zap = zn->zn_zap; /* fzap_add() may change zap */ } else { mze = mze_find(zn); @@ -1096,7 +1128,7 @@ 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); + zap_unlockdir(zap, FTAG); return (err); } @@ -1109,19 +1141,19 @@ zap_add_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key, int err; zap_name_t *zn; - err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, &zap); + err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, FTAG, &zap); if (err) return (err); zn = zap_name_alloc_uint64(zap, key, key_numints); if (zn == NULL) { - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (SET_ERROR(ENOTSUP)); } - err = fzap_add(zn, integer_size, num_integers, val, tx); + err = fzap_add(zn, integer_size, num_integers, val, FTAG, tx); zap = zn->zn_zap; /* fzap_add() may change zap */ zap_name_free(zn); if (zap != NULL) /* may be NULL if fzap_add() failed */ - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (err); } @@ -1146,25 +1178,27 @@ zap_update(objset_t *os, uint64_t zapobj, const char *name, (void) zap_lookup(os, zapobj, name, 8, 1, &oldval); #endif - err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, &zap); + err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, FTAG, &zap); if (err) return (err); zn = zap_name_alloc(zap, name, MT_EXACT); if (zn == NULL) { - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (SET_ERROR(ENOTSUP)); } if (!zap->zap_ismicro) { - err = fzap_update(zn, integer_size, num_integers, val, tx); + err = fzap_update(zn, integer_size, num_integers, val, + FTAG, tx); zap = zn->zn_zap; /* fzap_update() may change zap */ } else if (integer_size != 8 || num_integers != 1 || strlen(name) >= MZAP_NAME_LEN) { dprintf("upgrading obj %llu: intsz=%u numint=%llu name=%s\n", zapobj, integer_size, num_integers, name); - err = mzap_upgrade(&zn->zn_zap, tx, 0); - if (err == 0) + err = mzap_upgrade(&zn->zn_zap, FTAG, tx, 0); + if (err == 0) { err = fzap_update(zn, integer_size, num_integers, - val, tx); + val, FTAG, tx); + } zap = zn->zn_zap; /* fzap_update() may change zap */ } else { mze = mze_find(zn); @@ -1178,7 +1212,7 @@ zap_update(objset_t *os, uint64_t zapobj, const char *name, ASSERT(zap == zn->zn_zap); zap_name_free(zn); if (zap != NULL) /* may be NULL if fzap_upgrade() failed */ - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (err); } @@ -1191,19 +1225,19 @@ zap_update_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key, zap_name_t *zn; int err; - err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, &zap); + err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, FTAG, &zap); if (err) return (err); zn = zap_name_alloc_uint64(zap, key, key_numints); if (zn == NULL) { - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (SET_ERROR(ENOTSUP)); } - err = fzap_update(zn, integer_size, num_integers, val, tx); + err = fzap_update(zn, integer_size, num_integers, val, FTAG, tx); zap = zn->zn_zap; /* fzap_update() may change zap */ zap_name_free(zn); if (zap != NULL) /* may be NULL if fzap_upgrade() failed */ - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (err); } @@ -1222,12 +1256,12 @@ zap_remove_norm(objset_t *os, uint64_t zapobj, const char *name, mzap_ent_t *mze; zap_name_t *zn; - err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, FALSE, &zap); + 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); + zap_unlockdir(zap, FTAG); return (SET_ERROR(ENOTSUP)); } if (!zap->zap_ismicro) { @@ -1244,7 +1278,7 @@ zap_remove_norm(objset_t *os, uint64_t zapobj, const char *name, } } zap_name_free(zn); - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (err); } @@ -1256,17 +1290,17 @@ zap_remove_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key, int err; zap_name_t *zn; - err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, FALSE, &zap); + err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, FALSE, FTAG, &zap); if (err) return (err); zn = zap_name_alloc_uint64(zap, key, key_numints); if (zn == NULL) { - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (SET_ERROR(ENOTSUP)); } err = fzap_remove(zn, tx); zap_name_free(zn); - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (err); } @@ -1298,7 +1332,7 @@ zap_cursor_fini(zap_cursor_t *zc) { if (zc->zc_zap) { rw_enter(&zc->zc_zap->zap_rwlock, RW_READER); - zap_unlockdir(zc->zc_zap); + zap_unlockdir(zc->zc_zap, NULL); zc->zc_zap = NULL; } if (zc->zc_leaf) { @@ -1345,7 +1379,7 @@ zap_cursor_retrieve(zap_cursor_t *zc, zap_attribute_t *za) if (zc->zc_zap == NULL) { int hb; err = zap_lockdir(zc->zc_objset, zc->zc_zapobj, NULL, - RW_READER, TRUE, FALSE, &zc->zc_zap); + RW_READER, TRUE, FALSE, NULL, &zc->zc_zap); if (err) return (err); @@ -1409,7 +1443,7 @@ zap_get_stats(objset_t *os, uint64_t zapobj, zap_stats_t *zs) int err; zap_t *zap; - err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap); + err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap); if (err) return (err); @@ -1422,7 +1456,7 @@ zap_get_stats(objset_t *os, uint64_t zapobj, zap_stats_t *zs) } else { fzap_get_stats(zap, zs); } - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (0); } @@ -1441,7 +1475,7 @@ zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add, * - 2 blocks for possibly split leaves, * - 2 grown ptrtbl blocks * - * This also accomodates the case where an add operation to a fairly + * This also accommodates the case where an add operation to a fairly * large microzap results in a promotion to fatzap. */ if (name == NULL) { @@ -1453,10 +1487,11 @@ zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add, * We lock the zap with adding == FALSE. Because, if we pass * the actual value of add, it could trigger a mzap_upgrade(). * At present we are just evaluating the possibility of this operation - * and hence we donot want to trigger an upgrade. + * and hence we do not want to trigger an upgrade. */ - err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap); - if (err) + err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, + FTAG, &zap); + if (err != 0) return (err); if (!zap->zap_ismicro) { @@ -1497,7 +1532,7 @@ zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add, } } - zap_unlockdir(zap); + zap_unlockdir(zap, FTAG); return (err); } From ee12785bddfc536b4f646f19fc84306bbe95aa2f Mon Sep 17 00:00:00 2001 From: Matthew Ahrens Date: Wed, 20 Jul 2016 15:42:13 -0700 Subject: [PATCH 2/2] 7004 dmu_tx_hold_zap() does dnode_hold() 7x on same object Using a benchmark which has 32 threads creating 2 million files in the same directory, on a machine with 16 CPU cores, I observed poor performance. I noticed that dmu_tx_hold_zap() was using about 30% of all CPU, and doing dnode_hold() 7 times on the same object (the ZAP object that is being held). dmu_tx_hold_zap() keeps a hold on the dnode_t the entire time it is running, in dmu_tx_hold_t:txh_dnode, so it would be nice to use the dnode_t that we already have in hand, rather than repeatedly calling dnode_hold(). To do this, we need to pass the dnode_t down through all the intermediate calls that dmu_tx_hold_zap() makes, making these routines take the dnode_t* rather than an objset_t* and a uint64_t object number. In particular, the following routines will need to have analogous *_by_dnode() variants created: dmu_buf_hold_noread() dmu_buf_hold() zap_lookup() zap_lookup_norm() zap_count_write() zap_lockdir() zap_count_write() This can improve performance on the benchmark described above by 100%, from 30,000 file creations per second to 60,000. (This improvement is on top of that provided by working around the object allocation issue. Peak performance of ~90,000 creations per second was observed with 8 CPUs; adding CPUs past that decreased performance due to lock contention.) The CPU used by dmu_tx_hold_zap() was reduced by 88%, from 340 CPU-seconds to 40 CPU-seconds. Sponsored by: Intel Corp. Closes #4641 --- include/sys/dmu.h | 13 +++++++---- include/sys/dnode.h | 6 ++--- include/sys/zap.h | 9 +++++++- module/zfs/dbuf.c | 17 +++++++++++++- module/zfs/dmu.c | 43 +++++++++++++++++++++++++++++++++++ module/zfs/dmu_tx.c | 7 +++--- module/zfs/zap.c | 19 +++++++++++++--- module/zfs/zap_micro.c | 51 +++++++++++++++++++++++++++++++++++++++--- 8 files changed, 146 insertions(+), 19 deletions(-) diff --git a/include/sys/dmu.h b/include/sys/dmu.h index 98da92890226..a8ed2868f744 100644 --- a/include/sys/dmu.h +++ b/include/sys/dmu.h @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, 2014 by Delphix. All rights reserved. + * Copyright (c) 2011, 2016 by Delphix. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. * Copyright 2014 HybridCluster. All rights reserved. @@ -73,6 +73,7 @@ struct sa_handle; typedef struct objset objset_t; typedef struct dmu_tx dmu_tx_t; typedef struct dsl_dir dsl_dir_t; +typedef struct dnode dnode_t; typedef enum dmu_object_byteswap { DMU_BSWAP_UINT8, @@ -420,7 +421,7 @@ dmu_write_embedded(objset_t *os, uint64_t object, uint64_t offset, #define WP_DMU_SYNC 0x2 #define WP_SPILL 0x4 -void dmu_write_policy(objset_t *os, struct dnode *dn, int level, int wp, +void dmu_write_policy(objset_t *os, dnode_t *dn, int level, int wp, struct zio_prop *zp); /* * The bonus data is accessed more or less like a regular buffer. @@ -446,7 +447,7 @@ int dmu_rm_spill(objset_t *, uint64_t, dmu_tx_t *); */ int dmu_spill_hold_by_bonus(dmu_buf_t *bonus, void *tag, dmu_buf_t **dbp); -int dmu_spill_hold_by_dnode(struct dnode *dn, uint32_t flags, +int dmu_spill_hold_by_dnode(dnode_t *dn, uint32_t flags, void *tag, dmu_buf_t **dbp); int dmu_spill_hold_existing(dmu_buf_t *bonus, void *tag, dmu_buf_t **dbp); @@ -466,6 +467,8 @@ int dmu_spill_hold_existing(dmu_buf_t *bonus, void *tag, dmu_buf_t **dbp); */ int dmu_buf_hold(objset_t *os, uint64_t object, uint64_t offset, void *tag, dmu_buf_t **, int flags); +int dmu_buf_hold_by_dnode(dnode_t *dn, uint64_t offset, + void *tag, dmu_buf_t **dbp, int flags); /* * Add a reference to a dmu buffer that has already been held via @@ -620,6 +623,8 @@ void *dmu_buf_remove_user(dmu_buf_t *db, dmu_buf_user_t *user); void *dmu_buf_get_user(dmu_buf_t *db); objset_t *dmu_buf_get_objset(dmu_buf_t *db); +dnode_t *dmu_buf_dnode_enter(dmu_buf_t *db); +void dmu_buf_dnode_exit(dmu_buf_t *db); /* Block until any in-progress dmu buf user evictions complete. */ void dmu_buf_user_evict_wait(void); @@ -799,7 +804,7 @@ extern const dmu_object_byteswap_info_t dmu_ot_byteswap[DMU_BSWAP_NUMFUNCS]; int dmu_object_info(objset_t *os, uint64_t object, dmu_object_info_t *doi); void __dmu_object_info_from_dnode(struct dnode *dn, dmu_object_info_t *doi); /* Like dmu_object_info, but faster if you have a held dnode in hand. */ -void dmu_object_info_from_dnode(struct dnode *dn, dmu_object_info_t *doi); +void dmu_object_info_from_dnode(dnode_t *dn, dmu_object_info_t *doi); /* Like dmu_object_info, but faster if you have a held dbuf in hand. */ void dmu_object_info_from_db(dmu_buf_t *db, dmu_object_info_t *doi); /* diff --git a/include/sys/dnode.h b/include/sys/dnode.h index cee4ea783810..fac00ac96a82 100644 --- a/include/sys/dnode.h +++ b/include/sys/dnode.h @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2014 by Delphix. All rights reserved. + * Copyright (c) 2012, 2016 by Delphix. All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. */ @@ -181,7 +181,7 @@ typedef struct dnode_phys { #define DN_SPILL_BLKPTR(dnp) (blkptr_t *)((char *)(dnp) + \ (((dnp)->dn_extra_slots + 1) << DNODE_SHIFT) - (1 << SPA_BLKPTRSHIFT)) -typedef struct dnode { +struct dnode { /* * Protects the structure of the dnode, including the number of levels * of indirection (dn_nlevels), dn_maxblkid, and dn_next_* @@ -280,7 +280,7 @@ typedef struct dnode { /* holds prefetch structure */ struct zfetch dn_zfetch; -} dnode_t; +}; /* * Adds a level of indirection between the dbuf and the dnode to avoid diff --git a/include/sys/zap.h b/include/sys/zap.h index 7009473979b2..c4169029adf8 100644 --- a/include/sys/zap.h +++ b/include/sys/zap.h @@ -236,7 +236,14 @@ int zap_prefetch(objset_t *os, uint64_t zapobj, const char *name); int zap_prefetch_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key, int key_numints); -int zap_count_write(objset_t *os, uint64_t zapobj, const char *name, +int zap_lookup_by_dnode(dnode_t *dn, const char *name, + uint64_t integer_size, uint64_t num_integers, void *buf); +int zap_lookup_norm_by_dnode(dnode_t *dn, const char *name, + uint64_t integer_size, uint64_t num_integers, void *buf, + matchtype_t mt, char *realname, int rn_len, + boolean_t *ncp); + +int zap_count_write_by_dnode(dnode_t *dn, const char *name, int add, uint64_t *towrite, uint64_t *tooverwrite); /* diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index 5b3b4f016fa9..46e3191dc487 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. - * Copyright (c) 2012, 2015 by Delphix. All rights reserved. + * Copyright (c) 2012, 2016 by Delphix. All rights reserved. * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. */ @@ -2815,6 +2815,21 @@ dmu_buf_get_objset(dmu_buf_t *db) return (dbi->db_objset); } +dnode_t * +dmu_buf_dnode_enter(dmu_buf_t *db) +{ + dmu_buf_impl_t *dbi = (dmu_buf_impl_t *)db; + DB_DNODE_ENTER(dbi); + return (DB_DNODE(dbi)); +} + +void +dmu_buf_dnode_exit(dmu_buf_t *db) +{ + dmu_buf_impl_t *dbi = (dmu_buf_impl_t *)db; + DB_DNODE_EXIT(dbi); +} + static void dbuf_check_blkptr(dnode_t *dn, dmu_buf_impl_t *db) { diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index e1dfb41ff353..6ed4743ee01c 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -127,6 +127,26 @@ const dmu_object_byteswap_info_t dmu_ot_byteswap[DMU_BSWAP_NUMFUNCS] = { { zfs_acl_byteswap, "acl" } }; +int +dmu_buf_hold_noread_by_dnode(dnode_t *dn, uint64_t offset, + void *tag, dmu_buf_t **dbp) +{ + uint64_t blkid; + dmu_buf_impl_t *db; + + blkid = dbuf_whichblock(dn, 0, offset); + rw_enter(&dn->dn_struct_rwlock, RW_READER); + db = dbuf_hold(dn, blkid, tag); + rw_exit(&dn->dn_struct_rwlock); + + if (db == NULL) { + *dbp = NULL; + return (SET_ERROR(EIO)); + } + + *dbp = &db->db; + return (0); +} int dmu_buf_hold_noread(objset_t *os, uint64_t object, uint64_t offset, void *tag, dmu_buf_t **dbp) @@ -154,6 +174,29 @@ dmu_buf_hold_noread(objset_t *os, uint64_t object, uint64_t offset, return (err); } +int +dmu_buf_hold_by_dnode(dnode_t *dn, uint64_t offset, + void *tag, dmu_buf_t **dbp, int flags) +{ + int err; + int db_flags = DB_RF_CANFAIL; + + if (flags & DMU_READ_NO_PREFETCH) + db_flags |= DB_RF_NOPREFETCH; + + err = dmu_buf_hold_noread_by_dnode(dn, offset, tag, dbp); + if (err == 0) { + dmu_buf_impl_t *db = (dmu_buf_impl_t *)(*dbp); + err = dbuf_read(db, NULL, db_flags); + if (err != 0) { + dbuf_rele(db, tag); + *dbp = NULL; + } + } + + return (err); +} + int dmu_buf_hold(objset_t *os, uint64_t object, uint64_t offset, void *tag, dmu_buf_t **dbp, int flags) diff --git a/module/zfs/dmu_tx.c b/module/zfs/dmu_tx.c index ed29bfbc692b..c50f732a70a5 100644 --- a/module/zfs/dmu_tx.c +++ b/module/zfs/dmu_tx.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. - * Copyright (c) 2012, 2015 by Delphix. All rights reserved. + * Copyright (c) 2012, 2016 by Delphix. All rights reserved. */ #include @@ -794,15 +794,14 @@ dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name) * access the name in this fat-zap so that we'll check * for i/o errors to the leaf blocks, etc. */ - err = zap_lookup(dn->dn_objset, dn->dn_object, name, - 8, 0, NULL); + err = zap_lookup_by_dnode(dn, name, 8, 0, NULL); if (err == EIO) { tx->tx_err = err; return; } } - err = zap_count_write(dn->dn_objset, dn->dn_object, name, add, + err = zap_count_write_by_dnode(dn, name, add, &txh->txh_space_towrite, &txh->txh_space_tooverwrite); /* diff --git a/module/zfs/zap.c b/module/zfs/zap.c index d0d438fe39e4..0ed6d7f49d50 100644 --- a/module/zfs/zap.c +++ b/module/zfs/zap.c @@ -270,6 +270,7 @@ zap_table_load(zap_t *zap, zap_table_phys_t *tbl, uint64_t idx, uint64_t *valp) uint64_t blk, off; int err; dmu_buf_t *db; + dnode_t *dn; int bs = FZAP_BLOCK_SHIFT(zap); ASSERT(RW_LOCK_HELD(&zap->zap_rwlock)); @@ -277,8 +278,15 @@ zap_table_load(zap_t *zap, zap_table_phys_t *tbl, uint64_t idx, uint64_t *valp) blk = idx >> (bs-3); off = idx & ((1<<(bs-3))-1); - err = dmu_buf_hold(zap->zap_objset, zap->zap_object, + /* + * Note: this is equivalent to dmu_buf_hold(), but we use + * _dnode_enter / _by_dnode because it's faster because we don't + * have to hold the dnode. + */ + dn = dmu_buf_dnode_enter(zap->zap_dbuf); + err = dmu_buf_hold_by_dnode(dn, (tbl->zt_blk + blk) << bs, FTAG, &db, DMU_READ_NO_PREFETCH); + dmu_buf_dnode_exit(zap->zap_dbuf); if (err) return (err); *valp = ((uint64_t *)db->db_data)[off]; @@ -292,9 +300,11 @@ zap_table_load(zap_t *zap, zap_table_phys_t *tbl, uint64_t idx, uint64_t *valp) */ blk = (idx*2) >> (bs-3); - err = dmu_buf_hold(zap->zap_objset, zap->zap_object, + dn = dmu_buf_dnode_enter(zap->zap_dbuf); + err = dmu_buf_hold_by_dnode(dn, (tbl->zt_nextblk + blk) << bs, FTAG, &db, DMU_READ_NO_PREFETCH); + dmu_buf_dnode_exit(zap->zap_dbuf); if (err == 0) dmu_buf_rele(db, FTAG); } @@ -502,6 +512,7 @@ zap_get_leaf_byblk(zap_t *zap, uint64_t blkid, dmu_tx_t *tx, krw_t lt, zap_leaf_t *l; int bs = FZAP_BLOCK_SHIFT(zap); int err; + dnode_t *dn; ASSERT(RW_LOCK_HELD(&zap->zap_rwlock)); @@ -515,8 +526,10 @@ zap_get_leaf_byblk(zap_t *zap, uint64_t blkid, dmu_tx_t *tx, krw_t lt, if (blkid == 0) return (ENOENT); - err = dmu_buf_hold(zap->zap_objset, zap->zap_object, + dn = dmu_buf_dnode_enter(zap->zap_dbuf); + err = dmu_buf_hold_by_dnode(dn, blkid << bs, NULL, &db, DMU_READ_NO_PREFETCH); + dmu_buf_dnode_exit(zap->zap_dbuf); if (err) return (err); diff --git a/module/zfs/zap_micro.c b/module/zfs/zap_micro.c index fcd33367db14..69230442d013 100644 --- a/module/zfs/zap_micro.c +++ b/module/zfs/zap_micro.c @@ -537,6 +537,24 @@ zap_lockdir_impl(dmu_buf_t *db, void *tag, dmu_tx_t *tx, return (0); } +static int +zap_lockdir_by_dnode(dnode_t *dn, dmu_tx_t *tx, + krw_t lti, boolean_t fatreader, boolean_t adding, void *tag, zap_t **zapp) +{ + dmu_buf_t *db; + int err; + + err = dmu_buf_hold_by_dnode(dn, 0, tag, &db, DMU_READ_NO_PREFETCH); + if (err != 0) { + return (err); + } + err = zap_lockdir_impl(db, tag, tx, lti, fatreader, adding, zapp); + if (err != 0) { + dmu_buf_rele(db, tag); + } + return (err); +} + int zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx, krw_t lti, boolean_t fatreader, boolean_t adding, void *tag, zap_t **zapp) @@ -928,6 +946,33 @@ zap_prefetch(objset_t *os, uint64_t zapobj, const char *name) return (err); } +int +zap_lookup_by_dnode(dnode_t *dn, const char *name, + uint64_t integer_size, uint64_t num_integers, void *buf) +{ + return (zap_lookup_norm_by_dnode(dn, name, integer_size, + num_integers, buf, MT_EXACT, NULL, 0, NULL)); +} + +int +zap_lookup_norm_by_dnode(dnode_t *dn, const char *name, + uint64_t integer_size, uint64_t num_integers, void *buf, + matchtype_t mt, char *realname, int rn_len, + boolean_t *ncp) +{ + zap_t *zap; + int err; + + err = zap_lockdir_by_dnode(dn, NULL, RW_READER, TRUE, FALSE, + FTAG, &zap); + if (err != 0) + return (err); + err = zap_lookup_impl(zap, name, integer_size, + num_integers, buf, mt, realname, rn_len, ncp); + zap_unlockdir(zap, FTAG); + return (err); +} + int zap_prefetch_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key, int key_numints) @@ -1461,7 +1506,7 @@ zap_get_stats(objset_t *os, uint64_t zapobj, zap_stats_t *zs) } int -zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add, +zap_count_write_by_dnode(dnode_t *dn, const char *name, int add, uint64_t *towrite, uint64_t *tooverwrite) { zap_t *zap; @@ -1489,7 +1534,7 @@ zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add, * At present we are just evaluating the possibility of this operation * and hence we do not want to trigger an upgrade. */ - err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, + err = zap_lockdir_by_dnode(dn, NULL, RW_READER, TRUE, FALSE, FTAG, &zap); if (err != 0) return (err); @@ -1553,7 +1598,7 @@ EXPORT_SYMBOL(zap_lookup_uint64); EXPORT_SYMBOL(zap_contains); EXPORT_SYMBOL(zap_prefetch); EXPORT_SYMBOL(zap_prefetch_uint64); -EXPORT_SYMBOL(zap_count_write); +EXPORT_SYMBOL(zap_count_write_by_dnode); EXPORT_SYMBOL(zap_add); EXPORT_SYMBOL(zap_add_uint64); EXPORT_SYMBOL(zap_update);