dmu_tx.c revision 215de5951bb4495ba8c9cab0ccc0757dd7df69f0
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/dmu_impl.h>
#include <sys/dmu_objset.h>
#include <sys/dsl_pool.h>
#include <sys/zfs_context.h>
#ifdef ZFS_DEBUG
int dmu_use_tx_debug_bufs = 1;
#endif
dmu_tx_t *
{
if (dd)
return (tx);
}
dmu_tx_t *
{
return (tx);
}
dmu_tx_t *
{
return (tx);
}
int
{
}
int
{
}
static void
{
int err;
if (object != DMU_NEW_OBJECT) {
if (err) {
return;
}
/*
* dn->dn_assigned_txg == tx->tx_txg doesn't pose a
* problem, but there's no way for it to happen (for
* now, at least).
*/
}
}
if (func)
}
void
{
/*
* If we're syncing, they can manipulate any object anyhow, and
* the hold on the dnode_t can cause problems.
*/
if (!dmu_tx_is_syncing(tx)) {
NULL, 0, 0);
}
}
static int
{
int err;
return (EIO);
return (err);
}
/* ARGSUSED */
static void
{
if (len == 0)
return;
/*
* For i/o error checking, read the first and last level-0
* blocks, and all the level-1 blocks. We needn't do this on
* the meta-dnode, because we've already read it in.
*/
int err;
if (dn->dn_maxblkid == 0) {
if (err) {
return;
}
} else {
/* first level-0 block */
if (err) {
return;
}
/* last level-0 block */
if (err) {
return;
}
}
/* level-1 blocks */
if (err) {
return;
}
}
}
if (err) {
return;
}
}
}
/*
* If there's more than one block, the blocksize can't change,
* so we can make a more precise estimate. Alternatively,
* if the dnode's ibs is larger than max_ibs, always use that.
* This ensures that if we reduce DN_MAX_INDBLKSHIFT,
* the code will still work correctly on existing pools.
*/
if (dn->dn_datablkshift != 0)
}
/*
* 'end' is the last thing we will access, not one past.
* This way we won't overflow when accessing the last byte.
*/
/*
* The object contains at most 2^(64 - min_bs) blocks,
* and each indirect level maps 2^epbs.
*/
/*
* If we increase the number of levels of indirection,
* we'll need new blkid=0 indirect blocks. If start == 0,
* we're already accounting for that blocks; and if end == 0,
* we can't increase the number of levels beyond that.
*/
}
}
static void
{
}
}
/* ARGSUSED */
static void
{
}
void
{
}
static void
{
int dirty;
/*
* We don't need to use any locking to check for dirtyness
* because it's OK if we get stale data -- the dnode may become
* dirty immediately after our check anyway. However, we need
* the lock to ensure that the link isn't changing while we call
* list_link_active(), to satisfy its assertions. This is just
* a means to avoid the expensive count when we aren't sure we
* need it. We need to be able to deal with a dirty dnode.
*/
return;
/*
* the struct_rwlock protects us against dn_phys->dn_nlevels
* changing, in case (against all odds) we manage to dirty &
* sync out the changes after we check for being dirty.
* also, dbuf_hold_impl() wants us to have the struct_rwlock.
*
* It's fine to use dn_datablkshift rather than the dn_phys
* equivalent because if it is changing, maxblkid==0 and we will
* bail.
*/
blkid = 0;
nblks = 1;
} else {
return;
}
} else {
return;
}
/* don't bother after 128,000 blocks */
}
int i;
for (i = 0; i < nblks; i++) {
}
}
nblks = 0;
}
while (nblks) {
if (err == 0) {
int i;
if (err != 0) {
break;
}
for (i = 0; i < tochk; i++) {
dprintf_bp(&bp[i],
"can free old%s", "");
}
}
}
break;
}
}
}
static void
{
/* first block */
if (off != 0 /* || dn->dn_maxblkid == 0 */)
/* last block */
if (len != DMU_OBJECT_END)
return;
if (len == DMU_OBJECT_END)
/*
* For i/o error checking, read the first and last level-0
* blocks, and all the level-1 blocks. The above count_write's
* will take care of the level-0 blocks.
*/
break;
if (err) {
return;
}
if (err) {
return;
}
}
if (err) {
return;
}
}
void
{
}
/* ARGSUSED */
static void
{
/*
* We will be able to fit a new object's entries into one leaf
* block. So there will be at most 2 blocks total,
* including the header block.
*/
return;
}
/*
* If there is only one block (i.e. this is a micro-zap)
* and we are not adding anything, the accounting is simple.
*/
if (err) {
return;
}
else
return;
}
/*
* access the name in this fat-zap so that we'll check
* for i/o errors to the leaf blocks, etc.
*/
8, 0, NULL);
return;
}
}
/*
* 3 blocks overwritten: target leaf, ptrtbl block, header block
* 3 new blocks written if adding: new split leaf, 2 grown ptrtbl blocks
*/
/*
* If the modified blocks are scattered to the four winds,
* we'll have to modify an indirect twig for each.
*/
}
void
{
}
void
{
dmu_tx_hold_write_impl, 0, 0);
}
/* ARGSUSED */
static void
{
}
void
{
dmu_tx_hold_space_impl, space, 0);
}
int
{
int holds = 0;
/*
* By asserting that the tx is assigned, we're counting the
* number of dn_tx_holds, which is the same as the number of
* dn_holds. Otherwise, we'd be counting dn_holds, but
* dn_tx_holds could be 0.
*/
/* if (tx->tx_anyobj == TRUE) */
/* return (0); */
holds++;
}
return (holds);
}
#ifdef ZFS_DEBUG
void
{
return;
/* XXX No checking on the meta dnode for now */
return;
match_object = TRUE;
/* XXX dth_arg2 better not be zero... */
dprintf("found dth type %x beginblk=%llx endblk=%llx\n",
case THT_WRITE:
match_offset = TRUE;
/*
* We will let this hold work for the bonus
* buffer so that we don't need to hold it
* when creating a new object.
*/
if (blkid == DB_BONUS_BLKID)
match_offset = TRUE;
/*
* They might have to increase nlevels,
* thus dirtying the new TLIBs. Or the
* might have to change the block size,
* thus dirying the new lvl=0 blk=0.
*/
if (blkid == 0)
match_offset = TRUE;
break;
case THT_FREE:
dn->dn_maxblkid == 0))
match_offset = TRUE;
match_offset = TRUE;
break;
case THT_BONUS:
if (blkid == DB_BONUS_BLKID)
match_offset = TRUE;
break;
case THT_ZAP:
match_offset = TRUE;
break;
case THT_NEWOBJECT:
match_object = TRUE;
break;
default:
ASSERT(!"bad dth_type");
}
}
if (match_object && match_offset)
return;
}
panic("dirtying dbuf obj=%llx lvl=%u blkid=%llx but not tx_held\n",
}
#endif
static int
{
return (ERESTART);
return (ERESTART);
}
}
if (dn->dn_assigned_txg == 0) {
} else {
}
}
}
/*
* If a snapshot has been taken since we made our estimates,
* assume that we won't be able to free or overwrite anything.
*/
tx->tx_lastsnap_txg) {
tx->tx_space_tooverwrite = 0;
tx->tx_space_tofree = 0;
}
/*
* Convert logical size to worst-case allocated size.
*/
if (err) {
return (err);
}
}
return (0);
}
static uint64_t
{
continue;
dn->dn_assigned_txg = 0;
}
}
return (txg);
}
/*
* Assign tx to a transaction group. txg_how can be one of:
*
* (1) TXG_WAIT. If the current open txg is full, waits until there's
* a new one. This should be used when you're not holding locks.
* If will only fail if we're truly out of space (or over quota).
*
* (2) TXG_NOWAIT. If we can't assign into the current open txg without
* blocking, returns immediately with ERESTART. This should be used
* whenever you're holding locks. On an ERESTART error, the caller
* should drop locks, do a txg_wait_open(dp, 0), and try again.
*
* (3) A specific txg. Use this if you need to ensure that multiple
* transactions all sync in the same txg. Like TXG_NOWAIT, it
* returns ERESTART if it can't assign you into the requested txg.
*/
int
{
int err;
return (err);
}
return (0);
}
void
{
return;
if (delta > 0) {
} else {
}
}
void
{
continue;
dn->dn_assigned_txg = 0;
}
}
}
dprintf("towrite=%llu written=%llu tofree=%llu freed=%llu\n",
#ifdef ZFS_DEBUG
if (tx->tx_debug_buf)
#endif
}
void
{
}
#ifdef ZFS_DEBUG
if (tx->tx_debug_buf)
#endif
}
{
}