]> git.proxmox.com Git - mirror_zfs-debian.git/blobdiff - module/zfs/dmu_object.c
Rebase master to b117
[mirror_zfs-debian.git] / module / zfs / dmu_object.c
index 1b9247d66e65e8e68a426a0593f5ed083c3f22f8..1f91fc1ad36f48b9d4e5ada94e373e42206134d9 100644 (file)
  * 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/dmu.h>
 #include <sys/dmu_objset.h>
 #include <sys/dmu_tx.h>
@@ -108,22 +106,56 @@ dmu_object_claim(objset_t *os, uint64_t object, dmu_object_type_t ot,
 
 int
 dmu_object_reclaim(objset_t *os, uint64_t object, dmu_object_type_t ot,
-    int blocksize, dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
+    int blocksize, dmu_object_type_t bonustype, int bonuslen)
 {
        dnode_t *dn;
+       dmu_tx_t *tx;
+       int nblkptr;
        int err;
 
-       if (object == DMU_META_DNODE_OBJECT && !dmu_tx_private_ok(tx))
+       if (object == DMU_META_DNODE_OBJECT)
                return (EBADF);
 
        err = dnode_hold_impl(os->os, object, DNODE_MUST_BE_ALLOCATED,
            FTAG, &dn);
        if (err)
                return (err);
+
+       if (dn->dn_type == ot && dn->dn_datablksz == blocksize &&
+           dn->dn_bonustype == bonustype && dn->dn_bonuslen == bonuslen) {
+               /* nothing is changing, this is a noop */
+               dnode_rele(dn, FTAG);
+               return (0);
+       }
+
+       nblkptr = 1 + ((DN_MAX_BONUSLEN - bonuslen) >> SPA_BLKPTRSHIFT);
+
+       /*
+        * If we are losing blkptrs or changing the block size this must
+        * be a new file instance.   We must clear out the previous file
+        * contents before we can change this type of metadata in the dnode.
+        */
+       if (dn->dn_nblkptr > nblkptr || dn->dn_datablksz != blocksize) {
+               err = dmu_free_long_range(os, object, 0, DMU_OBJECT_END);
+               if (err)
+                       goto out;
+       }
+
+       tx = dmu_tx_create(os);
+       dmu_tx_hold_bonus(tx, object);
+       err = dmu_tx_assign(tx, TXG_WAIT);
+       if (err) {
+               dmu_tx_abort(tx);
+               goto out;
+       }
+
        dnode_reallocate(dn, ot, blocksize, bonustype, bonuslen, tx);
+
+       dmu_tx_commit(tx);
+out:
        dnode_rele(dn, FTAG);
 
-       return (0);
+       return (err);
 }
 
 int