dsl_dataset.c (226707) | dsl_dataset.c (228103) |
---|---|
1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE --- 9 unchanged lines hidden (view full) --- 18 * 19 * CDDL HEADER END 20 */ 21/* 22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright (c) 2011 by Delphix. All rights reserved. 24 * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>. 25 * All rights reserved. | 1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE --- 9 unchanged lines hidden (view full) --- 18 * 19 * CDDL HEADER END 20 */ 21/* 22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright (c) 2011 by Delphix. All rights reserved. 24 * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>. 25 * All rights reserved. |
26 * Portions Copyright 2011 Martin Matuska <mm@FreeBSd.org> |
|
26 */ 27 28#include <sys/dmu_objset.h> 29#include <sys/dsl_dataset.h> 30#include <sys/dsl_dir.h> 31#include <sys/dsl_prop.h> 32#include <sys/dsl_synctask.h> 33#include <sys/dmu_traverse.h> --- 869 unchanged lines hidden (view full) --- 903 bzero(&os->os_zil_header, sizeof (os->os_zil_header)); 904 dsl_dataset_dirty(ds, tx); 905 dsl_dataset_rele(ds, FTAG); 906 } 907 908 return (dsobj); 909} 910 | 27 */ 28 29#include <sys/dmu_objset.h> 30#include <sys/dsl_dataset.h> 31#include <sys/dsl_dir.h> 32#include <sys/dsl_prop.h> 33#include <sys/dsl_synctask.h> 34#include <sys/dmu_traverse.h> --- 869 unchanged lines hidden (view full) --- 904 bzero(&os->os_zil_header, sizeof (os->os_zil_header)); 905 dsl_dataset_dirty(ds, tx); 906 dsl_dataset_rele(ds, FTAG); 907 } 908 909 return (dsobj); 910} 911 |
912#ifdef __FreeBSD__ 913/* FreeBSD ioctl compat begin */ |
|
911struct destroyarg { | 914struct destroyarg { |
912 dsl_sync_task_group_t *dstg; 913 char *snapname; 914 char *failed; 915 boolean_t defer; | 915 nvlist_t *nvl; 916 const char *snapname; |
916}; 917 918static int | 917}; 918 919static int |
919dsl_snapshot_destroy_one(const char *name, void *arg) | 920dsl_check_snap_cb(const char *name, void *arg) |
920{ 921 struct destroyarg *da = arg; 922 dsl_dataset_t *ds; | 921{ 922 struct destroyarg *da = arg; 923 dsl_dataset_t *ds; |
923 int err; | |
924 char *dsname; 925 926 dsname = kmem_asprintf("%s@%s", name, da->snapname); | 924 char *dsname; 925 926 dsname = kmem_asprintf("%s@%s", name, da->snapname); |
927 err = dsl_dataset_own(dsname, B_TRUE, da->dstg, &ds); 928 strfree(dsname); 929 if (err == 0) { 930 struct dsl_ds_destroyarg *dsda; | 927 VERIFY(nvlist_add_boolean(da->nvl, dsname) == 0); |
931 | 928 |
932 dsl_dataset_make_exclusive(ds, da->dstg); 933 dsda = kmem_zalloc(sizeof (struct dsl_ds_destroyarg), KM_SLEEP); 934 dsda->ds = ds; 935 dsda->defer = da->defer; 936 dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check, 937 dsl_dataset_destroy_sync, dsda, da->dstg, 0); 938 } else if (err == ENOENT) { 939 err = 0; 940 } else { 941 (void) strcpy(da->failed, name); 942 } | 929 return (0); 930} 931 932int 933dmu_get_recursive_snaps_nvl(const char *fsname, const char *snapname, 934 nvlist_t *snaps) 935{ 936 struct destroyarg *da; 937 int err; 938 939 da = kmem_zalloc(sizeof (struct destroyarg), KM_SLEEP); 940 da->nvl = snaps; 941 da->snapname = snapname; 942 err = dmu_objset_find(fsname, dsl_check_snap_cb, da, 943 DS_FIND_CHILDREN); 944 kmem_free(da, sizeof (struct destroyarg)); 945 |
943 return (err); 944} | 946 return (err); 947} |
948/* FreeBSD ioctl compat end */ 949#endif /* __FreeBSD__ */ |
|
945 946/* | 950 951/* |
947 * Destroy 'snapname' in all descendants of 'fsname'. | 952 * The snapshots must all be in the same pool. |
948 */ | 953 */ |
949#pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy | |
950int | 954int |
951dsl_snapshots_destroy(char *fsname, char *snapname, boolean_t defer) | 955dmu_snapshots_destroy_nvl(nvlist_t *snaps, boolean_t defer, char *failed) |
952{ 953 int err; | 956{ 957 int err; |
954 struct destroyarg da; | |
955 dsl_sync_task_t *dst; 956 spa_t *spa; | 958 dsl_sync_task_t *dst; 959 spa_t *spa; |
960 nvpair_t *pair; 961 dsl_sync_task_group_t *dstg; |
|
957 | 962 |
958 err = spa_open(fsname, &spa, FTAG); | 963 pair = nvlist_next_nvpair(snaps, NULL); 964 if (pair == NULL) 965 return (0); 966 967 err = spa_open(nvpair_name(pair), &spa, FTAG); |
959 if (err) 960 return (err); | 968 if (err) 969 return (err); |
961 da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 962 da.snapname = snapname; 963 da.failed = fsname; 964 da.defer = defer; | 970 dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); |
965 | 971 |
966 err = dmu_objset_find(fsname, 967 dsl_snapshot_destroy_one, &da, DS_FIND_CHILDREN); | 972 for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; 973 pair = nvlist_next_nvpair(snaps, pair)) { 974 dsl_dataset_t *ds; 975 int err; |
968 | 976 |
977 err = dsl_dataset_own(nvpair_name(pair), B_TRUE, dstg, &ds); 978 if (err == 0) { 979 struct dsl_ds_destroyarg *dsda; 980 981 dsl_dataset_make_exclusive(ds, dstg); 982 dsda = kmem_zalloc(sizeof (struct dsl_ds_destroyarg), 983 KM_SLEEP); 984 dsda->ds = ds; 985 dsda->defer = defer; 986 dsl_sync_task_create(dstg, dsl_dataset_destroy_check, 987 dsl_dataset_destroy_sync, dsda, dstg, 0); 988 } else if (err == ENOENT) { 989 err = 0; 990 } else { 991 (void) strcpy(failed, nvpair_name(pair)); 992 break; 993 } 994 } 995 |
|
969 if (err == 0) | 996 if (err == 0) |
970 err = dsl_sync_task_group_wait(da.dstg); | 997 err = dsl_sync_task_group_wait(dstg); |
971 | 998 |
972 for (dst = list_head(&da.dstg->dstg_tasks); dst; 973 dst = list_next(&da.dstg->dstg_tasks, dst)) { | 999 for (dst = list_head(&dstg->dstg_tasks); dst; 1000 dst = list_next(&dstg->dstg_tasks, dst)) { |
974 struct dsl_ds_destroyarg *dsda = dst->dst_arg1; 975 dsl_dataset_t *ds = dsda->ds; 976 977 /* 978 * Return the file system name that triggered the error 979 */ 980 if (dst->dst_err) { | 1001 struct dsl_ds_destroyarg *dsda = dst->dst_arg1; 1002 dsl_dataset_t *ds = dsda->ds; 1003 1004 /* 1005 * Return the file system name that triggered the error 1006 */ 1007 if (dst->dst_err) { |
981 dsl_dataset_name(ds, fsname); 982 *strchr(fsname, '@') = '\0'; | 1008 dsl_dataset_name(ds, failed); |
983 } 984 ASSERT3P(dsda->rm_origin, ==, NULL); | 1009 } 1010 ASSERT3P(dsda->rm_origin, ==, NULL); |
985 dsl_dataset_disown(ds, da.dstg); | 1011 dsl_dataset_disown(ds, dstg); |
986 kmem_free(dsda, sizeof (struct dsl_ds_destroyarg)); 987 } 988 | 1012 kmem_free(dsda, sizeof (struct dsl_ds_destroyarg)); 1013 } 1014 |
989 dsl_sync_task_group_destroy(da.dstg); | 1015 dsl_sync_task_group_destroy(dstg); |
990 spa_close(spa, FTAG); 991 return (err); | 1016 spa_close(spa, FTAG); 1017 return (err); |
1018 |
|
992} 993 994static boolean_t 995dsl_dataset_might_destroy_origin(dsl_dataset_t *ds) 996{ 997 boolean_t might_destroy = B_FALSE; 998 999 mutex_enter(&ds->ds_lock); --- 1145 unchanged lines hidden (view full) --- 2145 */ 2146 dmu_buf_will_dirty(ds->ds_dbuf, tx); 2147 ds->ds_phys->ds_fsid_guid = ds->ds_fsid_guid; 2148 2149 dsl_dir_dirty(ds->ds_dir, tx); 2150 dmu_objset_sync(ds->ds_objset, zio, tx); 2151} 2152 | 1019} 1020 1021static boolean_t 1022dsl_dataset_might_destroy_origin(dsl_dataset_t *ds) 1023{ 1024 boolean_t might_destroy = B_FALSE; 1025 1026 mutex_enter(&ds->ds_lock); --- 1145 unchanged lines hidden (view full) --- 2172 */ 2173 dmu_buf_will_dirty(ds->ds_dbuf, tx); 2174 ds->ds_phys->ds_fsid_guid = ds->ds_fsid_guid; 2175 2176 dsl_dir_dirty(ds->ds_dir, tx); 2177 dmu_objset_sync(ds->ds_objset, zio, tx); 2178} 2179 |
2180static void 2181get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv) 2182{ 2183 uint64_t count = 0; 2184 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 2185 zap_cursor_t zc; 2186 zap_attribute_t za; 2187 nvlist_t *propval; 2188 nvlist_t *val; 2189 2190 rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 2191 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2192 VERIFY(nvlist_alloc(&val, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2193 2194 /* 2195 * There may me missing entries in ds_next_clones_obj 2196 * due to a bug in a previous version of the code. 2197 * Only trust it if it has the right number of entries. 2198 */ 2199 if (ds->ds_phys->ds_next_clones_obj != 0) { 2200 ASSERT3U(0, ==, zap_count(mos, ds->ds_phys->ds_next_clones_obj, 2201 &count)); 2202 } 2203 if (count != ds->ds_phys->ds_num_children - 1) { 2204 goto fail; 2205 } 2206 for (zap_cursor_init(&zc, mos, ds->ds_phys->ds_next_clones_obj); 2207 zap_cursor_retrieve(&zc, &za) == 0; 2208 zap_cursor_advance(&zc)) { 2209 dsl_dataset_t *clone; 2210 char buf[ZFS_MAXNAMELEN]; 2211 if (dsl_dataset_hold_obj(ds->ds_dir->dd_pool, 2212 za.za_first_integer, FTAG, &clone) != 0) { 2213 goto fail; 2214 } 2215 dsl_dir_name(clone->ds_dir, buf); 2216 VERIFY(nvlist_add_boolean(val, buf) == 0); 2217 dsl_dataset_rele(clone, FTAG); 2218 } 2219 zap_cursor_fini(&zc); 2220 VERIFY(nvlist_add_nvlist(propval, ZPROP_VALUE, val) == 0); 2221 VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(ZFS_PROP_CLONES), 2222 propval) == 0); 2223fail: 2224 nvlist_free(val); 2225 nvlist_free(propval); 2226 rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 2227} 2228 |
|
2153void 2154dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) 2155{ 2156 uint64_t refd, avail, uobjs, aobjs, ratio; 2157 2158 dsl_dir_stats(ds->ds_dir, nv); 2159 2160 dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs); --- 14 unchanged lines hidden (view full) --- 2175 ds->ds_phys->ds_unique_bytes); 2176 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_OBJSETID, 2177 ds->ds_object); 2178 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERREFS, 2179 ds->ds_userrefs); 2180 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY, 2181 DS_IS_DEFER_DESTROY(ds) ? 1 : 0); 2182 | 2229void 2230dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) 2231{ 2232 uint64_t refd, avail, uobjs, aobjs, ratio; 2233 2234 dsl_dir_stats(ds->ds_dir, nv); 2235 2236 dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs); --- 14 unchanged lines hidden (view full) --- 2251 ds->ds_phys->ds_unique_bytes); 2252 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_OBJSETID, 2253 ds->ds_object); 2254 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERREFS, 2255 ds->ds_userrefs); 2256 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY, 2257 DS_IS_DEFER_DESTROY(ds) ? 1 : 0); 2258 |
2259 if (ds->ds_phys->ds_prev_snap_obj != 0) { 2260 uint64_t written, comp, uncomp; 2261 dsl_pool_t *dp = ds->ds_dir->dd_pool; 2262 dsl_dataset_t *prev; 2263 2264 rw_enter(&dp->dp_config_rwlock, RW_READER); 2265 int err = dsl_dataset_hold_obj(dp, 2266 ds->ds_phys->ds_prev_snap_obj, FTAG, &prev); 2267 rw_exit(&dp->dp_config_rwlock); 2268 if (err == 0) { 2269 err = dsl_dataset_space_written(prev, ds, &written, 2270 &comp, &uncomp); 2271 dsl_dataset_rele(prev, FTAG); 2272 if (err == 0) { 2273 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_WRITTEN, 2274 written); 2275 } 2276 } 2277 } 2278 |
|
2183 ratio = ds->ds_phys->ds_compressed_bytes == 0 ? 100 : 2184 (ds->ds_phys->ds_uncompressed_bytes * 100 / 2185 ds->ds_phys->ds_compressed_bytes); 2186 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio); 2187 2188 if (ds->ds_phys->ds_next_snap_obj) { 2189 /* 2190 * This is a snapshot; override the dd's space used with 2191 * our unique space and compression ratio. 2192 */ 2193 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, 2194 ds->ds_phys->ds_unique_bytes); 2195 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio); | 2279 ratio = ds->ds_phys->ds_compressed_bytes == 0 ? 100 : 2280 (ds->ds_phys->ds_uncompressed_bytes * 100 / 2281 ds->ds_phys->ds_compressed_bytes); 2282 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio); 2283 2284 if (ds->ds_phys->ds_next_snap_obj) { 2285 /* 2286 * This is a snapshot; override the dd's space used with 2287 * our unique space and compression ratio. 2288 */ 2289 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, 2290 ds->ds_phys->ds_unique_bytes); 2291 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio); |
2292 2293 get_clones_stat(ds, nv); |
|
2196 } 2197} 2198 2199void 2200dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat) 2201{ 2202 stat->dds_creation_txg = ds->ds_phys->ds_creation_txg; 2203 stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT; --- 1816 unchanged lines hidden (view full) --- 4020 zap_cursor_fini(&zc); 4021 kmem_free(za, sizeof (zap_attribute_t)); 4022 } 4023 dsl_dataset_rele(ds, FTAG); 4024 return (0); 4025} 4026 4027/* | 2294 } 2295} 2296 2297void 2298dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat) 2299{ 2300 stat->dds_creation_txg = ds->ds_phys->ds_creation_txg; 2301 stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT; --- 1816 unchanged lines hidden (view full) --- 4118 zap_cursor_fini(&zc); 4119 kmem_free(za, sizeof (zap_attribute_t)); 4120 } 4121 dsl_dataset_rele(ds, FTAG); 4122 return (0); 4123} 4124 4125/* |
4028 * Note, this fuction is used as the callback for dmu_objset_find(). We | 4126 * Note, this function is used as the callback for dmu_objset_find(). We |
4029 * always return 0 so that we will continue to find and process 4030 * inconsistent datasets, even if we encounter an error trying to 4031 * process one of them. 4032 */ 4033/* ARGSUSED */ 4034int 4035dsl_destroy_inconsistent(const char *dsname, void *arg) 4036{ 4037 dsl_dataset_t *ds; 4038 4039 if (dsl_dataset_own(dsname, B_TRUE, FTAG, &ds) == 0) { 4040 if (DS_IS_INCONSISTENT(ds)) 4041 (void) dsl_dataset_destroy(ds, FTAG, B_FALSE); 4042 else 4043 dsl_dataset_disown(ds, FTAG); 4044 } 4045 return (0); 4046} | 4127 * always return 0 so that we will continue to find and process 4128 * inconsistent datasets, even if we encounter an error trying to 4129 * process one of them. 4130 */ 4131/* ARGSUSED */ 4132int 4133dsl_destroy_inconsistent(const char *dsname, void *arg) 4134{ 4135 dsl_dataset_t *ds; 4136 4137 if (dsl_dataset_own(dsname, B_TRUE, FTAG, &ds) == 0) { 4138 if (DS_IS_INCONSISTENT(ds)) 4139 (void) dsl_dataset_destroy(ds, FTAG, B_FALSE); 4140 else 4141 dsl_dataset_disown(ds, FTAG); 4142 } 4143 return (0); 4144} |
4145 4146/* 4147 * Return (in *usedp) the amount of space written in new that is not 4148 * present in oldsnap. New may be a snapshot or the head. Old must be 4149 * a snapshot before new, in new's filesystem (or its origin). If not then 4150 * fail and return EINVAL. 4151 * 4152 * The written space is calculated by considering two components: First, we 4153 * ignore any freed space, and calculate the written as new's used space 4154 * minus old's used space. Next, we add in the amount of space that was freed 4155 * between the two snapshots, thus reducing new's used space relative to old's. 4156 * Specifically, this is the space that was born before old->ds_creation_txg, 4157 * and freed before new (ie. on new's deadlist or a previous deadlist). 4158 * 4159 * space freed [---------------------] 4160 * snapshots ---O-------O--------O-------O------ 4161 * oldsnap new 4162 */ 4163int 4164dsl_dataset_space_written(dsl_dataset_t *oldsnap, dsl_dataset_t *new, 4165 uint64_t *usedp, uint64_t *compp, uint64_t *uncompp) 4166{ 4167 int err = 0; 4168 uint64_t snapobj; 4169 dsl_pool_t *dp = new->ds_dir->dd_pool; 4170 4171 *usedp = 0; 4172 *usedp += new->ds_phys->ds_used_bytes; 4173 *usedp -= oldsnap->ds_phys->ds_used_bytes; 4174 4175 *compp = 0; 4176 *compp += new->ds_phys->ds_compressed_bytes; 4177 *compp -= oldsnap->ds_phys->ds_compressed_bytes; 4178 4179 *uncompp = 0; 4180 *uncompp += new->ds_phys->ds_uncompressed_bytes; 4181 *uncompp -= oldsnap->ds_phys->ds_uncompressed_bytes; 4182 4183 rw_enter(&dp->dp_config_rwlock, RW_READER); 4184 snapobj = new->ds_object; 4185 while (snapobj != oldsnap->ds_object) { 4186 dsl_dataset_t *snap; 4187 uint64_t used, comp, uncomp; 4188 4189 err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &snap); 4190 if (err != 0) 4191 break; 4192 4193 if (snap->ds_phys->ds_prev_snap_txg == 4194 oldsnap->ds_phys->ds_creation_txg) { 4195 /* 4196 * The blocks in the deadlist can not be born after 4197 * ds_prev_snap_txg, so get the whole deadlist space, 4198 * which is more efficient (especially for old-format 4199 * deadlists). Unfortunately the deadlist code 4200 * doesn't have enough information to make this 4201 * optimization itself. 4202 */ 4203 dsl_deadlist_space(&snap->ds_deadlist, 4204 &used, &comp, &uncomp); 4205 } else { 4206 dsl_deadlist_space_range(&snap->ds_deadlist, 4207 0, oldsnap->ds_phys->ds_creation_txg, 4208 &used, &comp, &uncomp); 4209 } 4210 *usedp += used; 4211 *compp += comp; 4212 *uncompp += uncomp; 4213 4214 /* 4215 * If we get to the beginning of the chain of snapshots 4216 * (ds_prev_snap_obj == 0) before oldsnap, then oldsnap 4217 * was not a snapshot of/before new. 4218 */ 4219 snapobj = snap->ds_phys->ds_prev_snap_obj; 4220 dsl_dataset_rele(snap, FTAG); 4221 if (snapobj == 0) { 4222 err = EINVAL; 4223 break; 4224 } 4225 4226 } 4227 rw_exit(&dp->dp_config_rwlock); 4228 return (err); 4229} 4230 4231/* 4232 * Return (in *usedp) the amount of space that will be reclaimed if firstsnap, 4233 * lastsnap, and all snapshots in between are deleted. 4234 * 4235 * blocks that would be freed [---------------------------] 4236 * snapshots ---O-------O--------O-------O--------O 4237 * firstsnap lastsnap 4238 * 4239 * This is the set of blocks that were born after the snap before firstsnap, 4240 * (birth > firstsnap->prev_snap_txg) and died before the snap after the 4241 * last snap (ie, is on lastsnap->ds_next->ds_deadlist or an earlier deadlist). 4242 * We calculate this by iterating over the relevant deadlists (from the snap 4243 * after lastsnap, backward to the snap after firstsnap), summing up the 4244 * space on the deadlist that was born after the snap before firstsnap. 4245 */ 4246int 4247dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap, 4248 dsl_dataset_t *lastsnap, 4249 uint64_t *usedp, uint64_t *compp, uint64_t *uncompp) 4250{ 4251 int err = 0; 4252 uint64_t snapobj; 4253 dsl_pool_t *dp = firstsnap->ds_dir->dd_pool; 4254 4255 ASSERT(dsl_dataset_is_snapshot(firstsnap)); 4256 ASSERT(dsl_dataset_is_snapshot(lastsnap)); 4257 4258 /* 4259 * Check that the snapshots are in the same dsl_dir, and firstsnap 4260 * is before lastsnap. 4261 */ 4262 if (firstsnap->ds_dir != lastsnap->ds_dir || 4263 firstsnap->ds_phys->ds_creation_txg > 4264 lastsnap->ds_phys->ds_creation_txg) 4265 return (EINVAL); 4266 4267 *usedp = *compp = *uncompp = 0; 4268 4269 rw_enter(&dp->dp_config_rwlock, RW_READER); 4270 snapobj = lastsnap->ds_phys->ds_next_snap_obj; 4271 while (snapobj != firstsnap->ds_object) { 4272 dsl_dataset_t *ds; 4273 uint64_t used, comp, uncomp; 4274 4275 err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &ds); 4276 if (err != 0) 4277 break; 4278 4279 dsl_deadlist_space_range(&ds->ds_deadlist, 4280 firstsnap->ds_phys->ds_prev_snap_txg, UINT64_MAX, 4281 &used, &comp, &uncomp); 4282 *usedp += used; 4283 *compp += comp; 4284 *uncompp += uncomp; 4285 4286 snapobj = ds->ds_phys->ds_prev_snap_obj; 4287 ASSERT3U(snapobj, !=, 0); 4288 dsl_dataset_rele(ds, FTAG); 4289 } 4290 rw_exit(&dp->dp_config_rwlock); 4291 return (err); 4292} |
|