dmu_object.c revision 249195
1219820Sjeff/*
2219820Sjeff * CDDL HEADER START
3219820Sjeff *
4219820Sjeff * The contents of this file are subject to the terms of the
5219820Sjeff * Common Development and Distribution License (the "License").
6219820Sjeff * You may not use this file except in compliance with the License.
7219820Sjeff *
8219820Sjeff * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9219820Sjeff * or http://www.opensolaris.org/os/licensing.
10219820Sjeff * See the License for the specific language governing permissions
11219820Sjeff * and limitations under the License.
12219820Sjeff *
13219820Sjeff * When distributing Covered Code, include this CDDL HEADER in each
14219820Sjeff * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15219820Sjeff * If applicable, add the following below this CDDL HEADER, with the
16219820Sjeff * fields enclosed by brackets "[]" replaced with your own identifying
17219820Sjeff * information: Portions Copyright [yyyy] [name of copyright owner]
18219820Sjeff *
19219820Sjeff * CDDL HEADER END
20219820Sjeff */
21219820Sjeff/*
22219820Sjeff * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23219820Sjeff * Copyright (c) 2013 by Delphix. All rights reserved.
24219820Sjeff */
25219820Sjeff
26219820Sjeff#include <sys/dmu.h>
27219820Sjeff#include <sys/dmu_objset.h>
28219820Sjeff#include <sys/dmu_tx.h>
29219820Sjeff#include <sys/dnode.h>
30219820Sjeff
31219820Sjeffuint64_t
32219820Sjeffdmu_object_alloc(objset_t *os, dmu_object_type_t ot, int blocksize,
33219820Sjeff    dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
34219820Sjeff{
35219820Sjeff	uint64_t object;
36219820Sjeff	uint64_t L2_dnode_count = DNODES_PER_BLOCK <<
37219820Sjeff	    (DMU_META_DNODE(os)->dn_indblkshift - SPA_BLKPTRSHIFT);
38219820Sjeff	dnode_t *dn = NULL;
39219820Sjeff	int restarted = B_FALSE;
40219820Sjeff
41219820Sjeff	mutex_enter(&os->os_obj_lock);
42219820Sjeff	for (;;) {
43219820Sjeff		object = os->os_obj_next;
44219820Sjeff		/*
45219820Sjeff		 * Each time we polish off an L2 bp worth of dnodes
46219820Sjeff		 * (2^13 objects), move to another L2 bp that's still
47219820Sjeff		 * reasonably sparse (at most 1/4 full).  Look from the
48219820Sjeff		 * beginning once, but after that keep looking from here.
49219820Sjeff		 * If we can't find one, just keep going from here.
50219820Sjeff		 */
51219820Sjeff		if (P2PHASE(object, L2_dnode_count) == 0) {
52219820Sjeff			uint64_t offset = restarted ? object << DNODE_SHIFT : 0;
53219820Sjeff			int error = dnode_next_offset(DMU_META_DNODE(os),
54219820Sjeff			    DNODE_FIND_HOLE,
55219820Sjeff			    &offset, 2, DNODES_PER_BLOCK >> 2, 0);
56219820Sjeff			restarted = B_TRUE;
57219820Sjeff			if (error == 0)
58219820Sjeff				object = offset >> DNODE_SHIFT;
59219820Sjeff		}
60219820Sjeff		os->os_obj_next = ++object;
61219820Sjeff
62219820Sjeff		/*
63219820Sjeff		 * XXX We should check for an i/o error here and return
64219820Sjeff		 * up to our caller.  Actually we should pre-read it in
65219820Sjeff		 * dmu_tx_assign(), but there is currently no mechanism
66219820Sjeff		 * to do so.
67219820Sjeff		 */
68219820Sjeff		(void) dnode_hold_impl(os, object, DNODE_MUST_BE_FREE,
69219820Sjeff		    FTAG, &dn);
70219820Sjeff		if (dn)
71219820Sjeff			break;
72219820Sjeff
73219820Sjeff		if (dmu_object_next(os, &object, B_TRUE, 0) == 0)
74219820Sjeff			os->os_obj_next = object - 1;
75219820Sjeff	}
76219820Sjeff
77219820Sjeff	dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, tx);
78219820Sjeff	dnode_rele(dn, FTAG);
79219820Sjeff
80219820Sjeff	mutex_exit(&os->os_obj_lock);
81219820Sjeff
82219820Sjeff	dmu_tx_add_new_object(tx, os, object);
83219820Sjeff	return (object);
84219820Sjeff}
85219820Sjeff
86219820Sjeffint
87219820Sjeffdmu_object_claim(objset_t *os, uint64_t object, dmu_object_type_t ot,
88219820Sjeff    int blocksize, dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
89219820Sjeff{
90219820Sjeff	dnode_t *dn;
91219820Sjeff	int err;
92219820Sjeff
93219820Sjeff	if (object == DMU_META_DNODE_OBJECT && !dmu_tx_private_ok(tx))
94219820Sjeff		return (SET_ERROR(EBADF));
95219820Sjeff
96219820Sjeff	err = dnode_hold_impl(os, object, DNODE_MUST_BE_FREE, FTAG, &dn);
97219820Sjeff	if (err)
98219820Sjeff		return (err);
99219820Sjeff	dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, tx);
100219820Sjeff	dnode_rele(dn, FTAG);
101219820Sjeff
102219820Sjeff	dmu_tx_add_new_object(tx, os, object);
103219820Sjeff	return (0);
104219820Sjeff}
105219820Sjeff
106219820Sjeffint
107219820Sjeffdmu_object_reclaim(objset_t *os, uint64_t object, dmu_object_type_t ot,
108219820Sjeff    int blocksize, dmu_object_type_t bonustype, int bonuslen)
109219820Sjeff{
110219820Sjeff	dnode_t *dn;
111219820Sjeff	dmu_tx_t *tx;
112219820Sjeff	int nblkptr;
113219820Sjeff	int err;
114219820Sjeff
115219820Sjeff	if (object == DMU_META_DNODE_OBJECT)
116219820Sjeff		return (SET_ERROR(EBADF));
117219820Sjeff
118219820Sjeff	err = dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED,
119219820Sjeff	    FTAG, &dn);
120219820Sjeff	if (err)
121219820Sjeff		return (err);
122219820Sjeff
123219820Sjeff	if (dn->dn_type == ot && dn->dn_datablksz == blocksize &&
124219820Sjeff	    dn->dn_bonustype == bonustype && dn->dn_bonuslen == bonuslen) {
125219820Sjeff		/* nothing is changing, this is a noop */
126219820Sjeff		dnode_rele(dn, FTAG);
127219820Sjeff		return (0);
128219820Sjeff	}
129219820Sjeff
130219820Sjeff	if (bonustype == DMU_OT_SA) {
131219820Sjeff		nblkptr = 1;
132219820Sjeff	} else {
133219820Sjeff		nblkptr = 1 + ((DN_MAX_BONUSLEN - bonuslen) >> SPA_BLKPTRSHIFT);
134219820Sjeff	}
135219820Sjeff
136219820Sjeff	/*
137219820Sjeff	 * If we are losing blkptrs or changing the block size this must
138219820Sjeff	 * be a new file instance.   We must clear out the previous file
139219820Sjeff	 * contents before we can change this type of metadata in the dnode.
140219820Sjeff	 */
141219820Sjeff	if (dn->dn_nblkptr > nblkptr || dn->dn_datablksz != blocksize) {
142219820Sjeff		err = dmu_free_long_range(os, object, 0, DMU_OBJECT_END);
143219820Sjeff		if (err)
144219820Sjeff			goto out;
145219820Sjeff	}
146219820Sjeff
147219820Sjeff	tx = dmu_tx_create(os);
148219820Sjeff	dmu_tx_hold_bonus(tx, object);
149219820Sjeff	err = dmu_tx_assign(tx, TXG_WAIT);
150219820Sjeff	if (err) {
151219820Sjeff		dmu_tx_abort(tx);
152219820Sjeff		goto out;
153219820Sjeff	}
154219820Sjeff
155219820Sjeff	dnode_reallocate(dn, ot, blocksize, bonustype, bonuslen, tx);
156219820Sjeff
157219820Sjeff	dmu_tx_commit(tx);
158219820Sjeffout:
159219820Sjeff	dnode_rele(dn, FTAG);
160219820Sjeff
161219820Sjeff	return (err);
162219820Sjeff}
163219820Sjeff
164219820Sjeffint
165219820Sjeffdmu_object_free(objset_t *os, uint64_t object, dmu_tx_t *tx)
166219820Sjeff{
167219820Sjeff	dnode_t *dn;
168219820Sjeff	int err;
169219820Sjeff
170219820Sjeff	ASSERT(object != DMU_META_DNODE_OBJECT || dmu_tx_private_ok(tx));
171219820Sjeff
172219820Sjeff	err = dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED,
173219820Sjeff	    FTAG, &dn);
174219820Sjeff	if (err)
175219820Sjeff		return (err);
176219820Sjeff
177219820Sjeff	ASSERT(dn->dn_type != DMU_OT_NONE);
178219820Sjeff	dnode_free_range(dn, 0, DMU_OBJECT_END, tx);
179219820Sjeff	dnode_free(dn, tx);
180219820Sjeff	dnode_rele(dn, FTAG);
181219820Sjeff
182219820Sjeff	return (0);
183219820Sjeff}
184219820Sjeff
185219820Sjeffint
186219820Sjeffdmu_object_next(objset_t *os, uint64_t *objectp, boolean_t hole, uint64_t txg)
187219820Sjeff{
188219820Sjeff	uint64_t offset = (*objectp + 1) << DNODE_SHIFT;
189219820Sjeff	int error;
190219820Sjeff
191219820Sjeff	error = dnode_next_offset(DMU_META_DNODE(os),
192219820Sjeff	    (hole ? DNODE_FIND_HOLE : 0), &offset, 0, DNODES_PER_BLOCK, txg);
193219820Sjeff
194219820Sjeff	*objectp = offset >> DNODE_SHIFT;
195219820Sjeff
196219820Sjeff	return (error);
197219820Sjeff}
198219820Sjeff