diff options
author | Justin T. Gibbs <[email protected]> | 2015-04-02 22:59:15 +1100 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2015-04-28 16:25:44 -0700 |
commit | 6ebebaceb1091142b81430291c610d79b6a3073e (patch) | |
tree | 70197ad52e7d910f4a860dcfc1d475aa5d073efc /module/zfs/dbuf.c | |
parent | 0c66c32d1d8b64a261cceb5f50a9e86777c5d0b2 (diff) |
Illumos 5531 - NULL pointer dereference in dsl_prop_get_ds()
5531 NULL pointer dereference in dsl_prop_get_ds()
Author: Justin T. Gibbs <[email protected]>
Reviewed by: Matthew Ahrens <[email protected]>
Reviewed by: Dan McDonald <[email protected]>
Reviewed by: George Wilson <[email protected]>
Reviewed by: Bayard Bell <[email protected]>
Approved by: Robert Mustacchi <[email protected]>
References:
https://www.illumos.org/issues/5531
https://github.com/illumos/illumos-gate/commit/e57a022
Ported-by: Chris Dunlop <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Diffstat (limited to 'module/zfs/dbuf.c')
-rw-r--r-- | module/zfs/dbuf.c | 52 |
1 files changed, 46 insertions, 6 deletions
diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index ddfd2e981..cd74ce3e8 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -149,16 +149,13 @@ dbuf_hash(void *os, uint64_t obj, uint8_t lvl, uint64_t blkid) (dbuf)->db_blkid == (blkid)) dmu_buf_impl_t * -dbuf_find(dnode_t *dn, uint8_t level, uint64_t blkid) +dbuf_find(objset_t *os, uint64_t obj, uint8_t level, uint64_t blkid) { dbuf_hash_table_t *h = &dbuf_hash_table; - objset_t *os = dn->dn_objset; - uint64_t obj; uint64_t hv; uint64_t idx; dmu_buf_impl_t *db; - obj = dn->dn_object; hv = DBUF_HASH(os, obj, level, blkid); idx = hv & h->hash_table_mask; @@ -177,6 +174,24 @@ dbuf_find(dnode_t *dn, uint8_t level, uint64_t blkid) return (NULL); } +static dmu_buf_impl_t * +dbuf_find_bonus(objset_t *os, uint64_t object) +{ + dnode_t *dn; + dmu_buf_impl_t *db = NULL; + + if (dnode_hold(os, object, FTAG, &dn) == 0) { + rw_enter(&dn->dn_struct_rwlock, RW_READER); + if (dn->dn_bonus != NULL) { + db = dn->dn_bonus; + mutex_enter(&db->db_mtx); + } + rw_exit(&dn->dn_struct_rwlock); + dnode_rele(dn, FTAG); + } + return (db); +} + /* * Insert an entry into the hash table. If there is already an element * equal to elem in the hash table, then the already existing element @@ -2000,7 +2015,7 @@ dbuf_prefetch(dnode_t *dn, uint64_t blkid, zio_priority_t prio) return; /* dbuf_find() returns with db_mtx held */ - if ((db = dbuf_find(dn, 0, blkid))) { + if ((db = dbuf_find(dn->dn_objset, dn->dn_object, 0, blkid))) { /* * This dbuf is already in the cache. We assume that * it is already CACHED, or else about to be either @@ -2048,7 +2063,8 @@ __dbuf_hold_impl(struct dbuf_hold_impl_data *dh) *(dh->dh_dbp) = NULL; top: /* dbuf_find() returns with db_mtx held */ - dh->dh_db = dbuf_find(dh->dh_dn, dh->dh_level, dh->dh_blkid); + dh->dh_db = dbuf_find(dh->dh_dn->dn_objset, dh->dh_dn->dn_object, + dh->dh_level, dh->dh_blkid); if (dh->dh_db == NULL) { dh->dh_bp = NULL; @@ -2228,6 +2244,30 @@ dbuf_add_ref(dmu_buf_impl_t *db, void *tag) VERIFY(refcount_add(&db->db_holds, tag) > 1); } +#pragma weak dmu_buf_try_add_ref = dbuf_try_add_ref +boolean_t +dbuf_try_add_ref(dmu_buf_t *db_fake, objset_t *os, uint64_t obj, uint64_t blkid, + void *tag) +{ + dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake; + dmu_buf_impl_t *found_db; + boolean_t result = B_FALSE; + + if (db->db_blkid == DMU_BONUS_BLKID) + found_db = dbuf_find_bonus(os, obj); + else + found_db = dbuf_find(os, obj, 0, blkid); + + if (found_db != NULL) { + if (db == found_db && dbuf_refcount(db) > db->db_dirtycnt) { + (void) refcount_add(&db->db_holds, tag); + result = B_TRUE; + } + mutex_exit(&db->db_mtx); + } + return (result); +} + /* * If you call dbuf_rele() you had better not be referencing the dnode handle * unless you have some other direct or indirect hold on the dnode. (An indirect |