dmu_tx.c revision 9c9dc39aa72ac40bb2558d54adfa596d217135d9
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 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
{
if (object != DMU_NEW_OBJECT) {
/*
* 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).
*/
}
}
/*
* XXX Investigate using a different data structure to keep
* track of dnodes in a tx. Maybe array, since there will
* generally not be many entries?
*/
}
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);
}
}
/* ARGSUSED */
static void
{
if (len == 0)
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
{
if (dn->dn_datablkshift == 0)
return;
/*
* not that the dnode can change, since it isn't dirty, but
* dbuf_hold_impl() wants us to have the struct_rwlock.
* also need it to protect dn_maxblkid.
*/
goto out;
/* don't bother after the 100,000 blocks */
int i;
for (i = 0; i < nblks; i++) {
}
}
goto out;
}
while (nblks) {
if (err == 0) {
int i;
for (i = 0; i < tochk; i++) {
dprintf_bp(&bp[i],
"can free old%s", "");
}
}
} else {
/* the indirect block is sparse */
}
}
out:
}
static void
{
int dirty;
/* first block */
if (off != 0 /* || dn->dn_maxblkid == 0 */)
/* last block */
if (len != DMU_OBJECT_END)
return;
if (len == DMU_OBJECT_END)
/* XXX locking */
}
void
{
}
/* ARGSUSED */
static void
{
int epbs;
/*
* Assuming that nops+cops is not super huge, 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 only doing updates, the accounting is simple.
*/
else
return;
}
/*
* 3 blocks overwritten per op: target leaf, ptrtbl block, header block
* 3 new blocks written per op: 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.
*/
tx->tx_space_towrite +=
}
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
{
tx->tx_space_towrite = 0;
tx->tx_space_tofree = 0;
tx->tx_space_tooverwrite = 0;
return (ERESTART);
return (ERESTART);
}
}
if (dn->dn_assigned_txg == 0) {
} else {
}
}
}
/*
* 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
}
{
}