dsl_dir.c revision 1649cd4b1641110b549d9f70a902cafc2007bd77
/*
* 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/dsl_dataset.h>
#include <sys/dsl_prop.h>
#include "zfs_namecheck.h"
/* ARGSUSED */
static void
{
int t;
for (t = 0; t < TXG_SIZE; t++) {
}
/*
* The props callback list should be empty since they hold the
* dir open.
*/
}
{
#ifdef ZFS_DEBUG
{
}
#endif
/* XXX assert bonus buffer size is correct */
int err;
if (tail) {
#ifdef ZFS_DEBUG
#endif
} else {
/*
* The caller should be protecting this ddobj
* from being deleted concurrently
*/
}
} else {
}
if (winner) {
} else {
}
}
/*
* The dsl_dir_t has both open-to-close and instantiate-to-evict
* holds on the spa. We need the open-to-close holds because
* otherwise the spa_refcnt wouldn't change when we open a
* dir which the spa also has open, so we could incorrectly
* the instantiate-to-evict hold because the dsl_dir_t has a
* pointer to the dd_pool, which has a pointer to the spa_t.
*/
return (dd);
}
void
{
}
/* buf must be long enough (MAXNAMELEN should do) */
void
{
} else {
buf[0] = '\0';
}
/*
* recursive mutex so that we can use
* dprintf_dd() with dd_lock held
*/
} else {
}
}
int
{
return (rv);
}
static int
{
char *p;
return (NULL);
/* This would be a good place to reserve some namespace... */
if (p && (p[1] == '/' || p[1] == '@')) {
/* two separators in a row */
return (EINVAL);
}
/*
* if the first thing is an @ or /, it had better be an
* @ and it had better not have any more ats or slashes,
* and it had better have something after the @.
*/
if (p != NULL &&
return (EINVAL);
return (ENAMETOOLONG);
p = NULL;
} else if (p[0] == '/') {
if (p-path >= MAXNAMELEN)
return (ENAMETOOLONG);
p++;
} else if (p[0] == '@') {
/*
* if the next separator is an @, there better not be
* any more slashes.
*/
return (EINVAL);
if (p-path >= MAXNAMELEN)
return (ENAMETOOLONG);
} else {
ASSERT(!"invalid p");
}
*nextp = p;
return (0);
}
/*
* same as dsl_open_dir, ignore the first component of name and use the
* spa instead
*/
{
char buf[MAXNAMELEN];
int err;
dsl_pool_t *dp;
return (NULL);
if (err)
return (NULL);
if (err) {
return (NULL);
}
/* XXX this assertion belongs in spa_open */
}
if (err) {
if (openedspa)
return (NULL);
}
if (next[0] == '@')
break;
break;
dprintf("looking up %s in obj%lld\n",
break;
}
}
/*
* It's an error if there's more than one component left, or
* tailp==NULL and there's any component left.
*/
/* bad path name */
}
if (tailp)
if (openedspa)
return (dd);
}
/*
* Return the dsl_dir_t, and possibly the last component which couldn't
* be found in *tail. Return NULL if the path is bogus, or if
* tail==NULL and we couldn't parse the whole name. (*tail)[0] == '@'
* means that the last component is a snapshot.
*/
{
}
int
{
int err;
}
}
dprintf("dataset_create: zap_add %s->%lld to %lld returned %d\n",
return (0);
}
int
{
int t, err;
if (err)
goto out;
goto out;
}
for (t = 0; t < TXG_SIZE; t++) {
/*
* if they were dirty, they'd also be open.
* dp_config_rwlock ensures that it stays that way.
*/
}
if (child_zapobj != 0) {
if (count != 0)
goto out;
}
if (err)
goto out;
}
/* The point of no (unsuccessful) return */
/* Make sure parent's used gets updated */
val = 0;
if (child_zapobj)
if (props_zapobj)
out:
if (dd)
return (err);
}
void
{
int error;
}
void
{
}
sizeof (dds->dds_altroot));
}
int
{
int err = 0;
/*
* They can get their space from either this dd, or the
* root dd.
*/
continue;
}
if (err) {
return (err);
}
if (dd->dd_sync_txg != 0) {
txg_wait_synced(dp, 0);
goto again;
}
/* We're good to go */
dd->dd_sync_txg = 0;
return (err);
}
void
{
/* up the hold count until we can be written out */
}
}
static int64_t
{
return (new_accounted - old_accounted);
}
void
{
}
/* release the hold from dsl_dir_dirty */
}
static uint64_t
{
int i;
for (i = 0; i < TXG_SIZE; i++) {
}
return (space);
}
/*
* How much space would dd have available if ancestor had delta applied
* to it? If ondiskonly is set, we're only interested in what's
* on-disk, not estimated pending changes.
*/
static uint64_t
{
/*
* If there are no restrictions otherwise, assume we have
* unlimited space available.
*/
quota = UINT64_MAX;
}
if (ondiskonly) {
} else {
}
}
/*
* We have some space reserved, in addition to what our
* parent gave us.
*/
}
/* over quota */
myspace = 0;
#ifdef ZFS_DEBUG
{
/*
* While it's OK to be a little over quota, if
* we think we are using more space than there
* is in the pool (which is already 6% more than
* dsl_pool_adjustedsize()), something is very
* wrong.
*/
}
#endif
} else {
/*
* the lesser of parent's space and the space
* left in our quota
*/
}
return (myspace);
}
struct tempreserve {
};
/*
* Reserve space in this dsl_dir, to be used in this tx's txg.
* After the space has been dirtied (and thus
* dsl_dir_willuse_space() has been called), the reservation should
* be canceled, using dsl_dir_tempreserve_clear().
*/
static int
{
int i;
struct tempreserve *tr;
/*
* Check against the dsl_dir's quota. We don't add in the delta
* when checking for over-quota because they get one free hit.
*/
for (i = 0; i < TXG_SIZE; i++)
quota = UINT64_MAX;
/*
* If this transaction will result in a net free of space, we want
* to let it through, but we have to be careful: the space that it
* frees won't become available until *after* this txg syncs.
* Therefore, to ensure that it's possible to remove files from
* a full pool without inducing transient overcommits, we throttle
* netfree transactions against a quota that is slightly larger,
* but still within the pool's allocation slop. In cases where
* we're very close to full, this will allow a steady trickle of
* removes to get through.
*/
}
} else if (netfree) {
quota = UINT64_MAX;
}
/*
* If they are requesting more space, and our current estimate
* is over quota. They get to try again unless the actual
* on-disk is over quota.
*/
"quota=%lluK tr=%lluK err=%d\n",
return (edquot);
}
/* We need to up our estimated delta before dropping dd_lock */
/* see if it's OK with our parent */
} else {
return (0);
}
}
/*
* Reserve space in this dsl_dir, to be used in this tx's txg.
* After the space has been dirtied (and thus
* dsl_dir_willuse_space() has been called), the reservation should
* be canceled, using dsl_dir_tempreserve_clear().
*/
int
{
int err = 0;
if (err == 0) {
struct tempreserve *tr;
if (err == 0) {
}
}
if (err)
else
*tr_cookiep = tr_list;
return (err);
}
/*
* Clear a temporary reservation that we previously made with
* dsl_dir_tempreserve_space().
*/
void
{
struct tempreserve *tr;
} else {
}
}
}
/*
* eg. when dirtying data. Be conservative (ie. OK to write less than
* this or free more than this, but don't write more or free less).
*/
void
{
if (space > 0)
/* Make sure that we clean up dd_space_to* */
/* XXX this is potentially expensive and unnecessary... */
}
void
{
ASSERT(compressed >= 0 ||
ASSERT(uncompressed >= 0 ||
if (used > 0)
}
}
static int
{
int err = 0;
} else {
}
return (err);
}
int
{
int err;
return (ENOENT);
/*
* If someone removes a file, then tries to set the quota, we
* want to make sure the file freeing takes effect.
*/
return (err);
}
static int
{
if (new_reservation > INT64_MAX)
return (EOVERFLOW);
} else {
}
return (ENOSPC);
return (ENOSPC);
/* Roll up this additional usage into our ancestors */
}
return (0);
}
int
{
int err;
return (ENOENT);
return (err);
}
static dsl_dir_t *
{
return (dd);
}
}
return (NULL);
}
/*
* If delta is applied to dd, how much of that delta would be applied to
* ancestor? Syncing context only.
*/
static int64_t
{
return (delta);
}
int
{
const char *tail;
/* can't rename to different pool */
return (ENXIO);
}
/* new parent should exist */
return (ENOENT);
/* new name should not already exist */
return (EEXIST);
}
/* There should be 2 references: the open and the dirty */
return (EBUSY);
}
/* no rename into our descendent */
return (EINVAL);
}
return (ENOSPC);
}
/* The point of no (unsuccessful) return */
}
/* The point of no (unsuccessful) return */
/* remove from old parent zapobj */
/* add to new parent zapobj */
return (0);
}