Print this page
Possibility to physically reserve space without writing leaf blocks

@@ -1019,11 +1019,19 @@
 
         (void) arc_release(db->db_buf, db);
 }
 
 dbuf_dirty_record_t *
-dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
+dbuf_zero_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
+{
+        ASSERT(db->db_objset != NULL);
+
+        return (dbuf_dirty(db, tx, B_TRUE));
+}
+
+dbuf_dirty_record_t *
+dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx, boolean_t zero_write)
 {
         dnode_t *dn;
         objset_t *os;
         dbuf_dirty_record_t **drp, *dr;
         int drop_struct_lock = FALSE;

@@ -1150,10 +1158,11 @@
          * If this buffer is dirty in an old transaction group we need
          * 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->dr_zero_write = zero_write;
         if (db->db_level == 0) {
                 void *data_old = db->db_buf;
 
                 if (db->db_state != DB_NOFILL) {
                         if (db->db_blkid == DMU_BONUS_BLKID) {

@@ -1263,11 +1272,11 @@
                         parent_held = TRUE;
                 }
                 if (drop_struct_lock)
                         rw_exit(&dn->dn_struct_rwlock);
                 ASSERT3U(db->db_level+1, ==, parent->db_level);
-                di = dbuf_dirty(parent, tx);
+                di = dbuf_dirty(parent, tx, B_FALSE);
                 if (parent_held)
                         dbuf_rele(parent, FTAG);
 
                 mutex_enter(&db->db_mtx);
                 /*

@@ -1406,11 +1415,11 @@
         DB_DNODE_ENTER(db);
         if (RW_WRITE_HELD(&DB_DNODE(db)->dn_struct_rwlock))
                 rf |= DB_RF_HAVESTRUCT;
         DB_DNODE_EXIT(db);
         (void) dbuf_read(db, NULL, rf);
-        (void) dbuf_dirty(db, tx);
+        (void) dbuf_dirty(db, tx, B_FALSE);
 }
 
 void
 dmu_buf_will_not_fill(dmu_buf_t *db_fake, dmu_tx_t *tx)
 {

@@ -1433,11 +1442,29 @@
 
         ASSERT(db->db.db_object != DMU_META_DNODE_OBJECT ||
             dmu_tx_private_ok(tx));
 
         dbuf_noread(db);
-        (void) dbuf_dirty(db, tx);
+        (void) dbuf_dirty(db, tx, B_FALSE);
+}
+
+
+void
+dmu_buf_will_zero_fill(dmu_buf_t *db_fake, dmu_tx_t *tx)
+{
+        dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+
+        ASSERT(db->db_blkid != DMU_BONUS_BLKID);
+        ASSERT(tx->tx_txg != 0);
+        ASSERT(db->db_level == 0);
+        ASSERT(!refcount_is_zero(&db->db_holds));
+
+        ASSERT(db->db.db_object != DMU_META_DNODE_OBJECT ||
+            dmu_tx_private_ok(tx));
+
+        dbuf_noread(db);
+        (void) dbuf_zero_dirty(db, tx);
 }
 
 #pragma weak dmu_buf_fill_done = dbuf_fill_done
 /* ARGSUSED */
 void

@@ -1518,11 +1545,11 @@
         ASSERT(db->db_state == DB_CACHED || db->db_state == DB_UNCACHED);
 
         if (db->db_state == DB_CACHED &&
             refcount_count(&db->db_holds) - 1 > db->db_dirtycnt) {
                 mutex_exit(&db->db_mtx);
-                (void) dbuf_dirty(db, tx);
+                (void) dbuf_dirty(db, tx, B_FALSE);
                 bcopy(buf->b_data, db->db.db_data, db->db.db_size);
                 VERIFY(arc_buf_remove_ref(buf, db));
                 xuio_stat_wbuf_copied();
                 return;
         }

@@ -1549,11 +1576,11 @@
         }
         ASSERT(db->db_buf == NULL);
         dbuf_set_data(db, buf);
         db->db_state = DB_FILL;
         mutex_exit(&db->db_mtx);
-        (void) dbuf_dirty(db, tx);
+        (void) dbuf_dirty(db, tx, B_FALSE);
         dmu_buf_fill_done(&db->db, tx);
 }
 
 /*
  * "Clear" the contents of this dbuf.  This will mark the dbuf

@@ -2818,10 +2845,20 @@
         wp_flag |= (db->db_state == DB_NOFILL) ? WP_NOFILL : 0;
 
         dmu_write_policy(os, dn, db->db_level, wp_flag, &zp);
         DB_DNODE_EXIT(db);
 
+        if (dr->dr_zero_write) {
+                zp.zp_zero_write = B_TRUE;
+
+                if (!spa_feature_is_active(os->os_spa, SPA_FEATURE_SPACE_RESERVATION))
+                {
+                        spa_feature_incr(os->os_spa,
+                            SPA_FEATURE_SPACE_RESERVATION, tx);
+                }
+        }
+
         if (db->db_level == 0 &&
             dr->dt.dl.dr_override_state == DR_OVERRIDDEN) {
                 /*
                  * The BP for this block has been provided by open context
                  * (by dmu_sync() or dmu_buf_write_embedded()).