summaryrefslogtreecommitdiffstats
path: root/module/zfs/dbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/zfs/dbuf.c')
-rw-r--r--module/zfs/dbuf.c52
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