Mercurial > illumos > illumos-gate
diff usr/src/uts/common/fs/zfs/dsl_dataset.c @ 5481:1364fb7de75d
6619182 new non-sparse zvols should get refreservations
6623412 clone swap needs to check for enough space due to refreservation
6627460 Setting quota to itself should be a successful noop
author | ck153898 |
---|---|
date | Wed, 14 Nov 2007 12:28:57 -0800 |
parents | e140313199cc |
children | 85721e07d1fa |
line wrap: on
line diff
--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c Wed Nov 14 08:38:43 2007 -0800 +++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c Wed Nov 14 12:28:57 2007 -0800 @@ -2336,6 +2336,7 @@ dsl_dataset_t *cds; /* clone dataset */ dsl_dataset_t *ohds; /* origin's head dataset */ boolean_t force; + int64_t unused_refres_delta; /* change in unconsumed refreservation */ }; /* ARGSUSED */ @@ -2344,9 +2345,6 @@ { struct cloneswaparg *csa = arg1; - if (csa->ohds->ds_reserved != 0) - return (EINVAL); - /* they should both be heads */ if (dsl_dataset_is_snapshot(csa->cds) || dsl_dataset_is_snapshot(csa->ohds)) @@ -2368,6 +2366,19 @@ /* ohds shouldn't be modified unless 'force' */ if (!csa->force && dsl_dataset_modified_since_lastsnap(csa->ohds)) return (ETXTBSY); + + /* adjust amount of any unconsumed refreservation */ + csa->unused_refres_delta = + (int64_t)MIN(csa->ohds->ds_reserved, + csa->ohds->ds_phys->ds_unique_bytes) - + (int64_t)MIN(csa->ohds->ds_reserved, + csa->cds->ds_phys->ds_unique_bytes); + + if (csa->unused_refres_delta > 0 && + csa->unused_refres_delta > + dsl_dir_space_available(csa->ohds->ds_dir, NULL, 0, TRUE)) + return (ENOSPC); + return (0); } @@ -2382,6 +2393,9 @@ uint64_t unique = 0; int err; + ASSERT(csa->cds->ds_reserved == 0); + ASSERT(csa->cds->ds_quota == csa->ohds->ds_quota); + dmu_buf_will_dirty(csa->cds->ds_dbuf, tx); dmu_buf_will_dirty(csa->ohds->ds_dbuf, tx); dmu_buf_will_dirty(csa->cds->ds_prev->ds_dbuf, tx); @@ -2405,13 +2419,6 @@ } VERIFY(err == ENOENT); - /* undo any accounting due to a refreservation */ - if (csa->ohds->ds_reserved > csa->ohds->ds_phys->ds_unique_bytes) { - dsl_dir_diduse_space(csa->ohds->ds_dir, - csa->ohds->ds_phys->ds_unique_bytes - - csa->ohds->ds_reserved, 0, 0, tx); - } - /* reset origin's unique bytes */ csa->cds->ds_prev->ds_phys->ds_unique_bytes = unique; @@ -2454,13 +2461,6 @@ (y) = __tmp; \ } - /* redo any accounting due to a refreservation */ - if (csa->ohds->ds_reserved > csa->ohds->ds_phys->ds_unique_bytes) { - dsl_dir_diduse_space(csa->ohds->ds_dir, - csa->ohds->ds_reserved - - csa->ohds->ds_phys->ds_unique_bytes, 0, 0, tx); - } - /* swap ds_*_bytes */ SWITCH64(csa->ohds->ds_phys->ds_used_bytes, csa->cds->ds_phys->ds_used_bytes); @@ -2468,6 +2468,12 @@ csa->cds->ds_phys->ds_compressed_bytes); SWITCH64(csa->ohds->ds_phys->ds_uncompressed_bytes, csa->cds->ds_phys->ds_uncompressed_bytes); + SWITCH64(csa->ohds->ds_phys->ds_unique_bytes, + csa->cds->ds_phys->ds_unique_bytes); + + /* apply any parent delta for change in unconsumed refreservation */ + dsl_dir_diduse_space(csa->ohds->ds_dir, csa->unused_refres_delta, + 0, 0, tx); /* swap deadlists */ bplist_close(&csa->cds->ds_deadlist); @@ -2478,13 +2484,10 @@ csa->cds->ds_phys->ds_deadlist_obj)); VERIFY(0 == bplist_open(&csa->ohds->ds_deadlist, dp->dp_meta_objset, csa->ohds->ds_phys->ds_deadlist_obj)); - /* fix up clone's unique */ - dsl_dataset_recalc_head_uniq(csa->cds); - } /* - * Swap the clone "cosname" with its origin head file system. + * Swap 'clone' with its origin head file system. */ int dsl_dataset_clone_swap(dsl_dataset_t *clone, dsl_dataset_t *origin_head, @@ -2624,14 +2627,17 @@ if (err) return (err); - /* - * If someone removes a file, then tries to set the quota, we - * want to make sure the file freeing takes effect. - */ - txg_wait_open(ds->ds_dir->dd_pool, 0); - - err = dsl_sync_task_do(ds->ds_dir->dd_pool, dsl_dataset_set_quota_check, - dsl_dataset_set_quota_sync, ds, "a, 0); + if (quota != ds->ds_quota) { + /* + * If someone removes a file, then tries to set the quota, we + * want to make sure the file freeing takes effect. + */ + txg_wait_open(ds->ds_dir->dd_pool, 0); + + err = dsl_sync_task_do(ds->ds_dir->dd_pool, + dsl_dataset_set_quota_check, dsl_dataset_set_quota_sync, + ds, "a, 0); + } dsl_dataset_close(ds, DS_MODE_STANDARD, FTAG); return (err); }