Deleted Added
sdiff udiff text old ( 209093 ) new ( 209962 )
full compact
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

--- 5 unchanged lines hidden (view full) ---

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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <sys/dmu.h>
27#include <sys/dmu_impl.h>
28#include <sys/dbuf.h>
29#include <sys/dmu_tx.h>
30#include <sys/dmu_objset.h>

--- 124 unchanged lines hidden (view full) ---

155 rw_exit(&dn->dn_struct_rwlock);
156 if (db == NULL)
157 return (EIO);
158 err = dbuf_read(db, zio, DB_RF_CANFAIL | DB_RF_NOPREFETCH);
159 dbuf_rele(db, FTAG);
160 return (err);
161}
162
163static void
164dmu_tx_count_indirects(dmu_tx_hold_t *txh, dmu_buf_impl_t *db,
165 boolean_t freeable, dmu_buf_impl_t **history)
166{
167 int i = db->db_level + 1;
168 dnode_t *dn = db->db_dnode;
169
170 if (i >= dn->dn_nlevels)
171 return;
172
173 db = db->db_parent;
174 if (db == NULL) {
175 uint64_t lvls = dn->dn_nlevels - i;
176
177 txh->txh_space_towrite += lvls << dn->dn_indblkshift;
178 return;
179 }
180
181 if (db != history[i]) {
182 dsl_dataset_t *ds = dn->dn_objset->os_dsl_dataset;
183 uint64_t space = 1ULL << dn->dn_indblkshift;
184
185 freeable = (db->db_blkptr && (freeable ||
186 dsl_dataset_block_freeable(ds, db->db_blkptr->blk_birth)));
187 if (freeable)
188 txh->txh_space_tooverwrite += space;
189 else
190 txh->txh_space_towrite += space;
191 if (db->db_blkptr)
192 txh->txh_space_tounref += space;
193 history[i] = db;
194 dmu_tx_count_indirects(txh, db, freeable, history);
195 }
196}
197
198/* ARGSUSED */
199static void
200dmu_tx_count_write(dmu_tx_hold_t *txh, uint64_t off, uint64_t len)
201{
202 dnode_t *dn = txh->txh_dnode;
203 uint64_t start, end, i;
204 int min_bs, max_bs, min_ibs, max_ibs, epbs, bits;
205 int err = 0;
206
207 if (len == 0)
208 return;
209
210 min_bs = SPA_MINBLOCKSHIFT;
211 max_bs = SPA_MAXBLOCKSHIFT;
212 min_ibs = DN_MIN_INDBLKSHIFT;
213 max_ibs = DN_MAX_INDBLKSHIFT;
214
215 if (dn) {
216 dmu_buf_impl_t *last[DN_MAX_LEVELS];
217 int nlvls = dn->dn_nlevels;
218 int delta;
219
220 /*
221 * For i/o error checking, read the first and last level-0
222 * blocks (if they are not aligned), and all the level-1 blocks.
223 */
224
225 if (dn->dn_maxblkid == 0) {
226 delta = dn->dn_datablksz;
227 start = (off < dn->dn_datablksz) ? 0 : 1;
228 end = (off+len <= dn->dn_datablksz) ? 0 : 1;
229 if (start == 0 && (off > 0 || len < dn->dn_datablksz)) {
230 err = dmu_tx_check_ioerr(NULL, dn, 0, 0);
231 if (err)
232 goto out;
233 delta -= off;
234 }
235 } else {
236 zio_t *zio = zio_root(dn->dn_objset->os_spa,
237 NULL, NULL, ZIO_FLAG_CANFAIL);
238
239 /* first level-0 block */
240 start = off >> dn->dn_datablkshift;
241 if (P2PHASE(off, dn->dn_datablksz) ||
242 len < dn->dn_datablksz) {

--- 7 unchanged lines hidden (view full) ---

250 if (end != start &&
251 P2PHASE(off+len, dn->dn_datablksz)) {
252 err = dmu_tx_check_ioerr(zio, dn, 0, end);
253 if (err)
254 goto out;
255 }
256
257 /* level-1 blocks */
258 if (nlvls > 1) {
259 int shft = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
260 for (i = (start>>shft)+1; i < end>>shft; i++) {
261 err = dmu_tx_check_ioerr(zio, dn, 1, i);
262 if (err)
263 goto out;
264 }
265 }
266
267 err = zio_wait(zio);
268 if (err)
269 goto out;
270 delta = P2NPHASE(off, dn->dn_datablksz);
271 }
272
273 if (dn->dn_maxblkid > 0) {
274 /*
275 * The blocksize can't change,
276 * so we can make a more precise estimate.
277 */
278 ASSERT(dn->dn_datablkshift != 0);
279 min_bs = max_bs = dn->dn_datablkshift;
280 min_ibs = max_ibs = dn->dn_indblkshift;
281 } else if (dn->dn_indblkshift > max_ibs) {
282 /*
283 * This ensures that if we reduce DN_MAX_INDBLKSHIFT,
284 * the code will still work correctly on older pools.
285 */
286 min_ibs = max_ibs = dn->dn_indblkshift;
287 }
288
289 /*
290 * If this write is not off the end of the file
291 * we need to account for overwrites/unref.
292 */
293 if (start <= dn->dn_maxblkid)
294 bzero(last, sizeof (dmu_buf_impl_t *) * DN_MAX_LEVELS);
295 while (start <= dn->dn_maxblkid) {
296 spa_t *spa = txh->txh_tx->tx_pool->dp_spa;
297 dsl_dataset_t *ds = dn->dn_objset->os_dsl_dataset;
298 dmu_buf_impl_t *db;
299
300 rw_enter(&dn->dn_struct_rwlock, RW_READER);
301 db = dbuf_hold_level(dn, 0, start, FTAG);
302 rw_exit(&dn->dn_struct_rwlock);
303 if (db->db_blkptr && dsl_dataset_block_freeable(ds,
304 db->db_blkptr->blk_birth)) {
305 dprintf_bp(db->db_blkptr, "can free old%s", "");
306 txh->txh_space_tooverwrite += dn->dn_datablksz;
307 txh->txh_space_tounref += dn->dn_datablksz;
308 dmu_tx_count_indirects(txh, db, TRUE, last);
309 } else {
310 txh->txh_space_towrite += dn->dn_datablksz;
311 if (db->db_blkptr)
312 txh->txh_space_tounref +=
313 bp_get_dasize(spa, db->db_blkptr);
314 dmu_tx_count_indirects(txh, db, FALSE, last);
315 }
316 dbuf_rele(db, FTAG);
317 if (++start > end) {
318 /*
319 * Account for new indirects appearing
320 * before this IO gets assigned into a txg.
321 */
322 bits = 64 - min_bs;
323 epbs = min_ibs - SPA_BLKPTRSHIFT;
324 for (bits -= epbs * (nlvls - 1);
325 bits >= 0; bits -= epbs)
326 txh->txh_fudge += 1ULL << max_ibs;
327 goto out;
328 }
329 off += delta;
330 if (len >= delta)
331 len -= delta;
332 delta = dn->dn_datablksz;
333 }
334 }
335
336 /*
337 * 'end' is the last thing we will access, not one past.
338 * This way we won't overflow when accessing the last byte.
339 */
340 start = P2ALIGN(off, 1ULL << max_bs);
341 end = P2ROUNDUP(off + len, 1ULL << max_bs) - 1;

--- 6 unchanged lines hidden (view full) ---

348
349 /*
350 * The object contains at most 2^(64 - min_bs) blocks,
351 * and each indirect level maps 2^epbs.
352 */
353 for (bits = 64 - min_bs; bits >= 0; bits -= epbs) {
354 start >>= epbs;
355 end >>= epbs;
356 ASSERT3U(end, >=, start);
357 txh->txh_space_towrite += (end - start + 1) << max_ibs;
358 if (start != 0) {
359 /*
360 * We also need a new blkid=0 indirect block
361 * to reference any existing file data.
362 */
363 txh->txh_space_towrite += 1ULL << max_ibs;
364 }
365 }
366
367out:
368 if (txh->txh_space_towrite + txh->txh_space_tooverwrite >
369 2 * DMU_MAX_ACCESS)
370 err = EFBIG;
371
372 if (err)
373 txh->txh_tx->tx_err = err;
374}
375
376static void
377dmu_tx_count_dnode(dmu_tx_hold_t *txh)
378{
379 dnode_t *dn = txh->txh_dnode;
380 dnode_t *mdn = txh->txh_tx->tx_objset->os->os_meta_dnode;
381 uint64_t space = mdn->dn_datablksz +
382 ((mdn->dn_nlevels-1) << mdn->dn_indblkshift);
383
384 if (dn && dn->dn_dbuf->db_blkptr &&
385 dsl_dataset_block_freeable(dn->dn_objset->os_dsl_dataset,
386 dn->dn_dbuf->db_blkptr->blk_birth)) {
387 txh->txh_space_tooverwrite += space;
388 txh->txh_space_tounref += space;
389 } else {
390 txh->txh_space_towrite += space;
391 if (dn && dn->dn_dbuf->db_blkptr)
392 txh->txh_space_tounref += space;
393 }
394}
395
396void

--- 227 unchanged lines hidden (view full) ---

624 }
625 }
626
627 dmu_tx_count_dnode(txh);
628 dmu_tx_count_free(txh, off, len);
629}
630
631void
632dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name)
633{
634 dmu_tx_hold_t *txh;
635 dnode_t *dn;
636 uint64_t nblocks;
637 int epbs, err;
638
639 ASSERT(tx->tx_txg == 0);
640

--- 51 unchanged lines hidden (view full) ---

692 err = zap_lookup(&dn->dn_objset->os, dn->dn_object, name,
693 8, 0, NULL);
694 if (err == EIO) {
695 tx->tx_err = err;
696 return;
697 }
698 }
699
700 err = zap_count_write(&dn->dn_objset->os, dn->dn_object, name, add,
701 &txh->txh_space_towrite, &txh->txh_space_tooverwrite);
702
703 /*
704 * If the modified blocks are scattered to the four winds,
705 * we'll have to modify an indirect twig for each.
706 */
707 epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
708 for (nblocks = dn->dn_maxblkid >> epbs; nblocks != 0; nblocks >>= epbs)
709 if (dn->dn_objset->os_dsl_dataset->ds_phys->ds_prev_snap_obj)
710 txh->txh_space_towrite += 3 << dn->dn_indblkshift;
711 else
712 txh->txh_space_tooverwrite += 3 << dn->dn_indblkshift;
713}
714
715void
716dmu_tx_hold_bonus(dmu_tx_t *tx, uint64_t object)
717{
718 dmu_tx_hold_t *txh;
719
720 ASSERT(tx->tx_txg == 0);

--- 441 unchanged lines hidden ---