FreeBSD ZFS
The Zettabyte File System
|
00001 /* 00002 * CDDL HEADER START 00003 * 00004 * The contents of this file are subject to the terms of the 00005 * Common Development and Distribution License (the "License"). 00006 * You may not use this file except in compliance with the License. 00007 * 00008 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 00009 * or http://www.opensolaris.org/os/licensing. 00010 * See the License for the specific language governing permissions 00011 * and limitations under the License. 00012 * 00013 * When distributing Covered Code, include this CDDL HEADER in each 00014 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 00015 * If applicable, add the following below this CDDL HEADER, with the 00016 * fields enclosed by brackets "[]" replaced with your own identifying 00017 * information: Portions Copyright [yyyy] [name of copyright owner] 00018 * 00019 * CDDL HEADER END 00020 */ 00021 /* 00022 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 00023 */ 00024 00025 #include <sys/dmu.h> 00026 #include <sys/dmu_objset.h> 00027 #include <sys/dmu_tx.h> 00028 #include <sys/dnode.h> 00029 00030 uint64_t 00031 dmu_object_alloc(objset_t *os, dmu_object_type_t ot, int blocksize, 00032 dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx) 00033 { 00034 uint64_t object; 00035 uint64_t L2_dnode_count = DNODES_PER_BLOCK << 00036 (DMU_META_DNODE(os)->dn_indblkshift - SPA_BLKPTRSHIFT); 00037 dnode_t *dn = NULL; 00038 int restarted = B_FALSE; 00039 00040 mutex_enter(&os->os_obj_lock); 00041 for (;;) { 00042 object = os->os_obj_next; 00043 /* 00044 * Each time we polish off an L2 bp worth of dnodes 00045 * (2^13 objects), move to another L2 bp that's still 00046 * reasonably sparse (at most 1/4 full). Look from the 00047 * beginning once, but after that keep looking from here. 00048 * If we can't find one, just keep going from here. 00049 */ 00050 if (P2PHASE(object, L2_dnode_count) == 0) { 00051 uint64_t offset = restarted ? object << DNODE_SHIFT : 0; 00052 int error = dnode_next_offset(DMU_META_DNODE(os), 00053 DNODE_FIND_HOLE, 00054 &offset, 2, DNODES_PER_BLOCK >> 2, 0); 00055 restarted = B_TRUE; 00056 if (error == 0) 00057 object = offset >> DNODE_SHIFT; 00058 } 00059 os->os_obj_next = ++object; 00060 00061 /* 00062 * XXX We should check for an i/o error here and return 00063 * up to our caller. Actually we should pre-read it in 00064 * dmu_tx_assign(), but there is currently no mechanism 00065 * to do so. 00066 */ 00067 (void) dnode_hold_impl(os, object, DNODE_MUST_BE_FREE, 00068 FTAG, &dn); 00069 if (dn) 00070 break; 00071 00072 if (dmu_object_next(os, &object, B_TRUE, 0) == 0) 00073 os->os_obj_next = object - 1; 00074 } 00075 00076 dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, tx); 00077 dnode_rele(dn, FTAG); 00078 00079 mutex_exit(&os->os_obj_lock); 00080 00081 dmu_tx_add_new_object(tx, os, object); 00082 return (object); 00083 } 00084 00085 int 00086 dmu_object_claim(objset_t *os, uint64_t object, dmu_object_type_t ot, 00087 int blocksize, dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx) 00088 { 00089 dnode_t *dn; 00090 int err; 00091 00092 if (object == DMU_META_DNODE_OBJECT && !dmu_tx_private_ok(tx)) 00093 return (EBADF); 00094 00095 err = dnode_hold_impl(os, object, DNODE_MUST_BE_FREE, FTAG, &dn); 00096 if (err) 00097 return (err); 00098 dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, tx); 00099 dnode_rele(dn, FTAG); 00100 00101 dmu_tx_add_new_object(tx, os, object); 00102 return (0); 00103 } 00104 00105 int 00106 dmu_object_reclaim(objset_t *os, uint64_t object, dmu_object_type_t ot, 00107 int blocksize, dmu_object_type_t bonustype, int bonuslen) 00108 { 00109 dnode_t *dn; 00110 dmu_tx_t *tx; 00111 int nblkptr; 00112 int err; 00113 00114 if (object == DMU_META_DNODE_OBJECT) 00115 return (EBADF); 00116 00117 err = dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED, 00118 FTAG, &dn); 00119 if (err) 00120 return (err); 00121 00122 if (dn->dn_type == ot && dn->dn_datablksz == blocksize && 00123 dn->dn_bonustype == bonustype && dn->dn_bonuslen == bonuslen) { 00124 /* nothing is changing, this is a noop */ 00125 dnode_rele(dn, FTAG); 00126 return (0); 00127 } 00128 00129 if (bonustype == DMU_OT_SA) { 00130 nblkptr = 1; 00131 } else { 00132 nblkptr = 1 + ((DN_MAX_BONUSLEN - bonuslen) >> SPA_BLKPTRSHIFT); 00133 } 00134 00135 /* 00136 * If we are losing blkptrs or changing the block size this must 00137 * be a new file instance. We must clear out the previous file 00138 * contents before we can change this type of metadata in the dnode. 00139 */ 00140 if (dn->dn_nblkptr > nblkptr || dn->dn_datablksz != blocksize) { 00141 err = dmu_free_long_range(os, object, 0, DMU_OBJECT_END); 00142 if (err) 00143 goto out; 00144 } 00145 00146 tx = dmu_tx_create(os); 00147 dmu_tx_hold_bonus(tx, object); 00148 err = dmu_tx_assign(tx, TXG_WAIT); 00149 if (err) { 00150 dmu_tx_abort(tx); 00151 goto out; 00152 } 00153 00154 dnode_reallocate(dn, ot, blocksize, bonustype, bonuslen, tx); 00155 00156 dmu_tx_commit(tx); 00157 out: 00158 dnode_rele(dn, FTAG); 00159 00160 return (err); 00161 } 00162 00163 int 00164 dmu_object_free(objset_t *os, uint64_t object, dmu_tx_t *tx) 00165 { 00166 dnode_t *dn; 00167 int err; 00168 00169 ASSERT(object != DMU_META_DNODE_OBJECT || dmu_tx_private_ok(tx)); 00170 00171 err = dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED, 00172 FTAG, &dn); 00173 if (err) 00174 return (err); 00175 00176 ASSERT(dn->dn_type != DMU_OT_NONE); 00177 dnode_free_range(dn, 0, DMU_OBJECT_END, tx); 00178 dnode_free(dn, tx); 00179 dnode_rele(dn, FTAG); 00180 00181 return (0); 00182 } 00183 00184 int 00185 dmu_object_next(objset_t *os, uint64_t *objectp, boolean_t hole, uint64_t txg) 00186 { 00187 uint64_t offset = (*objectp + 1) << DNODE_SHIFT; 00188 int error; 00189 00190 error = dnode_next_offset(DMU_META_DNODE(os), 00191 (hole ? DNODE_FIND_HOLE : 0), &offset, 0, DNODES_PER_BLOCK, txg); 00192 00193 *objectp = offset >> DNODE_SHIFT; 00194 00195 return (error); 00196 }