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

*** 1,8 **** /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ /* * BSD 3 Clause License * --- 1,8 ---- /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ /* * BSD 3 Clause License *
*** 38,54 **** */ /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */ #include <errno.h> #include <signal.h> - #include <libgen.h> #include <libscf.h> #include <libintl.h> #include <sys/wait.h> #include <zone.h> #include <tsol/label.h> #include <dlfcn.h> #include "ndmpd.h" #include "ndmpd_common.h" /* zfs library handle & mutex */ libzfs_handle_t *zlibh; --- 38,57 ---- */ /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */ #include <errno.h> #include <signal.h> #include <libscf.h> #include <libintl.h> #include <sys/wait.h> + #include <syslog.h> + #include <syslog.h> #include <zone.h> #include <tsol/label.h> #include <dlfcn.h> + #include <sys/mount.h> + #include <libzfs.h> #include "ndmpd.h" #include "ndmpd_common.h" /* zfs library handle & mutex */ libzfs_handle_t *zlibh;
*** 79,89 **** plname = ndmpd_get_prop(NDMP_PLUGIN_PATH); if (plname == NULL || *plname == '\0') return (0); if ((mod_plp = dlopen(plname, RTLD_LOCAL | RTLD_NOW)) == NULL) { ! NDMP_LOG(LOG_ERR, "Error loading the plug-in %s: %s", plname, dlerror()); return (0); } plugin_init = (ndmp_plugin_t *(*)(int))dlsym(mod_plp, "_ndmp_init"); --- 82,92 ---- plname = ndmpd_get_prop(NDMP_PLUGIN_PATH); if (plname == NULL || *plname == '\0') return (0); if ((mod_plp = dlopen(plname, RTLD_LOCAL | RTLD_NOW)) == NULL) { ! syslog(LOG_ERR, "Error loading the plug-in %s: %s", plname, dlerror()); return (0); } plugin_init = (ndmp_plugin_t *(*)(int))dlsym(mod_plp, "_ndmp_init");
*** 90,100 **** if (plugin_init == NULL) { (void) dlclose(mod_plp); return (0); } if ((ndmp_pl = plugin_init(NDMP_PLUGIN_VERSION)) == NULL) { ! NDMP_LOG(LOG_ERR, "Error loading the plug-in %s", plname); return (-1); } return (0); } --- 93,103 ---- if (plugin_init == NULL) { (void) dlclose(mod_plp); return (0); } if ((ndmp_pl = plugin_init(NDMP_PLUGIN_VERSION)) == NULL) { ! syslog(LOG_ERR, "Error loading the plug-in %s", plname); return (-1); } return (0); }
*** 182,191 **** --- 185,418 ---- (void) sigprocmask(SIG_SETMASK, &oset, NULL); (void) chdir("/"); } /* + * Utility routine to check if a zpool is bootable. For the purposes + * of cleaning up ndmp backup clones and snapshots, shouldn't consider + * the 'boot' volume. + * + * Parameters: + * zhp (input) - the zfs handle of the zpool dataset. + * + * Returns: + * B_TRUE : If the given zpool has a boot record + * B_FALSE: otherwise + */ + boolean_t + ndmp_zpool_is_bootable(zpool_handle_t *zhp) + { + char bootfs[ZFS_MAX_DATASET_NAME_LEN]; + + return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs, + sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-", + sizeof (bootfs)) != 0); + } + + /* + * This is the zpool_iter() callback routine specifically for + * ZFS_TYPE_SNAPSHOTS and is passed in a zfs handle to each one + * it finds during iteration. If this callback returns zero + * the iterator keeps going, if it returns non-sero the + * iteration stops. + * + * Parameters: + * zhp (input) - the zfs handle of the ZFS_TYPE_SNAPSHOTS dataset. + * arg (input) - optional parameter (not used in this case) + * + * Returns: + * 0: on success + * -1: otherwise + */ + /*ARGSUSED*/ + int + ndmp_match_and_destroy_snapshot(zfs_handle_t *zhp, void *arg) + { + int err = 0; + char *dataset_name; + char *snap_name; + char *snap_delim; + zfs_handle_t *dszhp; + + dataset_name = strdup(zfs_get_name(zhp)); + if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) { + if (strstr(dataset_name, NDMP_RCF_BASENAME) != NULL) { + snap_delim = strchr(dataset_name, '@'); + snap_name = snap_delim + 1; + *snap_delim = '\0'; + + syslog(LOG_DEBUG, + "Remove snap [%s] from dataset [%s] tag [%s]\n", + snap_name, dataset_name, NDMP_RCF_BASENAME); + + if ((dszhp = zfs_open(zlibh, dataset_name, + ZFS_TYPE_DATASET)) != NULL) { + if ((err = zfs_release(dszhp, snap_name, + NDMP_RCF_BASENAME, B_FALSE)) != 0) { + if (libzfs_errno(zlibh) + != EZFS_REFTAG_RELE) { + syslog(LOG_DEBUG, + "(%d) problem zfs_release " + "error:%s action:" + "%s errno:%d\n", + err, + libzfs_error_description( + zlibh), + libzfs_error_action( + zlibh), + libzfs_errno( + zlibh)); + zfs_close(dszhp); + goto _out; + } + } + if ((err = zfs_destroy(zhp, B_FALSE)) != 0) { + syslog(LOG_DEBUG, + "(%d)snapshot: problem zfs_destroy " + "error:%s action:%s errno:%d\n", + err, + libzfs_error_description(zlibh), + libzfs_error_action(zlibh), + libzfs_errno(zlibh)); + } + zfs_close(dszhp); + } else { + err = -1; + goto _out; + } + } + } + _out: + free(dataset_name); + zfs_close(zhp); + return (err); + } + + /* + * This is the zpool_iter() callback routine specifically for + * ZFS_TYPE_FILESYSTEM and is passed in a zfs handle to each one + * it finds during iteration. If this callback returns zero + * the iterator keeps going, if it returns non-sero the + * iteration stops. + * + * Parameters: + * zhp (input) - the zfs handle of the ZFS_TYPE_FILESYSTEM dataset. + * arg (input) - optional parameter (not used in this case) + * + * Returns: + * 0: on success + * -1: otherwise + */ + /*ARGSUSED*/ + int + ndmp_match_and_destroy_filesystem(zfs_handle_t *zhp, void *arg) + { + int err = 0; + char *mntpt = NULL; + char *dataset_name; + + dataset_name = strdup(zfs_get_name(zhp)); + if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) { + if (strstr(dataset_name, NDMP_RCF_BASENAME) != NULL) { + + syslog(LOG_DEBUG, + "Remove filesystem [%s]", dataset_name); + if (zfs_is_mounted(zhp, &mntpt)) { + syslog(LOG_DEBUG, + "mountpoint for snapshot is [%s]\n", mntpt); + if (zfs_unmount(zhp, NULL, MS_FORCE) != 0) { + syslog(LOG_DEBUG, "Failed to unmount " + "mount point [%s]", mntpt); + err = -1; + goto _out; + } + } + if (rmdir(mntpt) != 0) { + if (errno != ENOENT) { + syslog(LOG_DEBUG, "Failed to remove " + "mount point [%s]", mntpt); + err = -1; + goto _out; + } + } + + if ((err = zfs_destroy(zhp, B_FALSE)) != 0) { + syslog(LOG_DEBUG, + "(%d)filesystem: problem zfs_destroy " + "error:%s action:%s errno:%d\n", + err, libzfs_error_description(zlibh), + libzfs_error_action(zlibh), + libzfs_errno(zlibh)); + } + } + } + _out: + free(dataset_name); + zfs_close(zhp); + return (err); + } + + /* + * This is the zpool iterator callback routine. For each pool on + * the system iterate filesystem dependents first then iterate snapshot + * dependents and run the corresponding ndmp_match_and_destroy_XXX() + * callback. The 'snapshot' are removed second because 'filesystem' + * is dependend on its parent 'snapshot'. If this callback returns + * zero the iterator keeps going, if it returns non-sero the + * iteration stops. + * + * Parameters: + * zhp (input) - the zfs handle of the zpool dataset. + * arg (input) - optional parameter (not used in this case) + * + * Returns: + * 0: on success + * -1: otherwise + */ + /*ARGSUSED*/ + int + ndmp_cleanup_snapshots_inpool(zfs_handle_t *zhp, void *arg) + { + const char *zpool_name; + int err = 0; + zpool_handle_t *php; + + /* + * Check for pools with bootfs entries and skip them + */ + zpool_name = zfs_get_name(zhp); + if ((php = zpool_open(zlibh, zpool_name)) != NULL) { + if (!ndmp_zpool_is_bootable(php)) { + syslog(LOG_DEBUG, + "Working on pool [%s]\n", zfs_get_name(zhp)); + + err = zfs_iter_dependents(zhp, B_FALSE, + ndmp_match_and_destroy_filesystem, (void *)NULL); + if (err) { + syslog(LOG_ERR, + "cleanup filesystems error: " + "%d on pool [%s]", + err, zpool_name); + goto _out; + } + err = zfs_iter_dependents(zhp, + B_FALSE, ndmp_match_and_destroy_snapshot, + (void *)NULL); + if (err) { + syslog(LOG_ERR, + "cleanup snapshots error: %d on pool", + err, zpool_name); + } + } + } + _out: + zpool_close(php); + zfs_close(zhp); + return (err); + } + + /* * main * * The main NDMP daemon function * * Parameters:
*** 201,211 **** struct sigaction act; sigset_t set; char c; void *arg = NULL; boolean_t run_in_foreground = B_FALSE; - boolean_t override_debug = B_FALSE; /* * Check for existing ndmpd door server (make sure ndmpd is not already * running) */ --- 428,437 ----
*** 235,254 **** } opterr = 0; while ((c = getopt(argc, argv, "df")) != -1) { switch (c) { - case 'd': - override_debug = B_TRUE; - break; case 'f': run_in_foreground = B_TRUE; break; default: (void) fprintf(stderr, "%s: Invalid option -%c.\n", argv[0], optopt); ! (void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]); exit(SMF_EXIT_ERR_CONFIG); } } /* set up signal handler */ --- 461,477 ---- } opterr = 0; while ((c = getopt(argc, argv, "df")) != -1) { switch (c) { case 'f': run_in_foreground = B_TRUE; break; default: (void) fprintf(stderr, "%s: Invalid option -%c.\n", argv[0], optopt); ! (void) fprintf(stderr, "Usage: %s [-f]\n", argv[0]); exit(SMF_EXIT_ERR_CONFIG); } } /* set up signal handler */
*** 269,315 **** (void) sigdelset(&set, SIGUSR1); (void) sigdelset(&set, SIGPIPE); set_privileges(); (void) umask(077); ! openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON); - /* - * Open log file before we detach from terminal in case that open - * fails and error message is printed to stderr. - */ - if (ndmp_log_open_file(run_in_foreground, override_debug) != 0) - exit(SMF_EXIT_ERR_FATAL); - if (!run_in_foreground) daemonize_init(); - (void) mutex_init(&ndmpd_zfs_fd_lock, 0, NULL); - if (mod_init() != 0) { ! NDMP_LOG(LOG_ERR, "Failed to load the plugin module."); exit(SMF_EXIT_ERR_CONFIG); } /* libzfs init */ if ((zlibh = libzfs_init()) == NULL) { ! NDMP_LOG(LOG_ERR, "Failed to initialize ZFS library."); exit(SMF_EXIT_ERR_CONFIG); } /* initialize and start the door server */ if (ndmp_door_init()) { ! NDMP_LOG(LOG_ERR, "Can not start ndmpd door server."); exit(SMF_EXIT_ERR_CONFIG); } if (tlm_init() == -1) { ! NDMP_LOG(LOG_ERR, "Failed to initialize tape manager."); exit(SMF_EXIT_ERR_CONFIG); } /* * Prior to this point, we are single-threaded. We will be * multi-threaded from this point on. */ (void) pthread_create(NULL, NULL, (funct_t)ndmpd_main, (void *)&arg); --- 492,539 ---- (void) sigdelset(&set, SIGUSR1); (void) sigdelset(&set, SIGPIPE); set_privileges(); (void) umask(077); ! openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_LOCAL4); if (!run_in_foreground) daemonize_init(); if (mod_init() != 0) { ! syslog(LOG_ERR, "Failed to load the plugin module."); exit(SMF_EXIT_ERR_CONFIG); } /* libzfs init */ if ((zlibh = libzfs_init()) == NULL) { ! syslog(LOG_ERR, "Failed to initialize ZFS library."); exit(SMF_EXIT_ERR_CONFIG); } /* initialize and start the door server */ if (ndmp_door_init()) { ! syslog(LOG_ERR, "Can not start ndmpd door server."); exit(SMF_EXIT_ERR_CONFIG); } if (tlm_init() == -1) { ! syslog(LOG_ERR, "Failed to initialize tape manager."); exit(SMF_EXIT_ERR_CONFIG); } /* + * Use libzfs iterator routine to list through all the pools and + * invoke cleanup callback routine on each. + */ + if (zfs_iter_root(zlibh, + ndmp_cleanup_snapshots_inpool, (void *)NULL) != 0) { + syslog(LOG_ERR, "Failed to cleanup leftover snapshots."); + exit(SMF_EXIT_ERR_CONFIG); + } + + /* * Prior to this point, we are single-threaded. We will be * multi-threaded from this point on. */ (void) pthread_create(NULL, NULL, (funct_t)ndmpd_main, (void *)&arg);
*** 325,335 **** break; case SIGHUP: /* Refresh SMF properties */ if (ndmpd_load_prop()) ! NDMP_LOG(LOG_ERR, "Service properties initialization " "failed."); break; default: --- 549,559 ---- break; case SIGHUP: /* Refresh SMF properties */ if (ndmpd_load_prop()) ! syslog(LOG_ERR, "Service properties initialization " "failed."); break; default:
*** 341,355 **** } ndmpd.s_sigval = 0; } - (void) mutex_destroy(&ndmpd_zfs_fd_lock); libzfs_fini(zlibh); mod_fini(); ndmp_door_fini(); ! ndmp_log_close_file(); return (SMF_EXIT_OK); } static void --- 565,578 ---- } ndmpd.s_sigval = 0; } libzfs_fini(zlibh); mod_fini(); ndmp_door_fini(); ! closelog(); return (SMF_EXIT_OK); } static void