Illumos #2619 and #2747
[zfs.git] / module / zfs / dbuf.c
index fb7d0ac..99f728f 100644 (file)
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
+#include <sys/arc.h>
 #include <sys/dmu.h>
 #include <sys/dmu_impl.h>
 #include <sys/dbuf.h>
@@ -258,7 +261,7 @@ dbuf_is_metadata(dmu_buf_impl_t *db)
                boolean_t is_metadata;
 
                DB_DNODE_ENTER(db);
-               is_metadata = dmu_ot[DB_DNODE(db)->dn_type].ot_metadata;
+               is_metadata = DMU_OT_IS_METADATA(DB_DNODE(db)->dn_type);
                DB_DNODE_EXIT(db);
 
                return (is_metadata);
@@ -296,7 +299,7 @@ retry:
 #if defined(_KERNEL) && defined(HAVE_SPL)
        /* Large allocations which do not require contiguous pages
         * should be using vmem_alloc() in the linux kernel */
-       h->hash_table = vmem_zalloc(hsize * sizeof (void *), KM_SLEEP);
+       h->hash_table = vmem_zalloc(hsize * sizeof (void *), KM_PUSHPAGE);
 #else
        h->hash_table = kmem_zalloc(hsize * sizeof (void *), KM_NOSLEEP);
 #endif
@@ -1094,7 +1097,7 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
                dn->dn_dirtyctx =
                    (dmu_tx_is_syncing(tx) ? DN_DIRTY_SYNC : DN_DIRTY_OPEN);
                ASSERT(dn->dn_dirtyctx_firstset == NULL);
-               dn->dn_dirtyctx_firstset = kmem_alloc(1, KM_SLEEP);
+               dn->dn_dirtyctx_firstset = kmem_alloc(1, KM_PUSHPAGE);
        }
        mutex_exit(&dn->dn_mtx);
 
@@ -1171,7 +1174,7 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
         * to make a copy of it so that the changes we make in this
         * transaction group won't leak out when we sync the older txg.
         */
-       dr = kmem_zalloc(sizeof (dbuf_dirty_record_t), KM_SLEEP);
+       dr = kmem_zalloc(sizeof (dbuf_dirty_record_t), KM_PUSHPAGE);
        list_link_init(&dr->dr_dirty_node);
        if (db->db_level == 0) {
                void *data_old = db->db_buf;
@@ -1346,13 +1349,17 @@ dbuf_undirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
         * it, since one of the current holders may be in the
         * middle of an update.  Note that users of dbuf_undirty()
         * should not place a hold on the dbuf before the call.
+        * Also note: we can get here with a spill block, so
+        * test for that similar to how dbuf_dirty does.
         */
        if (refcount_count(&db->db_holds) > db->db_dirtycnt) {
                mutex_exit(&db->db_mtx);
                /* Make sure we don't toss this buffer at sync phase */
-               mutex_enter(&dn->dn_mtx);
-               dnode_clear_range(dn, db->db_blkid, 1, tx);
-               mutex_exit(&dn->dn_mtx);
+               if (db->db_blkid != DMU_SPILL_BLKID) {
+                       mutex_enter(&dn->dn_mtx);
+                       dnode_clear_range(dn, db->db_blkid, 1, tx);
+                       mutex_exit(&dn->dn_mtx);
+               }
                DB_DNODE_EXIT(db);
                return (0);
        }
@@ -1365,11 +1372,18 @@ dbuf_undirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
 
        *drp = dr->dr_next;
 
+       /*
+        * Note that there are three places in dbuf_dirty()
+        * where this dirty record may be put on a list.
+        * Make sure to do a list_remove corresponding to
+        * every one of those list_insert calls.
+        */
        if (dr->dr_parent) {
                mutex_enter(&dr->dr_parent->dt.di.dr_mtx);
                list_remove(&dr->dr_parent->dt.di.dr_children, dr);
                mutex_exit(&dr->dr_parent->dt.di.dr_mtx);
-       } else if (db->db_level+1 == dn->dn_nlevels) {
+       } else if (db->db_blkid == DMU_SPILL_BLKID ||
+           db->db_level+1 == dn->dn_nlevels) {
                ASSERT(db->db_blkptr == NULL || db->db_parent == dn->dn_dbuf);
                mutex_enter(&dn->dn_mtx);
                list_remove(&dn->dn_dirty_records[txg & TXG_MASK], dr);
@@ -1706,7 +1720,7 @@ dbuf_create(dnode_t *dn, uint8_t level, uint64_t blkid,
        ASSERT(RW_LOCK_HELD(&dn->dn_struct_rwlock));
        ASSERT(dn->dn_type != DMU_OT_NONE);
 
-       db = kmem_cache_alloc(dbuf_cache, KM_SLEEP);
+       db = kmem_cache_alloc(dbuf_cache, KM_PUSHPAGE);
 
        db->db_objset = os;
        db->db.db_object = dn->dn_object;
@@ -2006,7 +2020,7 @@ dbuf_hold_impl(dnode_t *dn, uint8_t level, uint64_t blkid, int fail_sparse,
        int error;
 
        dh = kmem_zalloc(sizeof(struct dbuf_hold_impl_data) *
-           DBUF_HOLD_IMPL_MAX_DEPTH, KM_SLEEP);
+           DBUF_HOLD_IMPL_MAX_DEPTH, KM_PUSHPAGE);
        __dbuf_hold_impl_init(dh, dn, level, blkid, fail_sparse, tag, dbp, 0);
 
        error = __dbuf_hold_impl(dh);
@@ -2816,3 +2830,41 @@ dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx)
                    ZIO_PRIORITY_ASYNC_WRITE, ZIO_FLAG_MUSTSUCCEED, &zb);
        }
 }
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(dbuf_find);
+EXPORT_SYMBOL(dbuf_is_metadata);
+EXPORT_SYMBOL(dbuf_evict);
+EXPORT_SYMBOL(dbuf_loan_arcbuf);
+EXPORT_SYMBOL(dbuf_whichblock);
+EXPORT_SYMBOL(dbuf_read);
+EXPORT_SYMBOL(dbuf_unoverride);
+EXPORT_SYMBOL(dbuf_free_range);
+EXPORT_SYMBOL(dbuf_new_size);
+EXPORT_SYMBOL(dbuf_release_bp);
+EXPORT_SYMBOL(dbuf_dirty);
+EXPORT_SYMBOL(dmu_buf_will_dirty);
+EXPORT_SYMBOL(dmu_buf_will_not_fill);
+EXPORT_SYMBOL(dmu_buf_will_fill);
+EXPORT_SYMBOL(dmu_buf_fill_done);
+EXPORT_SYMBOL(dmu_buf_rele);
+EXPORT_SYMBOL(dbuf_assign_arcbuf);
+EXPORT_SYMBOL(dbuf_clear);
+EXPORT_SYMBOL(dbuf_prefetch);
+EXPORT_SYMBOL(dbuf_hold_impl);
+EXPORT_SYMBOL(dbuf_hold);
+EXPORT_SYMBOL(dbuf_hold_level);
+EXPORT_SYMBOL(dbuf_create_bonus);
+EXPORT_SYMBOL(dbuf_spill_set_blksz);
+EXPORT_SYMBOL(dbuf_rm_spill);
+EXPORT_SYMBOL(dbuf_add_ref);
+EXPORT_SYMBOL(dbuf_rele);
+EXPORT_SYMBOL(dbuf_rele_and_unlock);
+EXPORT_SYMBOL(dbuf_refcount);
+EXPORT_SYMBOL(dbuf_sync_list);
+EXPORT_SYMBOL(dmu_buf_set_user);
+EXPORT_SYMBOL(dmu_buf_set_user_ie);
+EXPORT_SYMBOL(dmu_buf_update_user);
+EXPORT_SYMBOL(dmu_buf_get_user);
+EXPORT_SYMBOL(dmu_buf_freeable);
+#endif