dmu.c revision feb08c6bb47ceffa5bb7a70f2c0549113f40fcc5
/*
* 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 2007 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/zfs_context.h>
#include <sys/dmu_objset.h>
#include <sys/dmu_traverse.h>
#include <sys/dsl_dataset.h>
#include <sys/dsl_pool.h>
#include <sys/dsl_synctask.h>
#include <sys/dsl_prop.h>
#include <sys/dmu_zfetch.h>
#include <sys/zfs_ioctl.h>
#include <sys/zio_checksum.h>
#ifdef _KERNEL
#endif
};
int
{
int err;
if (err)
return (err);
} else {
if (err) {
}
}
return (err);
}
int
dmu_bonus_max(void)
{
return (DN_MAX_BONUSLEN);
}
/*
* returns ENOENT, EIO, or 0.
*/
int
{
if (err)
return (err);
}
if (count == 1)
return (0);
}
/*
* Note: longer-term, we should modify all of the dmu_buf_*() interfaces
* to take a held dnode rather than <os, object> -- the lookup is wasteful,
* and can induce severe lock contention when writing to several files
* whose dnodes are in the same block.
*/
static int
{
int err;
if (length > zfetch_array_rd_sz)
if (dn->dn_datablkshift) {
} else {
nblks = 1;
}
for (i = 0; i < nblks; i++) {
return (EIO);
}
/* initiate async i/o */
if (read) {
}
}
/* wait for async i/o */
if (err) {
return (err);
}
/* wait for other io to complete */
if (read) {
for (i = 0; i < nblks; i++) {
if (err) {
return (err);
}
}
}
return (0);
}
static int
{
int err;
if (err)
return (err);
return (err);
}
int
{
int err;
return (err);
}
void
{
int i;
if (numbufs == 0)
return;
for (i = 0; i < numbufs; i++) {
if (dbp[i])
}
}
void
{
if (zfs_prefetch_disable)
return;
if (len == 0) { /* they're interested in the bonus buffer */
return;
return;
}
/*
* XXX - Note, if the dnode for the requested object is not
* already cached, we will do a *synchronous* read in the
* dnode_hold() call. The same is true for any indirects.
*/
if (err != 0)
return;
if (dn->dn_datablkshift) {
} else {
}
if (nblks != 0) {
for (i = 0; i < nblks; i++)
}
}
int
{
if (err)
return (err);
return (0);
}
int
void *buf)
{
if (err)
return (err);
/*
* Deal with odd block sizes, where there can't be data past the first
* block. If we ever do the tail block optimization, we will need to
* handle that here as well.
*/
if (dn->dn_datablkshift == 0) {
}
while (size > 0) {
int err;
/*
* NB: we could do this block-at-a-time, but it's nice
* to be reading in parallel.
*/
if (err)
return (err);
for (i = 0; i < numbufs; i++) {
int tocpy;
int bufoff;
}
}
return (0);
}
void
{
int numbufs, i;
if (size == 0)
return;
for (i = 0; i < numbufs; i++) {
int tocpy;
int bufoff;
else
}
}
#ifdef _KERNEL
int
{
/*
* NB: we could do this block-at-a-time, but it's nice
* to be reading in parallel.
*/
if (err)
return (err);
for (i = 0; i < numbufs; i++) {
int tocpy;
int bufoff;
if (err)
break;
}
return (err);
}
int
{
int numbufs, i;
int err = 0;
if (size == 0)
return (0);
if (err)
return (err);
for (i = 0; i < numbufs; i++) {
int tocpy;
int bufoff;
else
/*
* XXX uiomove could block forever (eg. nfs-backed
* pages). There needs to be a uiolockdown() function
* to lock the pages in memory, so that uiomove won't
* block.
*/
if (err)
break;
}
return (err);
}
int
{
int numbufs, i;
int err;
if (size == 0)
return (0);
if (err)
return (err);
for (i = 0; i < numbufs; i++) {
int bufoff;
else
}
if (err)
break;
}
return (err);
}
#endif
typedef struct {
void *arg;
/* ARGSUSED */
static void
{
}
if (done)
}
/*
* Intent log support: sync the block associated with db to disk.
* N.B. and XXX: the caller is responsible for making sure that the
* data isn't changing while dmu_sync() is writing it.
*
* Return values:
*
* EEXIST: this txg has already been synced, so there's nothing to to.
* The caller should not log the write.
*
* ENOENT: the block was dbuf_free_range()'d, so there's nothing to do.
* The caller should not log the write.
*
* EALREADY: this block is already in the process of being synced.
* The caller should track its progress (somehow).
*
* EINPROGRESS: the IO has been initiated.
* The caller should log this blkptr in the callback.
*
* 0: completed. Sets *bp to the blkptr just written.
* The caller should log this blkptr immediately.
*/
int
{
int err;
dprintf("dmu_sync txg=%llu, s,o,q %llu %llu %llu\n",
/*
* XXX - would be nice if we could do this without suspending...
*/
/*
* If this txg already synced, there's nothing to do.
*/
txg_resume(dp);
/*
* If we're running ziltest, we need the blkptr regardless.
*/
/* if db_blkptr == NULL, this was an empty write */
return (0);
}
return (EEXIST);
}
while (db->db_data_pending) {
/*
* IO is in-progress. Wait for it to finish.
* XXX - would be nice to be able to somehow "attach"
* this zio to the parent zio passed in.
*/
if (!db->db_data_pending &&
/*
* IO was compressed away
*/
txg_resume(dp);
return (0);
}
}
/*
* IO is already completed.
*/
txg_resume(dp);
return (0);
}
}
/*
* This dbuf isn't dirty, must have been free_range'd.
* There's no need to log writes to freed blocks, so we're done.
*/
txg_resume(dp);
return (ENOENT);
}
/*
* We have already issued a sync write for this buffer.
*/
txg_resume(dp);
return (EALREADY);
/*
* This buffer has already been synced. It could not
* have been dirtied since, or we would have cleared the state.
*/
txg_resume(dp);
return (0);
}
txg_resume(dp);
if (pio) {
err = EINPROGRESS;
} else {
}
return (err);
}
int
{
int err;
if (err)
return (err);
return (err);
}
void
{
/* XXX assumes dnode_hold will not get an i/o error */
}
void
{
/* XXX assumes dnode_hold will not get an i/o error */
}
/*
* XXX - eventually, this should take into account per-dataset (or
* even per-object?) user requests for higher levels of replication.
*/
int
{
int ncopies = 1;
ncopies++;
ncopies++;
ncopies++;
}
int
{
int i, err;
if (err)
return (err);
/*
* Sync any current changes before
* we go trundling through the block pointers.
*/
for (i = 0; i < TXG_SIZE; i++) {
break;
}
if (i != TXG_SIZE) {
if (err)
return (err);
}
return (err);
}
void
{
}
/*
* Get information on a DMU object.
* If doi is NULL, just indicates whether the object exists.
*/
int
{
if (err)
return (err);
return (0);
}
/*
* As above, but faster; can be used when you have a held dbuf in hand.
*/
void
{
}
/*
* Faster still when you only care about the size.
* This is specifically optimized for zfs_getattr().
*/
void
{
/* add 1 for dnode space */
SPA_MINBLOCKSHIFT) + 1;
}
void
{
int i;
for (i = 0; i < count; i++)
}
void
{
int i;
for (i = 0; i < count; i++)
}
void
{
int i;
for (i = 0; i < count; i++)
}
/* ARGSUSED */
void
{
}
void
dmu_init(void)
{
dbuf_init();
dnode_init();
arc_init();
}
void
dmu_fini(void)
{
arc_fini();
dnode_fini();
dbuf_fini();
}