xref: /illumos-gate/usr/src/uts/common/fs/zfs/dmu_object.c (revision db874c57ae335a07060499f1492b0d0e2593e26c)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/dmu.h>
30 #include <sys/dmu_objset.h>
31 #include <sys/dmu_tx.h>
32 #include <sys/dnode.h>
33 
34 uint64_t
35 dmu_object_alloc(objset_t *os, dmu_object_type_t ot, int blocksize,
36     dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
37 {
38 	objset_impl_t *osi = os->os;
39 	uint64_t object;
40 	uint64_t L2_dnode_count = DNODES_PER_BLOCK <<
41 	    (osi->os_meta_dnode->dn_indblkshift - SPA_BLKPTRSHIFT);
42 	dnode_t *dn;
43 	int restarted = B_FALSE;
44 
45 	mutex_enter(&osi->os_obj_lock);
46 	for (;;) {
47 		object = osi->os_obj_next;
48 		/*
49 		 * Each time we polish off an L2 bp worth of dnodes
50 		 * (2^13 objects), move to another L2 bp that's still
51 		 * reasonably sparse (at most 1/4 full).  Look from the
52 		 * beginning once, but after that keep looking from here.
53 		 * If we can't find one, just keep going from here.
54 		 */
55 		if (P2PHASE(object, L2_dnode_count) == 0) {
56 			uint64_t offset = restarted ? object << DNODE_SHIFT : 0;
57 			int error = dnode_next_offset(osi->os_meta_dnode,
58 			    B_TRUE, &offset, 2, DNODES_PER_BLOCK >> 2);
59 			restarted = B_TRUE;
60 			if (error == 0)
61 				object = offset >> DNODE_SHIFT;
62 		}
63 		osi->os_obj_next = ++object;
64 
65 		dn = dnode_hold_impl(os->os, object, DNODE_MUST_BE_FREE, FTAG);
66 		if (dn)
67 			break;
68 
69 		if (dmu_object_next(os, &object, B_TRUE) == 0)
70 			osi->os_obj_next = object - 1;
71 	}
72 
73 	dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, tx);
74 	dnode_rele(dn, FTAG);
75 
76 	mutex_exit(&osi->os_obj_lock);
77 
78 	dmu_tx_add_new_object(tx, os, object);
79 	return (object);
80 }
81 
82 int
83 dmu_object_claim(objset_t *os, uint64_t object, dmu_object_type_t ot,
84     int blocksize, dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
85 {
86 	dnode_t *dn;
87 
88 	if ((object & DMU_PRIVATE_OBJECT) && !dmu_tx_private_ok(tx))
89 		return (EBADF);
90 
91 	dn = dnode_hold_impl(os->os, object, DNODE_MUST_BE_FREE, FTAG);
92 	if (dn == NULL)
93 		return (EEXIST);
94 	dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, tx);
95 	dnode_rele(dn, FTAG);
96 
97 	dmu_tx_add_new_object(tx, os, object);
98 	return (0);
99 }
100 
101 int
102 dmu_object_reclaim(objset_t *os, uint64_t object, dmu_object_type_t ot,
103     int blocksize, dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
104 {
105 	dnode_t *dn;
106 
107 	if ((object & DMU_PRIVATE_OBJECT) && !dmu_tx_private_ok(tx))
108 		return (EBADF);
109 
110 	dn = dnode_hold_impl(os->os, object, DNODE_MUST_BE_ALLOCATED, FTAG);
111 	if (dn == NULL)
112 		return (EBADF);
113 	dnode_reallocate(dn, ot, blocksize, bonustype, bonuslen, tx);
114 	dnode_rele(dn, FTAG);
115 
116 	return (0);
117 }
118 
119 int
120 dmu_object_free(objset_t *os, uint64_t object, dmu_tx_t *tx)
121 {
122 	dnode_t *dn;
123 
124 	ASSERT(!(object & DMU_PRIVATE_OBJECT) || dmu_tx_private_ok(tx));
125 
126 	dn = dnode_hold_impl(os->os, object, DNODE_MUST_BE_ALLOCATED, FTAG);
127 	if (dn == NULL)
128 		return (ENOENT);
129 
130 	ASSERT(dn->dn_type != DMU_OT_NONE);
131 	dnode_free(dn, tx);
132 	dnode_rele(dn, FTAG);
133 
134 	return (0);
135 }
136 
137 int
138 dmu_object_next(objset_t *os, uint64_t *objectp, boolean_t hole)
139 {
140 	uint64_t offset = (*objectp + 1) << DNODE_SHIFT;
141 	int error;
142 
143 	error = dnode_next_offset(os->os->os_meta_dnode,
144 	    hole, &offset, 0, DNODES_PER_BLOCK);
145 
146 	*objectp = offset >> DNODE_SHIFT;
147 
148 	return (error);
149 }
150