usr/src/uts/common/fs/zfs/dmu.c
changeset 6992 20c04e18c58c
parent 5450 b25030891c44
child 7046 361307ae060d
equal deleted inserted replaced
6991:c0faefde7d97 6992:20c04e18c58c
    17  * information: Portions Copyright [yyyy] [name of copyright owner]
    17  * information: Portions Copyright [yyyy] [name of copyright owner]
    18  *
    18  *
    19  * CDDL HEADER END
    19  * CDDL HEADER END
    20  */
    20  */
    21 /*
    21 /*
    22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
    22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
    23  * Use is subject to license terms.
    23  * Use is subject to license terms.
    24  */
    24  */
    25 
    25 
    26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
    26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
    27 
    27 
   362 	rw_exit(&dn->dn_struct_rwlock);
   362 	rw_exit(&dn->dn_struct_rwlock);
   363 
   363 
   364 	dnode_rele(dn, FTAG);
   364 	dnode_rele(dn, FTAG);
   365 }
   365 }
   366 
   366 
       
   367 static int
       
   368 get_next_chunk(dnode_t *dn, uint64_t *offset, uint64_t limit)
       
   369 {
       
   370 	uint64_t len = limit - *offset;
       
   371 	uint64_t chunk_len = dn->dn_datablksz * DMU_MAX_DELETEBLKCNT;
       
   372 	uint64_t dn_used;
       
   373 	int err;
       
   374 
       
   375 	ASSERT(limit <= *offset);
       
   376 
       
   377 	dn_used = dn->dn_phys->dn_used <<
       
   378 	    (dn->dn_phys->dn_flags & DNODE_FLAG_USED_BYTES ? 0 : DEV_BSHIFT);
       
   379 	if (len <= chunk_len || dn_used <= chunk_len) {
       
   380 		*offset = limit;
       
   381 		return (0);
       
   382 	}
       
   383 
       
   384 	while (*offset > limit) {
       
   385 		uint64_t initial_offset = *offset;
       
   386 		uint64_t delta;
       
   387 
       
   388 		/* skip over allocated data */
       
   389 		err = dnode_next_offset(dn,
       
   390 		    DNODE_FIND_HOLE|DNODE_FIND_BACKWARDS, offset, 1, 1, 0);
       
   391 		if (err == ESRCH)
       
   392 			*offset = limit;
       
   393 		else if (err)
       
   394 			return (err);
       
   395 
       
   396 		ASSERT3U(*offset, <=, initial_offset);
       
   397 		delta = initial_offset - *offset;
       
   398 		if (delta >= chunk_len) {
       
   399 			*offset += delta - chunk_len;
       
   400 			return (0);
       
   401 		}
       
   402 		chunk_len -= delta;
       
   403 
       
   404 		/* skip over unallocated data */
       
   405 		err = dnode_next_offset(dn,
       
   406 		    DNODE_FIND_BACKWARDS, offset, 1, 1, 0);
       
   407 		if (err == ESRCH)
       
   408 			*offset = limit;
       
   409 		else if (err)
       
   410 			return (err);
       
   411 
       
   412 		if (*offset < limit)
       
   413 			*offset = limit;
       
   414 		ASSERT3U(*offset, <, initial_offset);
       
   415 	}
       
   416 	return (0);
       
   417 }
       
   418 
       
   419 static int
       
   420 dmu_free_long_range_impl(objset_t *os, dnode_t *dn, uint64_t offset,
       
   421     uint64_t length, boolean_t free_dnode)
       
   422 {
       
   423 	dmu_tx_t *tx;
       
   424 	uint64_t object_size, start, end, len;
       
   425 	boolean_t trunc = (length == DMU_OBJECT_END);
       
   426 	int align, err;
       
   427 
       
   428 	align = 1 << dn->dn_datablkshift;
       
   429 	ASSERT(align > 0);
       
   430 	object_size = align == 1 ? dn->dn_datablksz :
       
   431 	    (dn->dn_maxblkid + 1) << dn->dn_datablkshift;
       
   432 
       
   433 	if (trunc || (end = offset + length) > object_size)
       
   434 		end = object_size;
       
   435 	if (end <= offset)
       
   436 		return (0);
       
   437 	length = end - offset;
       
   438 
       
   439 	while (length) {
       
   440 		start = end;
       
   441 		err = get_next_chunk(dn, &start, offset);
       
   442 		if (err)
       
   443 			return (err);
       
   444 		len = trunc ? DMU_OBJECT_END : end - start;
       
   445 
       
   446 		tx = dmu_tx_create(os);
       
   447 		dmu_tx_hold_free(tx, dn->dn_object, start, len);
       
   448 		err = dmu_tx_assign(tx, TXG_WAIT);
       
   449 		if (err) {
       
   450 			dmu_tx_abort(tx);
       
   451 			return (err);
       
   452 		}
       
   453 
       
   454 		dnode_free_range(dn, start, trunc ? -1 : len, tx);
       
   455 
       
   456 		if (start == 0 && trunc && free_dnode)
       
   457 			dnode_free(dn, tx);
       
   458 
       
   459 		length -= end - start;
       
   460 
       
   461 		dmu_tx_commit(tx);
       
   462 		end = start;
       
   463 		trunc = FALSE;
       
   464 	}
       
   465 	return (0);
       
   466 }
       
   467 
       
   468 int
       
   469 dmu_free_long_range(objset_t *os, uint64_t object,
       
   470     uint64_t offset, uint64_t length)
       
   471 {
       
   472 	dnode_t *dn;
       
   473 	int err;
       
   474 
       
   475 	err = dnode_hold(os->os, object, FTAG, &dn);
       
   476 	if (err != 0)
       
   477 		return (err);
       
   478 	err = dmu_free_long_range_impl(os, dn, offset, length, FALSE);
       
   479 	dnode_rele(dn, FTAG);
       
   480 	return (err);
       
   481 }
       
   482 
       
   483 int
       
   484 dmu_free_object(objset_t *os, uint64_t object)
       
   485 {
       
   486 	dnode_t *dn;
       
   487 	dmu_tx_t *tx;
       
   488 	int err;
       
   489 
       
   490 	err = dnode_hold_impl(os->os, object, DNODE_MUST_BE_ALLOCATED,
       
   491 	    FTAG, &dn);
       
   492 	if (err != 0)
       
   493 		return (err);
       
   494 	if (dn->dn_nlevels == 1) {
       
   495 		tx = dmu_tx_create(os);
       
   496 		dmu_tx_hold_bonus(tx, object);
       
   497 		dmu_tx_hold_free(tx, dn->dn_object, 0, DMU_OBJECT_END);
       
   498 		err = dmu_tx_assign(tx, TXG_WAIT);
       
   499 		if (err == 0) {
       
   500 			dnode_free_range(dn, 0, DMU_OBJECT_END, tx);
       
   501 			dnode_free(dn, tx);
       
   502 			dmu_tx_commit(tx);
       
   503 		} else {
       
   504 			dmu_tx_abort(tx);
       
   505 		}
       
   506 	} else {
       
   507 		err = dmu_free_long_range_impl(os, dn, 0, DMU_OBJECT_END, TRUE);
       
   508 	}
       
   509 	dnode_rele(dn, FTAG);
       
   510 	return (err);
       
   511 }
       
   512 
   367 int
   513 int
   368 dmu_free_range(objset_t *os, uint64_t object, uint64_t offset,
   514 dmu_free_range(objset_t *os, uint64_t object, uint64_t offset,
   369     uint64_t size, dmu_tx_t *tx)
   515     uint64_t size, dmu_tx_t *tx)
   370 {
   516 {
   371 	dnode_t *dn;
   517 	dnode_t *dn;
   910 		err = dnode_hold(os->os, object, FTAG, &dn);
  1056 		err = dnode_hold(os->os, object, FTAG, &dn);
   911 		if (err)
  1057 		if (err)
   912 			return (err);
  1058 			return (err);
   913 	}
  1059 	}
   914 
  1060 
   915 	err = dnode_next_offset(dn, hole, off, 1, 1, 0);
  1061 	err = dnode_next_offset(dn, (hole ? DNODE_FIND_HOLE : 0), off, 1, 1, 0);
   916 	dnode_rele(dn, FTAG);
  1062 	dnode_rele(dn, FTAG);
   917 
  1063 
   918 	return (err);
  1064 	return (err);
   919 }
  1065 }
   920 
  1066