* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/zfs_context.h>
#include <sys/dbuf.h>
#include <sys/dnode.h>
/*
* Write out the dnode's dirty buffers.
- *
- * NOTE: The dnode is kept in memory by being dirty. Once the
- * dirty bit is cleared, it may be evicted. Beware of this!
*/
void
dnode_sync(dnode_t *dn, dmu_tx_t *tx)
dnode_phys_t *dnp = dn->dn_phys;
int txgoff = tx->tx_txg & TXG_MASK;
list_t *list = &dn->dn_dirty_records[txgoff];
+ static const dnode_phys_t zerodn = { 0 };
ASSERT(dmu_tx_is_syncing(tx));
ASSERT(dnp->dn_type != DMU_OT_NONE || dn->dn_allocated_txg);
+ ASSERT(dnp->dn_type != DMU_OT_NONE ||
+ bcmp(dnp, &zerodn, DNODE_SIZE) == 0);
DNODE_VERIFY(dn);
ASSERT(dn->dn_dbuf == NULL || arc_released(dn->dn_dbuf->db_buf));
+ if (dmu_objset_userused_enabled(dn->dn_objset) &&
+ !DMU_OBJECT_IS_SPECIAL(dn->dn_object)) {
+ ASSERT(dn->dn_oldphys == NULL);
+ dn->dn_oldphys = zio_buf_alloc(sizeof (dnode_phys_t));
+ *dn->dn_oldphys = *dn->dn_phys; /* struct assignment */
+ dn->dn_phys->dn_flags |= DNODE_FLAG_USERUSED_ACCOUNTED;
+ } else {
+ /* Once we account for it, we should always account for it. */
+ ASSERT(!(dn->dn_phys->dn_flags &
+ DNODE_FLAG_USERUSED_ACCOUNTED));
+ }
+
mutex_enter(&dn->dn_mtx);
if (dn->dn_allocated_txg == tx->tx_txg) {
/* The dnode is newly allocated or reallocated */
if (dnp->dn_type == DMU_OT_NONE) {
/* this is a first alloc, not a realloc */
- /* XXX shouldn't the phys already be zeroed? */
- bzero(dnp, DNODE_CORE_SIZE);
dnp->dn_nlevels = 1;
+ dnp->dn_nblkptr = dn->dn_nblkptr;
}
- if (dn->dn_nblkptr > dnp->dn_nblkptr) {
- /* zero the new blkptrs we are gaining */
- bzero(dnp->dn_blkptr + dnp->dn_nblkptr,
- sizeof (blkptr_t) *
- (dn->dn_nblkptr - dnp->dn_nblkptr));
- }
dnp->dn_type = dn->dn_type;
dnp->dn_bonustype = dn->dn_bonustype;
dnp->dn_bonuslen = dn->dn_bonuslen;
- dnp->dn_nblkptr = dn->dn_nblkptr;
}
ASSERT(dnp->dn_nlevels > 1 ||
return;
}
+ if (dn->dn_next_nblkptr[txgoff]) {
+ /* this should only happen on a realloc */
+ ASSERT(dn->dn_allocated_txg == tx->tx_txg);
+ if (dn->dn_next_nblkptr[txgoff] > dnp->dn_nblkptr) {
+ /* zero the new blkptrs we are gaining */
+ bzero(dnp->dn_blkptr + dnp->dn_nblkptr,
+ sizeof (blkptr_t) *
+ (dn->dn_next_nblkptr[txgoff] - dnp->dn_nblkptr));
+#ifdef ZFS_DEBUG
+ } else {
+ int i;
+ ASSERT(dn->dn_next_nblkptr[txgoff] < dnp->dn_nblkptr);
+ /* the blkptrs we are losing better be unallocated */
+ for (i = dn->dn_next_nblkptr[txgoff];
+ i < dnp->dn_nblkptr; i++)
+ ASSERT(BP_IS_HOLE(&dnp->dn_blkptr[i]));
+#endif
+ }
+ mutex_enter(&dn->dn_mtx);
+ dnp->dn_nblkptr = dn->dn_next_nblkptr[txgoff];
+ dn->dn_next_nblkptr[txgoff] = 0;
+ mutex_exit(&dn->dn_mtx);
+ }
+
if (dn->dn_next_nlevels[txgoff]) {
dnode_increase_indirection(dn, tx);
dn->dn_next_nlevels[txgoff] = 0;
dbuf_sync_list(list, tx);
- if (dn->dn_object != DMU_META_DNODE_OBJECT) {
+ if (!DMU_OBJECT_IS_SPECIAL(dn->dn_object)) {
ASSERT3P(list_head(list), ==, NULL);
dnode_rele(dn, (void *)(uintptr_t)tx->tx_txg);
}