Print this page
NEX-13374 NDMP should be able to backup unmounted ZFS filesystems
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Revert "NEX-5801 Snapshots left over after failed backups"
This reverts commit f182fb95f09036db71fbfc6f0a6b90469b761f21.
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-2911 NDMP logging should use syslog and is too chatty (build noise)
NEX-2911 NDMP logging should use syslog and is too chatty
NEX-894 Default location of NDMP log file should be under /var/log
NEX-559 NDMP cannot backup/restore a file which spans multiple tapes

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c
          +++ new/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c
   1    1  /*
   2    2   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
   3      - * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
        3 + * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
   4    4   */
   5    5  
   6    6  /*
   7    7   * BSD 3 Clause License
   8    8   *
   9    9   * Copyright (c) 2007, The Storage Networking Industry Association.
  10   10   *
  11   11   * Redistribution and use in source and binary forms, with or without
  12   12   * modification, are permitted provided that the following conditions
  13   13   * are met:
↓ open down ↓ 19 lines elided ↑ open up ↑
  33   33   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34   34   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  35   35   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  36   36   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37   37   * POSSIBILITY OF SUCH DAMAGE.
  38   38   */
  39   39  /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
  40   40  
  41   41  #include <errno.h>
  42   42  #include <signal.h>
  43      -#include <libgen.h>
  44   43  #include <libscf.h>
  45   44  #include <libintl.h>
  46   45  #include <sys/wait.h>
       46 +#include <syslog.h>
       47 +#include <syslog.h>
  47   48  #include <zone.h>
  48   49  #include <tsol/label.h>
  49   50  #include <dlfcn.h>
       51 +#include <sys/mount.h>
       52 +#include <libzfs.h>
  50   53  #include "ndmpd.h"
  51   54  #include "ndmpd_common.h"
  52   55  
  53   56  /* zfs library handle & mutex */
  54   57  libzfs_handle_t *zlibh;
  55   58  mutex_t zlib_mtx;
  56   59  void *mod_plp;
  57   60  
  58   61  static void ndmpd_sig_handler(int sig);
  59   62  
↓ open down ↓ 14 lines elided ↑ open up ↑
  74   77          char *plname;
  75   78          ndmp_plugin_t *(*plugin_init)(int);
  76   79  
  77   80          ndmp_pl = NULL;
  78   81  
  79   82          plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
  80   83          if (plname == NULL || *plname == '\0')
  81   84                  return (0);
  82   85  
  83   86          if ((mod_plp = dlopen(plname, RTLD_LOCAL | RTLD_NOW)) == NULL) {
  84      -                NDMP_LOG(LOG_ERR, "Error loading the plug-in %s: %s",
       87 +                syslog(LOG_ERR, "Error loading the plug-in %s: %s",
  85   88                      plname, dlerror());
  86   89                  return (0);
  87   90          }
  88   91  
  89   92          plugin_init = (ndmp_plugin_t *(*)(int))dlsym(mod_plp, "_ndmp_init");
  90   93          if (plugin_init == NULL) {
  91   94                  (void) dlclose(mod_plp);
  92   95                  return (0);
  93   96          }
  94   97          if ((ndmp_pl = plugin_init(NDMP_PLUGIN_VERSION)) == NULL) {
  95      -                NDMP_LOG(LOG_ERR, "Error loading the plug-in %s", plname);
       98 +                syslog(LOG_ERR, "Error loading the plug-in %s", plname);
  96   99                  return (-1);
  97  100          }
  98  101          return (0);
  99  102  }
 100  103  
 101  104  /*
 102  105   * Unload
 103  106   */
 104  107  static void
 105  108  mod_fini()
↓ open down ↓ 71 lines elided ↑ open up ↑
 177  180          /* If we're the parent process, exit. */
 178  181          if (pid != 0) {
 179  182                  _exit(0);
 180  183          }
 181  184          (void) setsid();
 182  185          (void) sigprocmask(SIG_SETMASK, &oset, NULL);
 183  186          (void) chdir("/");
 184  187  }
 185  188  
 186  189  /*
      190 + * Utility routine to check if a zpool is bootable. For the purposes
      191 + * of cleaning up ndmp backup clones and snapshots, shouldn't consider
      192 + * the 'boot' volume.
      193 + *
      194 + * Parameters:
      195 + *   zhp (input) - the zfs handle of the zpool dataset.
      196 + *
      197 + * Returns:
      198 + *   B_TRUE : If the given zpool has a boot record
      199 + *   B_FALSE: otherwise
      200 + */
      201 +boolean_t
      202 +ndmp_zpool_is_bootable(zpool_handle_t *zhp)
      203 +{
      204 +        char bootfs[ZFS_MAX_DATASET_NAME_LEN];
      205 +
      206 +        return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
      207 +            sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-",
      208 +            sizeof (bootfs)) != 0);
      209 +}
      210 +
      211 +/*
      212 + * This is the zpool_iter() callback routine specifically for
      213 + * ZFS_TYPE_SNAPSHOTS and is passed in a zfs handle to each one
      214 + * it finds during iteration.  If this callback returns zero
      215 + * the iterator keeps going, if it returns non-sero the
      216 + * iteration stops.
      217 + *
      218 + * Parameters:
      219 + *   zhp (input) - the zfs handle of the ZFS_TYPE_SNAPSHOTS dataset.
      220 + *   arg (input) - optional parameter (not used in this case)
      221 + *
      222 + * Returns:
      223 + *   0: on success
      224 + *  -1: otherwise
      225 + */
      226 +/*ARGSUSED*/
      227 +int
      228 +ndmp_match_and_destroy_snapshot(zfs_handle_t *zhp, void *arg)
      229 +{
      230 +        int err = 0;
      231 +        char *dataset_name;
      232 +        char *snap_name;
      233 +        char *snap_delim;
      234 +        zfs_handle_t *dszhp;
      235 +
      236 +        dataset_name = strdup(zfs_get_name(zhp));
      237 +        if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
      238 +                if (strstr(dataset_name, NDMP_RCF_BASENAME) != NULL) {
      239 +                        snap_delim = strchr(dataset_name, '@');
      240 +                        snap_name = snap_delim + 1;
      241 +                        *snap_delim = '\0';
      242 +
      243 +                        syslog(LOG_DEBUG,
      244 +                            "Remove snap [%s] from dataset [%s] tag [%s]\n",
      245 +                            snap_name, dataset_name, NDMP_RCF_BASENAME);
      246 +
      247 +                        if ((dszhp = zfs_open(zlibh, dataset_name,
      248 +                            ZFS_TYPE_DATASET)) != NULL) {
      249 +                                if ((err = zfs_release(dszhp, snap_name,
      250 +                                    NDMP_RCF_BASENAME, B_FALSE)) != 0) {
      251 +                                        if (libzfs_errno(zlibh)
      252 +                                            != EZFS_REFTAG_RELE) {
      253 +                                                syslog(LOG_DEBUG,
      254 +                                                    "(%d) problem zfs_release "
      255 +                                                    "error:%s action:"
      256 +                                                    "%s errno:%d\n",
      257 +                                                    err,
      258 +                                                    libzfs_error_description(
      259 +                                                    zlibh),
      260 +                                                    libzfs_error_action(
      261 +                                                    zlibh),
      262 +                                                    libzfs_errno(
      263 +                                                    zlibh));
      264 +                                                zfs_close(dszhp);
      265 +                                                goto _out;
      266 +                                        }
      267 +                                }
      268 +                                if ((err = zfs_destroy(zhp, B_FALSE)) != 0) {
      269 +                                        syslog(LOG_DEBUG,
      270 +                                            "(%d)snapshot: problem zfs_destroy "
      271 +                                            "error:%s action:%s errno:%d\n",
      272 +                                            err,
      273 +                                            libzfs_error_description(zlibh),
      274 +                                            libzfs_error_action(zlibh),
      275 +                                            libzfs_errno(zlibh));
      276 +                                }
      277 +                                zfs_close(dszhp);
      278 +                        } else {
      279 +                                err = -1;
      280 +                                goto _out;
      281 +                        }
      282 +                }
      283 +        }
      284 +_out:
      285 +        free(dataset_name);
      286 +        zfs_close(zhp);
      287 +        return (err);
      288 +}
      289 +
      290 +/*
      291 + * This is the zpool_iter() callback routine specifically for
      292 + * ZFS_TYPE_FILESYSTEM and is passed in a zfs handle to each one
      293 + * it finds during iteration.  If this callback returns zero
      294 + * the iterator keeps going, if it returns non-sero the
      295 + * iteration stops.
      296 + *
      297 + * Parameters:
      298 + *   zhp (input) - the zfs handle of the ZFS_TYPE_FILESYSTEM dataset.
      299 + *   arg (input) - optional parameter (not used in this case)
      300 + *
      301 + * Returns:
      302 + *   0: on success
      303 + *  -1: otherwise
      304 + */
      305 +/*ARGSUSED*/
      306 +int
      307 +ndmp_match_and_destroy_filesystem(zfs_handle_t *zhp, void *arg)
      308 +{
      309 +        int err = 0;
      310 +        char *mntpt = NULL;
      311 +        char *dataset_name;
      312 +
      313 +        dataset_name = strdup(zfs_get_name(zhp));
      314 +        if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM)  {
      315 +                if (strstr(dataset_name, NDMP_RCF_BASENAME) != NULL) {
      316 +
      317 +                        syslog(LOG_DEBUG,
      318 +                            "Remove filesystem [%s]", dataset_name);
      319 +                        if (zfs_is_mounted(zhp, &mntpt)) {
      320 +                                syslog(LOG_DEBUG,
      321 +                                    "mountpoint for snapshot is [%s]\n", mntpt);
      322 +                                if (zfs_unmount(zhp, NULL, MS_FORCE) != 0) {
      323 +                                        syslog(LOG_DEBUG, "Failed to unmount "
      324 +                                            "mount point [%s]", mntpt);
      325 +                                        err = -1;
      326 +                                        goto _out;
      327 +                                }
      328 +                        }
      329 +                        if (rmdir(mntpt) != 0) {
      330 +                                if (errno != ENOENT) {
      331 +                                        syslog(LOG_DEBUG, "Failed to remove "
      332 +                                            "mount point [%s]", mntpt);
      333 +                                        err = -1;
      334 +                                        goto _out;
      335 +                                }
      336 +                        }
      337 +
      338 +                        if ((err = zfs_destroy(zhp, B_FALSE)) != 0) {
      339 +                                syslog(LOG_DEBUG,
      340 +                                    "(%d)filesystem: problem zfs_destroy "
      341 +                                    "error:%s action:%s errno:%d\n",
      342 +                                    err, libzfs_error_description(zlibh),
      343 +                                    libzfs_error_action(zlibh),
      344 +                                    libzfs_errno(zlibh));
      345 +                        }
      346 +                }
      347 +        }
      348 +_out:
      349 +        free(dataset_name);
      350 +        zfs_close(zhp);
      351 +        return (err);
      352 +}
      353 +
      354 +/*
      355 + * This is the zpool iterator callback routine.  For each pool on
      356 + * the system iterate filesystem dependents first then iterate snapshot
      357 + * dependents and run the corresponding ndmp_match_and_destroy_XXX()
      358 + * callback. The 'snapshot' are removed second because 'filesystem'
      359 + * is dependend on its parent 'snapshot'.  If this callback returns
      360 + * zero the iterator keeps going, if it returns non-sero the
      361 + * iteration stops.
      362 + *
      363 + * Parameters:
      364 + *   zhp (input) - the zfs handle of the zpool dataset.
      365 + *   arg (input) - optional parameter (not used in this case)
      366 + *
      367 + * Returns:
      368 + *   0: on success
      369 + *  -1: otherwise
      370 + */
      371 +/*ARGSUSED*/
      372 +int
      373 +ndmp_cleanup_snapshots_inpool(zfs_handle_t *zhp, void *arg)
      374 +{
      375 +        const char *zpool_name;
      376 +        int err = 0;
      377 +        zpool_handle_t *php;
      378 +
      379 +        /*
      380 +         * Check for pools with bootfs entries and skip them
      381 +         */
      382 +        zpool_name = zfs_get_name(zhp);
      383 +        if ((php = zpool_open(zlibh, zpool_name)) != NULL) {
      384 +                if (!ndmp_zpool_is_bootable(php)) {
      385 +                        syslog(LOG_DEBUG,
      386 +                            "Working on pool [%s]\n", zfs_get_name(zhp));
      387 +
      388 +                        err = zfs_iter_dependents(zhp, B_FALSE,
      389 +                            ndmp_match_and_destroy_filesystem, (void *)NULL);
      390 +                        if (err) {
      391 +                                syslog(LOG_ERR,
      392 +                                    "cleanup filesystems error: "
      393 +                                    "%d on pool [%s]",
      394 +                                    err, zpool_name);
      395 +                                goto _out;
      396 +                        }
      397 +                        err = zfs_iter_dependents(zhp,
      398 +                            B_FALSE, ndmp_match_and_destroy_snapshot,
      399 +                            (void *)NULL);
      400 +                        if (err) {
      401 +                                syslog(LOG_ERR,
      402 +                                    "cleanup snapshots error: %d on pool",
      403 +                                    err, zpool_name);
      404 +                        }
      405 +                }
      406 +        }
      407 +_out:
      408 +        zpool_close(php);
      409 +        zfs_close(zhp);
      410 +        return (err);
      411 +}
      412 +
      413 +/*
 187  414   * main
 188  415   *
 189  416   * The main NDMP daemon function
 190  417   *
 191  418   * Parameters:
 192  419   *   argc (input) - the argument count
 193  420   *   argv (input) - command line options
 194  421   *
 195  422   * Returns:
 196  423   *   0
 197  424   */
 198  425  int
 199  426  main(int argc, char *argv[])
 200  427  {
 201  428          struct sigaction act;
 202  429          sigset_t set;
 203  430          char c;
 204  431          void *arg = NULL;
 205  432          boolean_t run_in_foreground = B_FALSE;
 206      -        boolean_t override_debug = B_FALSE;
 207  433  
 208  434          /*
 209  435           * Check for existing ndmpd door server (make sure ndmpd is not already
 210  436           * running)
 211  437           */
 212  438          if (ndmp_door_check()) {
 213  439                  /* ndmpd is already running, exit. */
 214  440                  (void) fprintf(stderr, "ndmpd is already running.\n");
 215  441                  return (0);
 216  442          }
↓ open down ↓ 13 lines elided ↑ open up ↑
 230  456          /* load SMF configuration */
 231  457          if (ndmpd_load_prop()) {
 232  458                  (void) fprintf(stderr,
 233  459                      "SMF properties initialization failed.\n");
 234  460                  exit(SMF_EXIT_ERR_CONFIG);
 235  461          }
 236  462  
 237  463          opterr = 0;
 238  464          while ((c = getopt(argc, argv, "df")) != -1) {
 239  465                  switch (c) {
 240      -                case 'd':
 241      -                        override_debug = B_TRUE;
 242      -                        break;
 243  466                  case 'f':
 244  467                          run_in_foreground = B_TRUE;
 245  468                          break;
 246  469                  default:
 247  470                          (void) fprintf(stderr, "%s: Invalid option -%c.\n",
 248  471                              argv[0], optopt);
 249      -                        (void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]);
      472 +                        (void) fprintf(stderr, "Usage: %s [-f]\n", argv[0]);
 250  473                          exit(SMF_EXIT_ERR_CONFIG);
 251  474                  }
 252  475          }
 253  476  
 254  477          /* set up signal handler */
 255  478          (void) sigfillset(&set);
 256  479          (void) sigdelset(&set, SIGABRT); /* always unblocked for ASSERT() */
 257  480          (void) sigfillset(&act.sa_mask);
 258  481          act.sa_handler = ndmpd_sig_handler;
 259  482          act.sa_flags = 0;
↓ open down ↓ 4 lines elided ↑ open up ↑
 264  487          (void) sigaction(SIGUSR1, &act, NULL);
 265  488          (void) sigaction(SIGPIPE, &act, NULL);
 266  489          (void) sigdelset(&set, SIGTERM);
 267  490          (void) sigdelset(&set, SIGHUP);
 268  491          (void) sigdelset(&set, SIGINT);
 269  492          (void) sigdelset(&set, SIGUSR1);
 270  493          (void) sigdelset(&set, SIGPIPE);
 271  494  
 272  495          set_privileges();
 273  496          (void) umask(077);
 274      -        openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON);
      497 +        openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_LOCAL4);
 275  498  
 276      -        /*
 277      -         * Open log file before we detach from terminal in case that open
 278      -         * fails and error message is printed to stderr.
 279      -         */
 280      -        if (ndmp_log_open_file(run_in_foreground, override_debug) != 0)
 281      -                exit(SMF_EXIT_ERR_FATAL);
 282      -
 283  499          if (!run_in_foreground)
 284  500                  daemonize_init();
 285  501  
 286      -        (void) mutex_init(&ndmpd_zfs_fd_lock, 0, NULL);
 287      -
 288  502          if (mod_init() != 0) {
 289      -                NDMP_LOG(LOG_ERR, "Failed to load the plugin module.");
      503 +                syslog(LOG_ERR, "Failed to load the plugin module.");
 290  504                  exit(SMF_EXIT_ERR_CONFIG);
 291  505          }
 292  506  
 293  507          /* libzfs init */
 294  508          if ((zlibh = libzfs_init()) == NULL) {
 295      -                NDMP_LOG(LOG_ERR, "Failed to initialize ZFS library.");
      509 +                syslog(LOG_ERR, "Failed to initialize ZFS library.");
 296  510                  exit(SMF_EXIT_ERR_CONFIG);
 297  511          }
 298  512  
 299  513          /* initialize and start the door server */
 300  514          if (ndmp_door_init()) {
 301      -                NDMP_LOG(LOG_ERR, "Can not start ndmpd door server.");
      515 +                syslog(LOG_ERR, "Can not start ndmpd door server.");
 302  516                  exit(SMF_EXIT_ERR_CONFIG);
 303  517          }
 304  518  
 305  519          if (tlm_init() == -1) {
 306      -                NDMP_LOG(LOG_ERR, "Failed to initialize tape manager.");
      520 +                syslog(LOG_ERR, "Failed to initialize tape manager.");
 307  521                  exit(SMF_EXIT_ERR_CONFIG);
 308  522          }
 309  523  
 310  524          /*
      525 +         * Use libzfs iterator routine to list through all the pools and
      526 +         * invoke cleanup callback routine on each.
      527 +         */
      528 +        if (zfs_iter_root(zlibh,
      529 +            ndmp_cleanup_snapshots_inpool, (void *)NULL) != 0) {
      530 +                syslog(LOG_ERR, "Failed to cleanup leftover snapshots.");
      531 +                exit(SMF_EXIT_ERR_CONFIG);
      532 +        }
      533 +
      534 +        /*
 311  535           * Prior to this point, we are single-threaded. We will be
 312  536           * multi-threaded from this point on.
 313  537           */
 314  538          (void) pthread_create(NULL, NULL, (funct_t)ndmpd_main,
 315  539              (void *)&arg);
 316  540  
 317  541          while (!ndmpd.s_shutdown_flag) {
 318  542                  (void) sigsuspend(&set);
 319  543  
 320  544                  switch (ndmpd.s_sigval) {
 321  545                  case 0:
 322  546                          break;
 323  547  
 324  548                  case SIGPIPE:
 325  549                          break;
 326  550  
 327  551                  case SIGHUP:
 328  552                          /* Refresh SMF properties */
 329  553                          if (ndmpd_load_prop())
 330      -                                NDMP_LOG(LOG_ERR,
      554 +                                syslog(LOG_ERR,
 331  555                                      "Service properties initialization "
 332  556                                      "failed.");
 333  557                          break;
 334  558  
 335  559                  default:
 336  560                          /*
 337  561                           * Typically SIGINT or SIGTERM.
 338  562                           */
 339  563                          ndmpd.s_shutdown_flag = 1;
 340  564                          break;
 341  565                  }
 342  566  
 343  567                  ndmpd.s_sigval = 0;
 344  568          }
 345  569  
 346      -        (void) mutex_destroy(&ndmpd_zfs_fd_lock);
 347  570          libzfs_fini(zlibh);
 348  571          mod_fini();
 349  572          ndmp_door_fini();
 350      -        ndmp_log_close_file();
      573 +        closelog();
 351  574  
 352  575          return (SMF_EXIT_OK);
 353  576  }
 354  577  
 355  578  static void
 356  579  ndmpd_sig_handler(int sig)
 357  580  {
 358  581          if (ndmpd.s_sigval == 0)
 359  582                  ndmpd.s_sigval = sig;
 360  583  }
↓ open down ↓ 17 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX