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 }