Changeset View
Changeset View
Standalone View
Standalone View
sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
Show First 20 Lines • Show All 1,554 Lines • ▼ Show 20 Lines | if (suspended != NULL) { | ||||
for (pair = nvlist_next_nvpair(suspended, NULL); pair != NULL; | for (pair = nvlist_next_nvpair(suspended, NULL); pair != NULL; | ||||
pair = nvlist_next_nvpair(suspended, pair)) { | pair = nvlist_next_nvpair(suspended, pair)) { | ||||
zil_resume((void *)(uintptr_t) | zil_resume((void *)(uintptr_t) | ||||
fnvpair_value_uint64(pair)); | fnvpair_value_uint64(pair)); | ||||
} | } | ||||
fnvlist_free(suspended); | fnvlist_free(suspended); | ||||
} | } | ||||
#ifdef __FreeBSD__ | |||||
#ifdef _KERNEL | |||||
if (error == 0) { | |||||
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; | |||||
pair = nvlist_next_nvpair(snaps, pair)) { | |||||
char *snapname = nvpair_name(pair); | |||||
zvol_create_minors(snapname); | |||||
} | |||||
} | |||||
#endif | |||||
#endif | |||||
return (error); | return (error); | ||||
} | } | ||||
typedef struct dsl_dataset_snapshot_tmp_arg { | typedef struct dsl_dataset_snapshot_tmp_arg { | ||||
const char *ddsta_fsname; | const char *ddsta_fsname; | ||||
const char *ddsta_snapname; | const char *ddsta_snapname; | ||||
minor_t ddsta_cleanup_minor; | minor_t ddsta_cleanup_minor; | ||||
const char *ddsta_htag; | const char *ddsta_htag; | ||||
▲ Show 20 Lines • Show All 425 Lines • ▼ Show 20 Lines | dsl_dataset_modified_since_snap(dsl_dataset_t *ds, dsl_dataset_t *snap) | ||||
return (B_FALSE); | return (B_FALSE); | ||||
} | } | ||||
typedef struct dsl_dataset_rename_snapshot_arg { | typedef struct dsl_dataset_rename_snapshot_arg { | ||||
const char *ddrsa_fsname; | const char *ddrsa_fsname; | ||||
const char *ddrsa_oldsnapname; | const char *ddrsa_oldsnapname; | ||||
const char *ddrsa_newsnapname; | const char *ddrsa_newsnapname; | ||||
boolean_t ddrsa_recursive; | boolean_t ddrsa_recursive; | ||||
nvlist_t *ddrsa_renamed; | |||||
dmu_tx_t *ddrsa_tx; | dmu_tx_t *ddrsa_tx; | ||||
} dsl_dataset_rename_snapshot_arg_t; | } dsl_dataset_rename_snapshot_arg_t; | ||||
/* ARGSUSED */ | /* ARGSUSED */ | ||||
static int | static int | ||||
dsl_dataset_rename_snapshot_check_impl(dsl_pool_t *dp, | dsl_dataset_rename_snapshot_check_impl(dsl_pool_t *dp, | ||||
dsl_dataset_t *hds, void *arg) | dsl_dataset_t *hds, void *arg) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | dsl_dataset_rename_snapshot_check(void *arg, dmu_tx_t *tx) | ||||
dsl_dataset_rele(hds, FTAG); | dsl_dataset_rele(hds, FTAG); | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp, | dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp, | ||||
dsl_dataset_t *hds, void *arg) | dsl_dataset_t *hds, void *arg) | ||||
{ | { | ||||
#ifdef __FreeBSD__ | char namebuf[ZFS_MAXNAMELEN]; | ||||
#ifdef _KERNEL | |||||
char *oldname, *newname; | |||||
#endif | |||||
#endif | |||||
dsl_dataset_rename_snapshot_arg_t *ddrsa = arg; | dsl_dataset_rename_snapshot_arg_t *ddrsa = arg; | ||||
dsl_dataset_t *ds; | dsl_dataset_t *ds; | ||||
uint64_t val; | uint64_t val; | ||||
dmu_tx_t *tx = ddrsa->ddrsa_tx; | dmu_tx_t *tx = ddrsa->ddrsa_tx; | ||||
int error; | int error; | ||||
error = dsl_dataset_snap_lookup(hds, ddrsa->ddrsa_oldsnapname, &val); | error = dsl_dataset_snap_lookup(hds, ddrsa->ddrsa_oldsnapname, &val); | ||||
ASSERT(error == 0 || error == ENOENT); | ASSERT(error == 0 || error == ENOENT); | ||||
Show All 11 Lines | dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp, | ||||
VERIFY0(dsl_dataset_snap_remove(hds, ddrsa->ddrsa_oldsnapname, tx, | VERIFY0(dsl_dataset_snap_remove(hds, ddrsa->ddrsa_oldsnapname, tx, | ||||
B_FALSE)); | B_FALSE)); | ||||
mutex_enter(&ds->ds_lock); | mutex_enter(&ds->ds_lock); | ||||
(void) strcpy(ds->ds_snapname, ddrsa->ddrsa_newsnapname); | (void) strcpy(ds->ds_snapname, ddrsa->ddrsa_newsnapname); | ||||
mutex_exit(&ds->ds_lock); | mutex_exit(&ds->ds_lock); | ||||
VERIFY0(zap_add(dp->dp_meta_objset, | VERIFY0(zap_add(dp->dp_meta_objset, | ||||
dsl_dataset_phys(hds)->ds_snapnames_zapobj, | dsl_dataset_phys(hds)->ds_snapnames_zapobj, | ||||
ds->ds_snapname, 8, 1, &ds->ds_object, tx)); | ds->ds_snapname, 8, 1, &ds->ds_object, tx)); | ||||
#ifdef __FreeBSD__ | |||||
#ifdef _KERNEL | |||||
oldname = kmem_alloc(MAXPATHLEN, KM_SLEEP); | |||||
newname = kmem_alloc(MAXPATHLEN, KM_SLEEP); | |||||
snprintf(oldname, MAXPATHLEN, "%s@%s", ddrsa->ddrsa_fsname, | |||||
ddrsa->ddrsa_oldsnapname); | |||||
snprintf(newname, MAXPATHLEN, "%s@%s", ddrsa->ddrsa_fsname, | |||||
ddrsa->ddrsa_newsnapname); | |||||
zfsvfs_update_fromname(oldname, newname); | |||||
zvol_rename_minors(oldname, newname); | |||||
kmem_free(newname, MAXPATHLEN); | |||||
kmem_free(oldname, MAXPATHLEN); | |||||
#endif | |||||
#endif | |||||
dsl_dataset_rele(ds, FTAG); | dsl_dataset_rele(ds, FTAG); | ||||
if (ddrsa->ddrsa_renamed != NULL) { | |||||
dsl_dataset_name(hds, namebuf); | |||||
fnvlist_add_boolean(ddrsa->ddrsa_renamed, namebuf); | |||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
dsl_dataset_rename_snapshot_sync(void *arg, dmu_tx_t *tx) | dsl_dataset_rename_snapshot_sync(void *arg, dmu_tx_t *tx) | ||||
{ | { | ||||
dsl_dataset_rename_snapshot_arg_t *ddrsa = arg; | dsl_dataset_rename_snapshot_arg_t *ddrsa = arg; | ||||
dsl_pool_t *dp = dmu_tx_pool(tx); | dsl_pool_t *dp = dmu_tx_pool(tx); | ||||
dsl_dataset_t *hds; | dsl_dataset_t *hds; | ||||
VERIFY0(dsl_dataset_hold(dp, ddrsa->ddrsa_fsname, FTAG, &hds)); | VERIFY0(dsl_dataset_hold(dp, ddrsa->ddrsa_fsname, FTAG, &hds)); | ||||
ddrsa->ddrsa_tx = tx; | ddrsa->ddrsa_tx = tx; | ||||
if (ddrsa->ddrsa_recursive) { | if (ddrsa->ddrsa_recursive) { | ||||
VERIFY0(dmu_objset_find_dp(dp, hds->ds_dir->dd_object, | VERIFY0(dmu_objset_find_dp(dp, hds->ds_dir->dd_object, | ||||
dsl_dataset_rename_snapshot_sync_impl, ddrsa, | dsl_dataset_rename_snapshot_sync_impl, ddrsa, | ||||
DS_FIND_CHILDREN)); | DS_FIND_CHILDREN)); | ||||
} else { | } else { | ||||
VERIFY0(dsl_dataset_rename_snapshot_sync_impl(dp, hds, ddrsa)); | VERIFY0(dsl_dataset_rename_snapshot_sync_impl(dp, hds, ddrsa)); | ||||
} | } | ||||
dsl_dataset_rele(hds, FTAG); | dsl_dataset_rele(hds, FTAG); | ||||
} | } | ||||
int | int | ||||
dsl_dataset_rename_snapshot(const char *fsname, | dsl_dataset_rename_snapshot(const char *fsname, | ||||
const char *oldsnapname, const char *newsnapname, boolean_t recursive) | const char *oldsnapname, const char *newsnapname, boolean_t recursive, | ||||
nvlist_t *renamed) | |||||
{ | { | ||||
dsl_dataset_rename_snapshot_arg_t ddrsa; | dsl_dataset_rename_snapshot_arg_t ddrsa; | ||||
ddrsa.ddrsa_fsname = fsname; | ddrsa.ddrsa_fsname = fsname; | ||||
ddrsa.ddrsa_oldsnapname = oldsnapname; | ddrsa.ddrsa_oldsnapname = oldsnapname; | ||||
ddrsa.ddrsa_newsnapname = newsnapname; | ddrsa.ddrsa_newsnapname = newsnapname; | ||||
ddrsa.ddrsa_recursive = recursive; | ddrsa.ddrsa_recursive = recursive; | ||||
ddrsa.ddrsa_renamed = renamed; | |||||
return (dsl_sync_task(fsname, dsl_dataset_rename_snapshot_check, | return (dsl_sync_task(fsname, dsl_dataset_rename_snapshot_check, | ||||
dsl_dataset_rename_snapshot_sync, &ddrsa, | dsl_dataset_rename_snapshot_sync, &ddrsa, | ||||
1, ZFS_SPACE_CHECK_RESERVED)); | 1, ZFS_SPACE_CHECK_RESERVED)); | ||||
} | } | ||||
/* | /* | ||||
* If we're doing an ownership handoff, we need to make sure that there is | * If we're doing an ownership handoff, we need to make sure that there is | ||||
▲ Show 20 Lines • Show All 173 Lines • ▼ Show 20 Lines | |||||
struct promotenode { | struct promotenode { | ||||
list_node_t link; | list_node_t link; | ||||
dsl_dataset_t *ds; | dsl_dataset_t *ds; | ||||
}; | }; | ||||
typedef struct dsl_dataset_promote_arg { | typedef struct dsl_dataset_promote_arg { | ||||
const char *ddpa_clonename; | const char *ddpa_clonename; | ||||
nvlist_t *ddpa_moved; | |||||
dsl_dataset_t *ddpa_clone; | dsl_dataset_t *ddpa_clone; | ||||
list_t shared_snaps, origin_snaps, clone_snaps; | list_t shared_snaps, origin_snaps, clone_snaps; | ||||
dsl_dataset_t *origin_origin; /* origin of the origin */ | dsl_dataset_t *origin_origin; /* origin of the origin */ | ||||
uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap; | uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap; | ||||
char *err_ds; | char *err_ds; | ||||
cred_t *cr; | cred_t *cr; | ||||
} dsl_dataset_promote_arg_t; | } dsl_dataset_promote_arg_t; | ||||
▲ Show 20 Lines • Show All 178 Lines • ▼ Show 20 Lines | dsl_dataset_promote_sync(void *arg, dmu_tx_t *tx) | ||||
dsl_dataset_t *hds; | dsl_dataset_t *hds; | ||||
struct promotenode *snap; | struct promotenode *snap; | ||||
dsl_dataset_t *origin_ds; | dsl_dataset_t *origin_ds; | ||||
dsl_dataset_t *origin_head; | dsl_dataset_t *origin_head; | ||||
dsl_dir_t *dd; | dsl_dir_t *dd; | ||||
dsl_dir_t *odd = NULL; | dsl_dir_t *odd = NULL; | ||||
uint64_t oldnext_obj; | uint64_t oldnext_obj; | ||||
int64_t delta; | int64_t delta; | ||||
#if defined(__FreeBSD__) && defined(_KERNEL) | |||||
char *oldname, *newname; | |||||
#endif | |||||
VERIFY0(promote_hold(ddpa, dp, FTAG)); | VERIFY0(promote_hold(ddpa, dp, FTAG)); | ||||
hds = ddpa->ddpa_clone; | hds = ddpa->ddpa_clone; | ||||
ASSERT0(dsl_dataset_phys(hds)->ds_flags & DS_FLAG_NOPROMOTE); | ASSERT0(dsl_dataset_phys(hds)->ds_flags & DS_FLAG_NOPROMOTE); | ||||
snap = list_head(&ddpa->shared_snaps); | snap = list_head(&ddpa->shared_snaps); | ||||
origin_ds = snap->ds; | origin_ds = snap->ds; | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | if (dsl_dir_phys(dd)->dd_clones == 0) { | ||||
dsl_dir_phys(dd)->dd_clones = | dsl_dir_phys(dd)->dd_clones = | ||||
zap_create(dp->dp_meta_objset, DMU_OT_DSL_CLONES, | zap_create(dp->dp_meta_objset, DMU_OT_DSL_CLONES, | ||||
DMU_OT_NONE, 0, tx); | DMU_OT_NONE, 0, tx); | ||||
} | } | ||||
VERIFY0(zap_add_int(dp->dp_meta_objset, | VERIFY0(zap_add_int(dp->dp_meta_objset, | ||||
dsl_dir_phys(dd)->dd_clones, origin_head->ds_object, tx)); | dsl_dir_phys(dd)->dd_clones, origin_head->ds_object, tx)); | ||||
} | } | ||||
#if defined(__FreeBSD__) && defined(_KERNEL) | |||||
/* Take the spa_namespace_lock early so zvol renames don't deadlock. */ | |||||
mutex_enter(&spa_namespace_lock); | |||||
oldname = kmem_alloc(MAXPATHLEN, KM_SLEEP); | |||||
newname = kmem_alloc(MAXPATHLEN, KM_SLEEP); | |||||
#endif | |||||
/* move snapshots to this dir */ | /* move snapshots to this dir */ | ||||
for (snap = list_head(&ddpa->shared_snaps); snap; | for (snap = list_head(&ddpa->shared_snaps); snap; | ||||
snap = list_next(&ddpa->shared_snaps, snap)) { | snap = list_next(&ddpa->shared_snaps, snap)) { | ||||
dsl_dataset_t *ds = snap->ds; | dsl_dataset_t *ds = snap->ds; | ||||
/* | /* | ||||
* Property callbacks are registered to a particular | * Property callbacks are registered to a particular | ||||
* dsl_dir. Since ours is changing, evict the objset | * dsl_dir. Since ours is changing, evict the objset | ||||
Show All 9 Lines | for (snap = list_head(&ddpa->shared_snaps); snap; | ||||
VERIFY0(dsl_dataset_snap_remove(origin_head, | VERIFY0(dsl_dataset_snap_remove(origin_head, | ||||
ds->ds_snapname, tx, B_TRUE)); | ds->ds_snapname, tx, B_TRUE)); | ||||
VERIFY0(zap_add(dp->dp_meta_objset, | VERIFY0(zap_add(dp->dp_meta_objset, | ||||
dsl_dataset_phys(hds)->ds_snapnames_zapobj, ds->ds_snapname, | dsl_dataset_phys(hds)->ds_snapnames_zapobj, ds->ds_snapname, | ||||
8, 1, &ds->ds_object, tx)); | 8, 1, &ds->ds_object, tx)); | ||||
dsl_fs_ss_count_adjust(hds->ds_dir, 1, | dsl_fs_ss_count_adjust(hds->ds_dir, 1, | ||||
DD_FIELD_SNAPSHOT_COUNT, tx); | DD_FIELD_SNAPSHOT_COUNT, tx); | ||||
if (ddpa->ddpa_moved != NULL) | |||||
fnvlist_add_boolean(ddpa->ddpa_moved, ds->ds_snapname); | |||||
/* change containing dsl_dir */ | /* change containing dsl_dir */ | ||||
dmu_buf_will_dirty(ds->ds_dbuf, tx); | dmu_buf_will_dirty(ds->ds_dbuf, tx); | ||||
ASSERT3U(dsl_dataset_phys(ds)->ds_dir_obj, ==, odd->dd_object); | ASSERT3U(dsl_dataset_phys(ds)->ds_dir_obj, ==, odd->dd_object); | ||||
dsl_dataset_phys(ds)->ds_dir_obj = dd->dd_object; | dsl_dataset_phys(ds)->ds_dir_obj = dd->dd_object; | ||||
ASSERT3P(ds->ds_dir, ==, odd); | ASSERT3P(ds->ds_dir, ==, odd); | ||||
dsl_dir_rele(ds->ds_dir, ds); | dsl_dir_rele(ds->ds_dir, ds); | ||||
VERIFY0(dsl_dir_hold_obj(dp, dd->dd_object, | VERIFY0(dsl_dir_hold_obj(dp, dd->dd_object, | ||||
NULL, ds, &ds->ds_dir)); | NULL, ds, &ds->ds_dir)); | ||||
#if defined(__FreeBSD__) && defined(_KERNEL) | |||||
dsl_dataset_name(ds, newname); | |||||
zfsvfs_update_fromname(oldname, newname); | |||||
zvol_rename_minors(oldname, newname); | |||||
#endif | |||||
/* move any clone references */ | /* move any clone references */ | ||||
if (dsl_dataset_phys(ds)->ds_next_clones_obj && | if (dsl_dataset_phys(ds)->ds_next_clones_obj && | ||||
spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { | spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { | ||||
zap_cursor_t zc; | zap_cursor_t zc; | ||||
zap_attribute_t za; | zap_attribute_t za; | ||||
for (zap_cursor_init(&zc, dp->dp_meta_objset, | for (zap_cursor_init(&zc, dp->dp_meta_objset, | ||||
dsl_dataset_phys(ds)->ds_next_clones_obj); | dsl_dataset_phys(ds)->ds_next_clones_obj); | ||||
Show All 22 Lines | if (dsl_dataset_phys(ds)->ds_next_clones_obj && | ||||
dsl_dataset_rele(cnds, FTAG); | dsl_dataset_rele(cnds, FTAG); | ||||
} | } | ||||
zap_cursor_fini(&zc); | zap_cursor_fini(&zc); | ||||
} | } | ||||
ASSERT(!dsl_prop_hascb(ds)); | ASSERT(!dsl_prop_hascb(ds)); | ||||
} | } | ||||
#if defined(__FreeBSD__) && defined(_KERNEL) | |||||
mutex_exit(&spa_namespace_lock); | |||||
kmem_free(newname, MAXPATHLEN); | |||||
kmem_free(oldname, MAXPATHLEN); | |||||
#endif | |||||
/* | /* | ||||
* Change space accounting. | * Change space accounting. | ||||
* Note, pa->*usedsnap and dd_used_breakdown[SNAP] will either | * Note, pa->*usedsnap and dd_used_breakdown[SNAP] will either | ||||
* both be valid, or both be 0 (resulting in delta == 0). This | * both be valid, or both be 0 (resulting in delta == 0). This | ||||
* is true for each of {clone,origin} independently. | * is true for each of {clone,origin} independently. | ||||
*/ | */ | ||||
delta = ddpa->cloneusedsnap - | delta = ddpa->cloneusedsnap - | ||||
▲ Show 20 Lines • Show All 152 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Promote a clone. | * Promote a clone. | ||||
* | * | ||||
* If it fails due to a conflicting snapshot name, "conflsnap" will be filled | * If it fails due to a conflicting snapshot name, "conflsnap" will be filled | ||||
* in with the name. (It must be at least MAXNAMELEN bytes long.) | * in with the name. (It must be at least MAXNAMELEN bytes long.) | ||||
*/ | */ | ||||
int | int | ||||
dsl_dataset_promote(const char *name, char *conflsnap) | dsl_dataset_promote(const char *name, char *conflsnap, nvlist_t *moved) | ||||
{ | { | ||||
dsl_dataset_promote_arg_t ddpa = { 0 }; | dsl_dataset_promote_arg_t ddpa = { 0 }; | ||||
uint64_t numsnaps; | uint64_t numsnaps; | ||||
int error; | int error; | ||||
objset_t *os; | objset_t *os; | ||||
/* | /* | ||||
* We will modify space proportional to the number of | * We will modify space proportional to the number of | ||||
* snapshots. Compute numsnaps. | * snapshots. Compute numsnaps. | ||||
*/ | */ | ||||
error = dmu_objset_hold(name, FTAG, &os); | error = dmu_objset_hold(name, FTAG, &os); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
error = zap_count(dmu_objset_pool(os)->dp_meta_objset, | error = zap_count(dmu_objset_pool(os)->dp_meta_objset, | ||||
dsl_dataset_phys(dmu_objset_ds(os))->ds_snapnames_zapobj, | dsl_dataset_phys(dmu_objset_ds(os))->ds_snapnames_zapobj, | ||||
&numsnaps); | &numsnaps); | ||||
dmu_objset_rele(os, FTAG); | dmu_objset_rele(os, FTAG); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
ddpa.ddpa_clonename = name; | ddpa.ddpa_clonename = name; | ||||
ddpa.ddpa_moved = moved; | |||||
ddpa.err_ds = conflsnap; | ddpa.err_ds = conflsnap; | ||||
ddpa.cr = CRED(); | ddpa.cr = CRED(); | ||||
return (dsl_sync_task(name, dsl_dataset_promote_check, | return (dsl_sync_task(name, dsl_dataset_promote_check, | ||||
dsl_dataset_promote_sync, &ddpa, | dsl_dataset_promote_sync, &ddpa, | ||||
2 + numsnaps, ZFS_SPACE_CHECK_RESERVED)); | 2 + numsnaps, ZFS_SPACE_CHECK_RESERVED)); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 744 Lines • Show Last 20 Lines |