900 } |
900 } |
901 |
901 |
902 return (dsobj); |
902 return (dsobj); |
903 } |
903 } |
904 |
904 |
905 struct destroyarg { |
905 /* |
906 dsl_sync_task_group_t *dstg; |
906 * The snapshots must all be in the same pool. |
907 char *snapname; |
907 */ |
908 char *failed; |
908 int |
909 boolean_t defer; |
909 dmu_snapshots_destroy_nvl(nvlist_t *snaps, boolean_t defer, char *failed) |
910 }; |
910 { |
911 |
|
912 static int |
|
913 dsl_snapshot_destroy_one(const char *name, void *arg) |
|
914 { |
|
915 struct destroyarg *da = arg; |
|
916 dsl_dataset_t *ds; |
|
917 int err; |
911 int err; |
918 char *dsname; |
|
919 |
|
920 dsname = kmem_asprintf("%s@%s", name, da->snapname); |
|
921 err = dsl_dataset_own(dsname, B_TRUE, da->dstg, &ds); |
|
922 strfree(dsname); |
|
923 if (err == 0) { |
|
924 struct dsl_ds_destroyarg *dsda; |
|
925 |
|
926 dsl_dataset_make_exclusive(ds, da->dstg); |
|
927 dsda = kmem_zalloc(sizeof (struct dsl_ds_destroyarg), KM_SLEEP); |
|
928 dsda->ds = ds; |
|
929 dsda->defer = da->defer; |
|
930 dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check, |
|
931 dsl_dataset_destroy_sync, dsda, da->dstg, 0); |
|
932 } else if (err == ENOENT) { |
|
933 err = 0; |
|
934 } else { |
|
935 (void) strcpy(da->failed, name); |
|
936 } |
|
937 return (err); |
|
938 } |
|
939 |
|
940 /* |
|
941 * Destroy 'snapname' in all descendants of 'fsname'. |
|
942 */ |
|
943 #pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy |
|
944 int |
|
945 dsl_snapshots_destroy(char *fsname, char *snapname, boolean_t defer) |
|
946 { |
|
947 int err; |
|
948 struct destroyarg da; |
|
949 dsl_sync_task_t *dst; |
912 dsl_sync_task_t *dst; |
950 spa_t *spa; |
913 spa_t *spa; |
951 |
914 nvpair_t *pair; |
952 err = spa_open(fsname, &spa, FTAG); |
915 dsl_sync_task_group_t *dstg; |
|
916 |
|
917 pair = nvlist_next_nvpair(snaps, NULL); |
|
918 if (pair == NULL) |
|
919 return (0); |
|
920 |
|
921 err = spa_open(nvpair_name(pair), &spa, FTAG); |
953 if (err) |
922 if (err) |
954 return (err); |
923 return (err); |
955 da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); |
924 dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); |
956 da.snapname = snapname; |
925 |
957 da.failed = fsname; |
926 for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; |
958 da.defer = defer; |
927 pair = nvlist_next_nvpair(snaps, pair)) { |
959 |
928 dsl_dataset_t *ds; |
960 err = dmu_objset_find(fsname, |
929 int err; |
961 dsl_snapshot_destroy_one, &da, DS_FIND_CHILDREN); |
930 |
|
931 err = dsl_dataset_own(nvpair_name(pair), B_TRUE, dstg, &ds); |
|
932 if (err == 0) { |
|
933 struct dsl_ds_destroyarg *dsda; |
|
934 |
|
935 dsl_dataset_make_exclusive(ds, dstg); |
|
936 dsda = kmem_zalloc(sizeof (struct dsl_ds_destroyarg), |
|
937 KM_SLEEP); |
|
938 dsda->ds = ds; |
|
939 dsda->defer = defer; |
|
940 dsl_sync_task_create(dstg, dsl_dataset_destroy_check, |
|
941 dsl_dataset_destroy_sync, dsda, dstg, 0); |
|
942 } else if (err == ENOENT) { |
|
943 err = 0; |
|
944 } else { |
|
945 (void) strcpy(failed, nvpair_name(pair)); |
|
946 break; |
|
947 } |
|
948 } |
962 |
949 |
963 if (err == 0) |
950 if (err == 0) |
964 err = dsl_sync_task_group_wait(da.dstg); |
951 err = dsl_sync_task_group_wait(dstg); |
965 |
952 |
966 for (dst = list_head(&da.dstg->dstg_tasks); dst; |
953 for (dst = list_head(&dstg->dstg_tasks); dst; |
967 dst = list_next(&da.dstg->dstg_tasks, dst)) { |
954 dst = list_next(&dstg->dstg_tasks, dst)) { |
968 struct dsl_ds_destroyarg *dsda = dst->dst_arg1; |
955 struct dsl_ds_destroyarg *dsda = dst->dst_arg1; |
969 dsl_dataset_t *ds = dsda->ds; |
956 dsl_dataset_t *ds = dsda->ds; |
970 |
957 |
971 /* |
958 /* |
972 * Return the file system name that triggered the error |
959 * Return the file system name that triggered the error |
973 */ |
960 */ |
974 if (dst->dst_err) { |
961 if (dst->dst_err) { |
975 dsl_dataset_name(ds, fsname); |
962 dsl_dataset_name(ds, failed); |
976 *strchr(fsname, '@') = '\0'; |
|
977 } |
963 } |
978 ASSERT3P(dsda->rm_origin, ==, NULL); |
964 ASSERT3P(dsda->rm_origin, ==, NULL); |
979 dsl_dataset_disown(ds, da.dstg); |
965 dsl_dataset_disown(ds, dstg); |
980 kmem_free(dsda, sizeof (struct dsl_ds_destroyarg)); |
966 kmem_free(dsda, sizeof (struct dsl_ds_destroyarg)); |
981 } |
967 } |
982 |
968 |
983 dsl_sync_task_group_destroy(da.dstg); |
969 dsl_sync_task_group_destroy(dstg); |
984 spa_close(spa, FTAG); |
970 spa_close(spa, FTAG); |
985 return (err); |
971 return (err); |
|
972 |
986 } |
973 } |
987 |
974 |
988 static boolean_t |
975 static boolean_t |
989 dsl_dataset_might_destroy_origin(dsl_dataset_t *ds) |
976 dsl_dataset_might_destroy_origin(dsl_dataset_t *ds) |
990 { |
977 { |
2141 |
2128 |
2142 dsl_dir_dirty(ds->ds_dir, tx); |
2129 dsl_dir_dirty(ds->ds_dir, tx); |
2143 dmu_objset_sync(ds->ds_objset, zio, tx); |
2130 dmu_objset_sync(ds->ds_objset, zio, tx); |
2144 } |
2131 } |
2145 |
2132 |
|
2133 static void |
|
2134 get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv) |
|
2135 { |
|
2136 uint64_t count = 0; |
|
2137 objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; |
|
2138 zap_cursor_t zc; |
|
2139 zap_attribute_t za; |
|
2140 nvlist_t *propval; |
|
2141 nvlist_t *val; |
|
2142 |
|
2143 rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); |
|
2144 VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); |
|
2145 VERIFY(nvlist_alloc(&val, NV_UNIQUE_NAME, KM_SLEEP) == 0); |
|
2146 |
|
2147 /* |
|
2148 * There may me missing entries in ds_next_clones_obj |
|
2149 * due to a bug in a previous version of the code. |
|
2150 * Only trust it if it has the right number of entries. |
|
2151 */ |
|
2152 if (ds->ds_phys->ds_next_clones_obj != 0) { |
|
2153 ASSERT3U(0, ==, zap_count(mos, ds->ds_phys->ds_next_clones_obj, |
|
2154 &count)); |
|
2155 } |
|
2156 if (count != ds->ds_phys->ds_num_children - 1) { |
|
2157 goto fail; |
|
2158 } |
|
2159 for (zap_cursor_init(&zc, mos, ds->ds_phys->ds_next_clones_obj); |
|
2160 zap_cursor_retrieve(&zc, &za) == 0; |
|
2161 zap_cursor_advance(&zc)) { |
|
2162 dsl_dataset_t *clone; |
|
2163 char buf[ZFS_MAXNAMELEN]; |
|
2164 if (dsl_dataset_hold_obj(ds->ds_dir->dd_pool, |
|
2165 za.za_first_integer, FTAG, &clone) != 0) { |
|
2166 goto fail; |
|
2167 } |
|
2168 dsl_dir_name(clone->ds_dir, buf); |
|
2169 VERIFY(nvlist_add_boolean(val, buf) == 0); |
|
2170 dsl_dataset_rele(clone, FTAG); |
|
2171 } |
|
2172 zap_cursor_fini(&zc); |
|
2173 VERIFY(nvlist_add_nvlist(propval, ZPROP_VALUE, val) == 0); |
|
2174 VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(ZFS_PROP_CLONES), |
|
2175 propval) == 0); |
|
2176 fail: |
|
2177 nvlist_free(val); |
|
2178 nvlist_free(propval); |
|
2179 rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); |
|
2180 } |
|
2181 |
2146 void |
2182 void |
2147 dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) |
2183 dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) |
2148 { |
2184 { |
2149 uint64_t refd, avail, uobjs, aobjs, ratio; |
2185 uint64_t refd, avail, uobjs, aobjs, ratio; |
2150 |
2186 |
2171 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERREFS, |
2207 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERREFS, |
2172 ds->ds_userrefs); |
2208 ds->ds_userrefs); |
2173 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY, |
2209 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY, |
2174 DS_IS_DEFER_DESTROY(ds) ? 1 : 0); |
2210 DS_IS_DEFER_DESTROY(ds) ? 1 : 0); |
2175 |
2211 |
|
2212 if (ds->ds_phys->ds_prev_snap_obj != 0) { |
|
2213 uint64_t written, comp, uncomp; |
|
2214 dsl_pool_t *dp = ds->ds_dir->dd_pool; |
|
2215 dsl_dataset_t *prev; |
|
2216 |
|
2217 rw_enter(&dp->dp_config_rwlock, RW_READER); |
|
2218 int err = dsl_dataset_hold_obj(dp, |
|
2219 ds->ds_phys->ds_prev_snap_obj, FTAG, &prev); |
|
2220 rw_exit(&dp->dp_config_rwlock); |
|
2221 if (err == 0) { |
|
2222 err = dsl_dataset_space_written(prev, ds, &written, |
|
2223 &comp, &uncomp); |
|
2224 dsl_dataset_rele(prev, FTAG); |
|
2225 if (err == 0) { |
|
2226 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_WRITTEN, |
|
2227 written); |
|
2228 } |
|
2229 } |
|
2230 } |
|
2231 |
2176 ratio = ds->ds_phys->ds_compressed_bytes == 0 ? 100 : |
2232 ratio = ds->ds_phys->ds_compressed_bytes == 0 ? 100 : |
2177 (ds->ds_phys->ds_uncompressed_bytes * 100 / |
2233 (ds->ds_phys->ds_uncompressed_bytes * 100 / |
2178 ds->ds_phys->ds_compressed_bytes); |
2234 ds->ds_phys->ds_compressed_bytes); |
2179 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio); |
2235 dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio); |
2180 |
2236 |
4029 else |
4087 else |
4030 dsl_dataset_disown(ds, FTAG); |
4088 dsl_dataset_disown(ds, FTAG); |
4031 } |
4089 } |
4032 return (0); |
4090 return (0); |
4033 } |
4091 } |
|
4092 |
|
4093 /* |
|
4094 * Return (in *usedp) the amount of space written in new that is not |
|
4095 * present in oldsnap. New may be a snapshot or the head. Old must be |
|
4096 * a snapshot before new, in new's filesystem (or its origin). If not then |
|
4097 * fail and return EINVAL. |
|
4098 * |
|
4099 * The written space is calculated by considering two components: First, we |
|
4100 * ignore any freed space, and calculate the written as new's used space |
|
4101 * minus old's used space. Next, we add in the amount of space that was freed |
|
4102 * between the two snapshots, thus reducing new's used space relative to old's. |
|
4103 * Specifically, this is the space that was born before old->ds_creation_txg, |
|
4104 * and freed before new (ie. on new's deadlist or a previous deadlist). |
|
4105 * |
|
4106 * space freed [---------------------] |
|
4107 * snapshots ---O-------O--------O-------O------ |
|
4108 * oldsnap new |
|
4109 */ |
|
4110 int |
|
4111 dsl_dataset_space_written(dsl_dataset_t *oldsnap, dsl_dataset_t *new, |
|
4112 uint64_t *usedp, uint64_t *compp, uint64_t *uncompp) |
|
4113 { |
|
4114 int err = 0; |
|
4115 uint64_t snapobj; |
|
4116 dsl_pool_t *dp = new->ds_dir->dd_pool; |
|
4117 |
|
4118 *usedp = 0; |
|
4119 *usedp += new->ds_phys->ds_used_bytes; |
|
4120 *usedp -= oldsnap->ds_phys->ds_used_bytes; |
|
4121 |
|
4122 *compp = 0; |
|
4123 *compp += new->ds_phys->ds_compressed_bytes; |
|
4124 *compp -= oldsnap->ds_phys->ds_compressed_bytes; |
|
4125 |
|
4126 *uncompp = 0; |
|
4127 *uncompp += new->ds_phys->ds_uncompressed_bytes; |
|
4128 *uncompp -= oldsnap->ds_phys->ds_uncompressed_bytes; |
|
4129 |
|
4130 rw_enter(&dp->dp_config_rwlock, RW_READER); |
|
4131 snapobj = new->ds_object; |
|
4132 while (snapobj != oldsnap->ds_object) { |
|
4133 dsl_dataset_t *snap; |
|
4134 uint64_t used, comp, uncomp; |
|
4135 |
|
4136 err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &snap); |
|
4137 if (err != 0) |
|
4138 break; |
|
4139 |
|
4140 if (snap->ds_phys->ds_prev_snap_txg == |
|
4141 oldsnap->ds_phys->ds_creation_txg) { |
|
4142 /* |
|
4143 * The blocks in the deadlist can not be born after |
|
4144 * ds_prev_snap_txg, so get the whole deadlist space, |
|
4145 * which is more efficient (especially for old-format |
|
4146 * deadlists). Unfortunately the deadlist code |
|
4147 * doesn't have enough information to make this |
|
4148 * optimization itself. |
|
4149 */ |
|
4150 dsl_deadlist_space(&snap->ds_deadlist, |
|
4151 &used, &comp, &uncomp); |
|
4152 } else { |
|
4153 dsl_deadlist_space_range(&snap->ds_deadlist, |
|
4154 0, oldsnap->ds_phys->ds_creation_txg, |
|
4155 &used, &comp, &uncomp); |
|
4156 } |
|
4157 *usedp += used; |
|
4158 *compp += comp; |
|
4159 *uncompp += uncomp; |
|
4160 |
|
4161 /* |
|
4162 * If we get to the beginning of the chain of snapshots |
|
4163 * (ds_prev_snap_obj == 0) before oldsnap, then oldsnap |
|
4164 * was not a snapshot of/before new. |
|
4165 */ |
|
4166 snapobj = snap->ds_phys->ds_prev_snap_obj; |
|
4167 dsl_dataset_rele(snap, FTAG); |
|
4168 if (snapobj == 0) { |
|
4169 err = EINVAL; |
|
4170 break; |
|
4171 } |
|
4172 |
|
4173 } |
|
4174 rw_exit(&dp->dp_config_rwlock); |
|
4175 return (err); |
|
4176 } |
|
4177 |
|
4178 /* |
|
4179 * Return (in *usedp) the amount of space that will be reclaimed if firstsnap, |
|
4180 * lastsnap, and all snapshots in between are deleted. |
|
4181 * |
|
4182 * blocks that would be freed [---------------------------] |
|
4183 * snapshots ---O-------O--------O-------O--------O |
|
4184 * firstsnap lastsnap |
|
4185 * |
|
4186 * This is the set of blocks that were born after the snap before firstsnap, |
|
4187 * (birth > firstsnap->prev_snap_txg) and died before the snap after the |
|
4188 * last snap (ie, is on lastsnap->ds_next->ds_deadlist or an earlier deadlist). |
|
4189 * We calculate this by iterating over the relevant deadlists (from the snap |
|
4190 * after lastsnap, backward to the snap after firstsnap), summing up the |
|
4191 * space on the deadlist that was born after the snap before firstsnap. |
|
4192 */ |
|
4193 int |
|
4194 dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap, |
|
4195 dsl_dataset_t *lastsnap, |
|
4196 uint64_t *usedp, uint64_t *compp, uint64_t *uncompp) |
|
4197 { |
|
4198 int err = 0; |
|
4199 uint64_t snapobj; |
|
4200 dsl_pool_t *dp = firstsnap->ds_dir->dd_pool; |
|
4201 |
|
4202 ASSERT(dsl_dataset_is_snapshot(firstsnap)); |
|
4203 ASSERT(dsl_dataset_is_snapshot(lastsnap)); |
|
4204 |
|
4205 /* |
|
4206 * Check that the snapshots are in the same dsl_dir, and firstsnap |
|
4207 * is before lastsnap. |
|
4208 */ |
|
4209 if (firstsnap->ds_dir != lastsnap->ds_dir || |
|
4210 firstsnap->ds_phys->ds_creation_txg > |
|
4211 lastsnap->ds_phys->ds_creation_txg) |
|
4212 return (EINVAL); |
|
4213 |
|
4214 *usedp = *compp = *uncompp = 0; |
|
4215 |
|
4216 rw_enter(&dp->dp_config_rwlock, RW_READER); |
|
4217 snapobj = lastsnap->ds_phys->ds_next_snap_obj; |
|
4218 while (snapobj != firstsnap->ds_object) { |
|
4219 dsl_dataset_t *ds; |
|
4220 uint64_t used, comp, uncomp; |
|
4221 |
|
4222 err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &ds); |
|
4223 if (err != 0) |
|
4224 break; |
|
4225 |
|
4226 dsl_deadlist_space_range(&ds->ds_deadlist, |
|
4227 firstsnap->ds_phys->ds_prev_snap_txg, UINT64_MAX, |
|
4228 &used, &comp, &uncomp); |
|
4229 *usedp += used; |
|
4230 *compp += comp; |
|
4231 *uncompp += uncomp; |
|
4232 |
|
4233 snapobj = ds->ds_phys->ds_prev_snap_obj; |
|
4234 ASSERT3U(snapobj, !=, 0); |
|
4235 dsl_dataset_rele(ds, FTAG); |
|
4236 } |
|
4237 rw_exit(&dp->dp_config_rwlock); |
|
4238 return (err); |
|
4239 } |