]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_object.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / cddl / contrib / opensolaris / uts / common / fs / zfs / dmu_object.c
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  * Copyright (c) 2013 by Delphix. All rights reserved.
24  */
25
26 #include <sys/dmu.h>
27 #include <sys/dmu_objset.h>
28 #include <sys/dmu_tx.h>
29 #include <sys/dnode.h>
30
31 uint64_t
32 dmu_object_alloc(objset_t *os, dmu_object_type_t ot, int blocksize,
33     dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
34 {
35         uint64_t object;
36         uint64_t L2_dnode_count = DNODES_PER_BLOCK <<
37             (DMU_META_DNODE(os)->dn_indblkshift - SPA_BLKPTRSHIFT);
38         dnode_t *dn = NULL;
39         int restarted = B_FALSE;
40
41         mutex_enter(&os->os_obj_lock);
42         for (;;) {
43                 object = os->os_obj_next;
44                 /*
45                  * Each time we polish off an L2 bp worth of dnodes
46                  * (2^13 objects), move to another L2 bp that's still
47                  * reasonably sparse (at most 1/4 full).  Look from the
48                  * beginning once, but after that keep looking from here.
49                  * If we can't find one, just keep going from here.
50                  */
51                 if (P2PHASE(object, L2_dnode_count) == 0) {
52                         uint64_t offset = restarted ? object << DNODE_SHIFT : 0;
53                         int error = dnode_next_offset(DMU_META_DNODE(os),
54                             DNODE_FIND_HOLE,
55                             &offset, 2, DNODES_PER_BLOCK >> 2, 0);
56                         restarted = B_TRUE;
57                         if (error == 0)
58                                 object = offset >> DNODE_SHIFT;
59                 }
60                 os->os_obj_next = ++object;
61
62                 /*
63                  * XXX We should check for an i/o error here and return
64                  * up to our caller.  Actually we should pre-read it in
65                  * dmu_tx_assign(), but there is currently no mechanism
66                  * to do so.
67                  */
68                 (void) dnode_hold_impl(os, object, DNODE_MUST_BE_FREE,
69                     FTAG, &dn);
70                 if (dn)
71                         break;
72
73                 if (dmu_object_next(os, &object, B_TRUE, 0) == 0)
74                         os->os_obj_next = object - 1;
75         }
76
77         dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, tx);
78         dnode_rele(dn, FTAG);
79
80         mutex_exit(&os->os_obj_lock);
81
82         dmu_tx_add_new_object(tx, os, object);
83         return (object);
84 }
85
86 int
87 dmu_object_claim(objset_t *os, uint64_t object, dmu_object_type_t ot,
88     int blocksize, dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
89 {
90         dnode_t *dn;
91         int err;
92
93         if (object == DMU_META_DNODE_OBJECT && !dmu_tx_private_ok(tx))
94                 return (SET_ERROR(EBADF));
95
96         err = dnode_hold_impl(os, object, DNODE_MUST_BE_FREE, FTAG, &dn);
97         if (err)
98                 return (err);
99         dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, tx);
100         dnode_rele(dn, FTAG);
101
102         dmu_tx_add_new_object(tx, os, object);
103         return (0);
104 }
105
106 int
107 dmu_object_reclaim(objset_t *os, uint64_t object, dmu_object_type_t ot,
108     int blocksize, dmu_object_type_t bonustype, int bonuslen)
109 {
110         dnode_t *dn;
111         dmu_tx_t *tx;
112         int nblkptr;
113         int err;
114
115         if (object == DMU_META_DNODE_OBJECT)
116                 return (SET_ERROR(EBADF));
117
118         err = dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED,
119             FTAG, &dn);
120         if (err)
121                 return (err);
122
123         if (dn->dn_type == ot && dn->dn_datablksz == blocksize &&
124             dn->dn_bonustype == bonustype && dn->dn_bonuslen == bonuslen) {
125                 /* nothing is changing, this is a noop */
126                 dnode_rele(dn, FTAG);
127                 return (0);
128         }
129
130         if (bonustype == DMU_OT_SA) {
131                 nblkptr = 1;
132         } else {
133                 nblkptr = 1 + ((DN_MAX_BONUSLEN - bonuslen) >> SPA_BLKPTRSHIFT);
134         }
135
136         /*
137          * If we are losing blkptrs or changing the block size this must
138          * be a new file instance.   We must clear out the previous file
139          * contents before we can change this type of metadata in the dnode.
140          */
141         if (dn->dn_nblkptr > nblkptr || dn->dn_datablksz != blocksize) {
142                 err = dmu_free_long_range(os, object, 0, DMU_OBJECT_END);
143                 if (err)
144                         goto out;
145         }
146
147         tx = dmu_tx_create(os);
148         dmu_tx_hold_bonus(tx, object);
149         err = dmu_tx_assign(tx, TXG_WAIT);
150         if (err) {
151                 dmu_tx_abort(tx);
152                 goto out;
153         }
154
155         dnode_reallocate(dn, ot, blocksize, bonustype, bonuslen, tx);
156
157         dmu_tx_commit(tx);
158 out:
159         dnode_rele(dn, FTAG);
160
161         return (err);
162 }
163
164 int
165 dmu_object_free(objset_t *os, uint64_t object, dmu_tx_t *tx)
166 {
167         dnode_t *dn;
168         int err;
169
170         ASSERT(object != DMU_META_DNODE_OBJECT || dmu_tx_private_ok(tx));
171
172         err = dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED,
173             FTAG, &dn);
174         if (err)
175                 return (err);
176
177         ASSERT(dn->dn_type != DMU_OT_NONE);
178         dnode_free_range(dn, 0, DMU_OBJECT_END, tx);
179         dnode_free(dn, tx);
180         dnode_rele(dn, FTAG);
181
182         return (0);
183 }
184
185 int
186 dmu_object_next(objset_t *os, uint64_t *objectp, boolean_t hole, uint64_t txg)
187 {
188         uint64_t offset = (*objectp + 1) << DNODE_SHIFT;
189         int error;
190
191         error = dnode_next_offset(DMU_META_DNODE(os),
192             (hole ? DNODE_FIND_HOLE : 0), &offset, 0, DNODES_PER_BLOCK, txg);
193
194         *objectp = offset >> DNODE_SHIFT;
195
196         return (error);
197 }