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