1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
14 */
15
16 /*
17 * ZFS Autosnap wrap-module
18 */
19
20 #include <sys/types.h>
21 #include <sys/kmem.h>
22 #include <sys/ddi.h>
23 #include <sys/sunddi.h>
24 #include <sys/sunldi.h>
25 #include <sys/time.h>
26 #include <sys/sdt.h>
27 #include <sys/sysmacros.h>
28 #include <sys/modctl.h>
29 #include <sys/class.h>
30 #include <sys/cmn_err.h>
31
32 #include "krrp_autosnap.h"
33
34 /* #define KRRP_DEBUG 1 */
35
36 typedef struct krrp_txg_s {
37 list_t node;
38 uint64_t txg_start;
39 uint64_t txg_end;
40 } krrp_txg_t;
41
42
43 static void krrp_autosnap_common_create(krrp_autosnap_t **result_autosnap,
44 size_t keep_snaps, const char *dataset, autosnap_flags_t flags);
45 static uint64_t krrp_get_txg_from_snap_nvp(nvpair_t *);
46 static boolean_t krrp_autosnap_try_hold_with_check_state(
47 krrp_autosnap_t *autosnap, krrp_autosnap_state_t min_state);
48
49 void
50 krrp_autosnap_rside_create(krrp_autosnap_t **result_autosnap,
51 size_t keep_snaps, const char *dataset, boolean_t recursive)
52 {
53 autosnap_flags_t flags;
54
55 flags = AUTOSNAP_CREATOR | AUTOSNAP_DESTROYER |
56 AUTOSNAP_OWNER | AUTOSNAP_KRRP;
57 if (recursive)
58 flags |= AUTOSNAP_RECURSIVE;
59
60 krrp_autosnap_common_create(result_autosnap, keep_snaps,
61 dataset, flags);
62 }
63
64 void
65 krrp_autosnap_wside_create(krrp_autosnap_t **result_autosnap,
66 size_t keep_snaps, const char *dataset)
67 {
68 autosnap_flags_t flags;
69
70 flags = AUTOSNAP_DESTROYER | AUTOSNAP_RECURSIVE |
71 AUTOSNAP_OWNER | AUTOSNAP_KRRP;
72
73 krrp_autosnap_common_create(result_autosnap, keep_snaps,
74 dataset, flags);
75 }
76
77 static void
78 krrp_autosnap_common_create(krrp_autosnap_t **result_autosnap,
79 size_t keep_snaps, const char *dataset, autosnap_flags_t flags)
80 {
81 krrp_autosnap_t *autosnap;
82
83 VERIFY(result_autosnap != NULL && *result_autosnap == NULL);
84 VERIFY(dataset != NULL && dataset[0] != '\0');
85
86 autosnap = kmem_zalloc(sizeof (krrp_autosnap_t), KM_SLEEP);
87
88 mutex_init(&autosnap->mtx, NULL, MUTEX_DEFAULT, NULL);
89 cv_init(&autosnap->cv, NULL, CV_DEFAULT, NULL);
90
91 krrp_queue_init(&autosnap->txg_to_rele, sizeof (krrp_txg_t),
92 offsetof(krrp_txg_t, node));
93
94 autosnap->keep_snaps = keep_snaps;
95 autosnap->state = KRRP_AUTOSNAP_STATE_CREATED;
96 autosnap->flags = flags;
97 autosnap->dataset = dataset;
98
99 *result_autosnap = autosnap;
100 }
101
102 void
103 krrp_autosnap_destroy(krrp_autosnap_t *autosnap)
104 {
105 krrp_txg_t *txg_item;
106 void *zfs_ctx = NULL;
107
108 krrp_autosnap_deactivate(autosnap);
109
110 krrp_autosnap_lock(autosnap);
111 autosnap->state = KRRP_AUTOSNAP_STATE_CREATED;
112 while (autosnap->ref_cnt > 0)
113 krrp_autosnap_cv_wait(autosnap);
114
115 zfs_ctx = autosnap->zfs_ctx;
116 autosnap->zfs_ctx = NULL;
117 krrp_autosnap_unlock(autosnap);
118
119 if (zfs_ctx != NULL)
120 autosnap_unregister_handler(zfs_ctx);
121
122
123 /*
124 * After deactivation no one can push to the queue
125 * therefore we can safely iterate over all the elements
126 * in the queue and free them.
127 */
128 while ((txg_item =
129 krrp_queue_get_no_wait(autosnap->txg_to_rele)) != NULL)
130 kmem_free(txg_item, sizeof (krrp_txg_t));
131
132 krrp_queue_fini(autosnap->txg_to_rele);
133
134 cv_destroy(&autosnap->cv);
135 mutex_destroy(&autosnap->mtx);
136
137 kmem_free(autosnap, sizeof (krrp_autosnap_t));
138 }
139
140 int
141 krrp_autosnap_activate(krrp_autosnap_t *autosnap, uint64_t incr_snap_txg,
142 autosnap_confirm_cb confirm_cb, autosnap_notify_created_cb notify_cb,
143 autosnap_error_cb error_cb, krrp_autosnap_restore_cb_t restore_cb,
144 void *cb_arg, krrp_error_t *error)
145 {
146 nvlist_t *snaps;
147 nvpair_t *target_snap_nvp = NULL, *snap_nvp;
148 uint64_t target_snap_txg = UINT64_MAX;
149 boolean_t read_side = ((autosnap->flags & AUTOSNAP_CREATOR) != 0);
150
151 VERIFY(notify_cb != NULL);
152
153 autosnap->zfs_ctx = autosnap_register_handler(autosnap->dataset,
154 autosnap->flags, confirm_cb, notify_cb, error_cb, cb_arg);
155
156 if (autosnap->zfs_ctx == NULL) {
157 krrp_error_set(error, KRRP_ERRNO_AUTOSNAP, EINVAL);
158 return (-1);
159 }
160
161 krrp_autosnap_lock(autosnap);
162 autosnap->state = KRRP_AUTOSNAP_STATE_REGISTERED;
163 krrp_autosnap_unlock(autosnap);
164
165 snaps = autosnap_get_owned_snapshots(autosnap->zfs_ctx);
166
167 snap_nvp = nvlist_next_nvpair(snaps, NULL);
168 while (snap_nvp != NULL) {
169 uint64_t snap_txg;
170
171 snap_txg = krrp_get_txg_from_snap_nvp(snap_nvp);
172
173 if (incr_snap_txg != UINT64_MAX && snap_txg < incr_snap_txg) {
174 /*
175 * All TXG that before incremetal is not
176 * required and should be released
177 */
178 DTRACE_PROBE1(rele_old_snap, uint64_t, snap_txg);
179
180 krrp_autosnap_txg_rele(autosnap, snap_txg,
181 AUTOSNAP_NO_SNAP);
182 }
183
184 if (incr_snap_txg == UINT64_MAX || snap_txg > incr_snap_txg) {
185 if (target_snap_txg == UINT64_MAX ||
186 snap_txg > target_snap_txg) {
187
188 if (target_snap_txg != UINT64_MAX) {
189 /*
190 * We are looking for maximum TXG,
191 * so all previous TXGs should
192 * be released
193 */
194 DTRACE_PROBE1(rele_interim_snap,
195 uint64_t, target_snap_txg);
196
197 autosnap_release_snapshots_by_txg(
198 autosnap->zfs_ctx,
199 target_snap_txg,
200 AUTOSNAP_NO_SNAP);
201 }
202
203 target_snap_txg = snap_txg;
204 target_snap_nvp = snap_nvp;
205 }
206 }
207
208 snap_nvp = nvlist_next_nvpair(snaps, snap_nvp);
209 }
210
211 if (read_side && incr_snap_txg == UINT64_MAX &&
212 target_snap_txg != UINT64_MAX) {
213 /*
214 * On start we always create snapshot,
215 * so the have found target_snap_txg
216 * is not required without incr_snap_txg
217 */
218 autosnap_release_snapshots_by_txg(autosnap->zfs_ctx,
219 target_snap_txg, AUTOSNAP_NO_SNAP);
220 goto out;
221 }
222
223 if (incr_snap_txg != UINT64_MAX) {
224 krrp_autosnap_txg_rele(autosnap, incr_snap_txg,
225 AUTOSNAP_NO_SNAP);
226 }
227
228 if (target_snap_txg != UINT64_MAX && restore_cb != NULL) {
229 char *snap_name;
230
231 snap_name = strchr(nvpair_name(target_snap_nvp), '@');
232 snap_name++;
233
234 restore_cb(cb_arg, snap_name, target_snap_txg);
235 }
236
237 out:
238 fnvlist_free(snaps);
239
240 krrp_autosnap_lock(autosnap);
241 autosnap->state = KRRP_AUTOSNAP_STATE_ACTIVE;
242 krrp_autosnap_unlock(autosnap);
243
244 return (0);
245 }
246
247 void
248 krrp_autosnap_deactivate(krrp_autosnap_t *autosnap)
249 {
250 krrp_autosnap_lock(autosnap);
251 if (autosnap->state == KRRP_AUTOSNAP_STATE_ACTIVE) {
252 autosnap->state = KRRP_AUTOSNAP_STATE_REGISTERED;
253 while (autosnap->ref_cnt > 0)
254 krrp_autosnap_cv_wait(autosnap);
255 }
256
257 krrp_autosnap_unlock(autosnap);
258 }
259
260 static uint64_t
261 krrp_get_txg_from_snap_nvp(nvpair_t *snap)
262 {
263 uint64_t *snap_info = NULL;
264 uint_t nelem = 0;
265
266 VERIFY3U(nvpair_value_uint64_array(snap,
267 &snap_info, &nelem), ==, 0);
268 VERIFY(nelem != 0);
269
270 return (snap_info[0]);
271 }
272
273 boolean_t
274 krrp_autosnap_try_hold_to_confirm(krrp_autosnap_t *autosnap)
275 {
276 return (krrp_autosnap_try_hold_with_check_state(autosnap,
277 KRRP_AUTOSNAP_STATE_ACTIVE));
278 }
279
280 static boolean_t
281 krrp_autosnap_try_hold_with_check_state(krrp_autosnap_t *autosnap,
282 krrp_autosnap_state_t min_state)
283 {
284 boolean_t rc = B_FALSE;
285
286 krrp_autosnap_lock(autosnap);
287
288 if (autosnap->state >= min_state) {
289 autosnap->ref_cnt++;
290 rc = B_TRUE;
291 }
292
293 krrp_autosnap_unlock(autosnap);
294
295 return (rc);
296 }
297
298 void
299 krrp_autosnap_unhold(krrp_autosnap_t *autosnap)
300 {
301 krrp_autosnap_lock(autosnap);
302 autosnap->ref_cnt--;
303 krrp_autosnap_cv_signal(autosnap);
304 krrp_autosnap_unlock(autosnap);
305 }
306
307 void
308 krrp_autosnap_create_snapshot(krrp_autosnap_t *autosnap)
309 {
310 if (krrp_autosnap_try_hold_with_check_state(autosnap,
311 KRRP_AUTOSNAP_STATE_ACTIVE)) {
312 autosnap_force_snap(autosnap->zfs_ctx, B_FALSE);
313
314 krrp_autosnap_unhold(autosnap);
315 }
316 }
317
318 void
319 krrp_autosnap_txg_rele(krrp_autosnap_t *autosnap,
320 uint64_t txg_start, uint64_t txg_end)
321 {
322 krrp_txg_t *txg_item;
323
324 if (!krrp_autosnap_try_hold_with_check_state(autosnap,
325 KRRP_AUTOSNAP_STATE_REGISTERED))
326 return;
327
328 txg_item = kmem_zalloc(sizeof (krrp_txg_t), KM_SLEEP);
329 txg_item->txg_start = txg_start;
330 txg_item->txg_end = txg_end;
331 krrp_queue_put(autosnap->txg_to_rele, txg_item);
332
333 while (krrp_queue_length(autosnap->txg_to_rele) >
334 autosnap->keep_snaps) {
335 txg_item = krrp_queue_get(autosnap->txg_to_rele);
336
337 autosnap_release_snapshots_by_txg(autosnap->zfs_ctx,
338 txg_item->txg_start, txg_item->txg_end);
339
340 kmem_free(txg_item, sizeof (krrp_txg_t));
341 }
342
343 krrp_autosnap_unhold(autosnap);
344 }
345
346 /*
347 * The function is used under krrp_autosnap hold and
348 * only from autosnap_notify_cb ctx
349 */
350 void
351 krrp_autosnap_txg_rele_one(krrp_autosnap_t *autosnap, uint64_t txg)
352 {
353 autosnap_release_snapshots_by_txg_no_lock(autosnap->zfs_ctx,
354 txg, AUTOSNAP_NO_SNAP);
355 }