xref: /illumos-gate/usr/src/uts/common/fs/zfs/dmu_object.c (revision 8d0c3d29bb99f6521f2dc5058a7e4debebad7899)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <sys/dmu.h>
26 #include <sys/dmu_objset.h>
27 #include <sys/dmu_tx.h>
28 #include <sys/dnode.h>
29 
30 uint64_t
31 dmu_object_alloc(objset_t *os, dmu_object_type_t ot, int blocksize,
32     dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
33 {
34 	uint64_t object;
35 	uint64_t L2_dnode_count = DNODES_PER_BLOCK <<
36 	    (DMU_META_DNODE(os)->dn_indblkshift - SPA_BLKPTRSHIFT);
37 	dnode_t *dn = NULL;
38 	int restarted = B_FALSE;
39 
40 	mutex_enter(&os->os_obj_lock);
41 	for (;;) {
42 		object = os->os_obj_next;
43 		/*
44 		 * Each time we polish off an L2 bp worth of dnodes
45 		 * (2^13 objects), move to another L2 bp that's still
46 		 * reasonably sparse (at most 1/4 full).  Look from the
47 		 * beginning once, but after that keep looking from here.
48 		 * If we can't find one, just keep going from here.
49 		 */
50 		if (P2PHASE(object, L2_dnode_count) == 0) {
51 			uint64_t offset = restarted ? object << DNODE_SHIFT : 0;
52 			int error = dnode_next_offset(DMU_META_DNODE(os),
53 			    DNODE_FIND_HOLE,
54 			    &offset, 2, DNODES_PER_BLOCK >> 2, 0);
55 			restarted = B_TRUE;
56 			if (error == 0)
57 				object = offset >> DNODE_SHIFT;
58 		}
59 		os->os_obj_next = ++object;
60 
61 		/*
62 		 * XXX We should check for an i/o error here and return
63 		 * up to our caller.  Actually we should pre-read it in
64 		 * dmu_tx_assign(), but there is currently no mechanism
65 		 * to do so.
66 		 */
67 		(void) dnode_hold_impl(os, object, DNODE_MUST_BE_FREE,
68 		    FTAG, &dn);
69 		if (dn)
70 			break;
71 
72 		if (dmu_object_next(os, &object, B_TRUE, 0) == 0)
73 			os->os_obj_next = object - 1;
74 	}
75 
76 	dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, tx);
77 	dnode_rele(dn, FTAG);
78 
79 	mutex_exit(&os->os_obj_lock);
80 
81 	dmu_tx_add_new_object(tx, os, object);
82 	return (object);
83 }
84 
85 int
86 dmu_object_claim(objset_t *os, uint64_t object, dmu_object_type_t ot,
87     int blocksize, dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
88 {
89 	dnode_t *dn;
90 	int err;
91 
92 	if (object == DMU_META_DNODE_OBJECT && !dmu_tx_private_ok(tx))
93 		return (EBADF);
94 
95 	err = dnode_hold_impl(os, object, DNODE_MUST_BE_FREE, FTAG, &dn);
96 	if (err)
97 		return (err);
98 	dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, tx);
99 	dnode_rele(dn, FTAG);
100 
101 	dmu_tx_add_new_object(tx, os, object);
102 	return (0);
103 }
104 
105 int
106 dmu_object_reclaim(objset_t *os, uint64_t object, dmu_object_type_t ot,
107     int blocksize, dmu_object_type_t bonustype, int bonuslen)
108 {
109 	dnode_t *dn;
110 	dmu_tx_t *tx;
111 	int nblkptr;
112 	int err;
113 
114 	if (object == DMU_META_DNODE_OBJECT)
115 		return (EBADF);
116 
117 	err = dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED,
118 	    FTAG, &dn);
119 	if (err)
120 		return (err);
121 
122 	if (dn->dn_type == ot && dn->dn_datablksz == blocksize &&
123 	    dn->dn_bonustype == bonustype && dn->dn_bonuslen == bonuslen) {
124 		/* nothing is changing, this is a noop */
125 		dnode_rele(dn, FTAG);
126 		return (0);
127 	}
128 
129 	if (bonustype == DMU_OT_SA) {
130 		nblkptr = 1;
131 	} else {
132 		nblkptr = 1 + ((DN_MAX_BONUSLEN - bonuslen) >> SPA_BLKPTRSHIFT);
133 	}
134 
135 	/*
136 	 * If we are losing blkptrs or changing the block size this must
137 	 * be a new file instance.   We must clear out the previous file
138 	 * contents before we can change this type of metadata in the dnode.
139 	 */
140 	if (dn->dn_nblkptr > nblkptr || dn->dn_datablksz != blocksize) {
141 		err = dmu_free_long_range(os, object, 0, DMU_OBJECT_END);
142 		if (err)
143 			goto out;
144 	}
145 
146 	tx = dmu_tx_create(os);
147 	dmu_tx_hold_bonus(tx, object);
148 	err = dmu_tx_assign(tx, TXG_WAIT);
149 	if (err) {
150 		dmu_tx_abort(tx);
151 		goto out;
152 	}
153 
154 	dnode_reallocate(dn, ot, blocksize, bonustype, bonuslen, tx);
155 
156 	dmu_tx_commit(tx);
157 out:
158 	dnode_rele(dn, FTAG);
159 
160 	return (err);
161 }
162 
163 int
164 dmu_object_free(objset_t *os, uint64_t object, dmu_tx_t *tx)
165 {
166 	dnode_t *dn;
167 	int err;
168 
169 	ASSERT(object != DMU_META_DNODE_OBJECT || dmu_tx_private_ok(tx));
170 
171 	err = dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED,
172 	    FTAG, &dn);
173 	if (err)
174 		return (err);
175 
176 	ASSERT(dn->dn_type != DMU_OT_NONE);
177 	dnode_free_range(dn, 0, DMU_OBJECT_END, tx);
178 	dnode_free(dn, tx);
179 	dnode_rele(dn, FTAG);
180 
181 	return (0);
182 }
183 
184 int
185 dmu_object_next(objset_t *os, uint64_t *objectp, boolean_t hole, uint64_t txg)
186 {
187 	uint64_t offset = (*objectp + 1) << DNODE_SHIFT;
188 	int error;
189 
190 	error = dnode_next_offset(DMU_META_DNODE(os),
191 	    (hole ? DNODE_FIND_HOLE : 0), &offset, 0, DNODES_PER_BLOCK, txg);
192 
193 	*objectp = offset >> DNODE_SHIFT;
194 
195 	return (error);
196 }
197