diff options
-rw-r--r-- | usr/src/cmd/ndmpd/Makefile | 8 | ||||
-rw-r--r-- | usr/src/cmd/ndmpd/ndmp/ndmpd.h | 132 | ||||
-rw-r--r-- | usr/src/cmd/ndmpd/ndmp/ndmpd_chkpnt.c | 13 | ||||
-rw-r--r-- | usr/src/cmd/ndmpd/ndmp/ndmpd_comm.c | 62 | ||||
-rw-r--r-- | usr/src/cmd/ndmpd/ndmp/ndmpd_common.h | 6 | ||||
-rw-r--r-- | usr/src/cmd/ndmpd/ndmp/ndmpd_config.c | 77 | ||||
-rw-r--r-- | usr/src/cmd/ndmpd/ndmp/ndmpd_data.c | 355 | ||||
-rw-r--r-- | usr/src/cmd/ndmpd/ndmp/ndmpd_fhistory.c | 6 | ||||
-rw-r--r-- | usr/src/cmd/ndmpd/ndmp/ndmpd_main.c | 5 | ||||
-rw-r--r-- | usr/src/cmd/ndmpd/ndmp/ndmpd_mover.c | 29 | ||||
-rw-r--r-- | usr/src/cmd/ndmpd/ndmp/ndmpd_tar.c | 42 | ||||
-rw-r--r-- | usr/src/cmd/ndmpd/ndmp/ndmpd_tar3.c | 54 | ||||
-rw-r--r-- | usr/src/cmd/ndmpd/ndmp/ndmpd_util.c | 11 | ||||
-rw-r--r-- | usr/src/cmd/ndmpd/ndmp/ndmpd_zfs.c | 2336 | ||||
-rw-r--r-- | usr/src/cmd/ndmpd/tlm/tlm_lib.c | 64 | ||||
-rw-r--r-- | usr/src/lib/libndmp/common/libndmp.h | 16 |
16 files changed, 2970 insertions, 246 deletions
diff --git a/usr/src/cmd/ndmpd/Makefile b/usr/src/cmd/ndmpd/Makefile index 2abd24753a..710650aaf4 100644 --- a/usr/src/cmd/ndmpd/Makefile +++ b/usr/src/cmd/ndmpd/Makefile @@ -1,6 +1,5 @@ # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # # @@ -81,18 +80,19 @@ NDMP_OBJ = \ ndmpd_data.o \ ndmpd_door.o \ ndmpd_dtime.o \ - ndmpd_prop.o \ ndmpd_fhistory.o \ ndmpd_handler.o \ ndmpd_log.o \ ndmpd_main.o \ ndmpd_mark.o \ ndmpd_mover.o \ + ndmpd_prop.o \ ndmpd_scsi.o \ ndmpd_tape.o \ ndmpd_tar.o \ ndmpd_tar3.o \ - ndmpd_util.o + ndmpd_util.o \ + ndmpd_zfs.o TLM_OBJ = \ tlm_backup_reader.o \ diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd.h b/usr/src/cmd/ndmpd/ndmp/ndmpd.h index 4ebb2455de..d63113ba20 100644 --- a/usr/src/cmd/ndmpd/ndmp/ndmpd.h +++ b/usr/src/cmd/ndmpd/ndmp/ndmpd.h @@ -1,6 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -114,15 +113,16 @@ typedef void *(*funct_t)(void *); /* function pointer */ #define ROOT_INODE 2 /* - * NDMP backup image signature. + * NDMP backup image signature */ #define NDMPUTF8MAGIC "NDMPUTF8MAGIC" /* * Supported BU types */ -#define NDMP_DUMP_TYPE "dump" #define NDMP_TAR_TYPE "tar" +#define NDMP_DUMP_TYPE "dump" +#define NDMP_ZFS_TYPE "zfs" /* All 1's binary maximum mover window */ #define MAX_WINDOW_SIZE 0xffffffffffffffffULL @@ -284,7 +284,6 @@ typedef struct mem_ndmp_name_v3 { ndmp_error nm3_err; } mem_ndmp_name_v3_t; - typedef struct ndmpd_file_handler { int fh_fd; ulong_t fh_mode; @@ -427,6 +426,76 @@ typedef struct ndmpd_session_file_history_v3 { ulong_t fh_dir_name_buf_index; } ndmpd_session_file_history_v3_t; +/* + * zfs-based backup (zfs send/recv) + */ + +typedef enum { + NDMPD_ZFS_MAJOR_0, +} ndmpd_zfs_major_t; + +typedef enum { + NDMPD_ZFS_MINOR_0, +} ndmpd_zfs_minor_t; + +typedef enum { + NDMPD_ZFS_PROP_MAJOR_0, +} ndmpd_zfs_prop_major_t; + +typedef enum { + NDMPD_ZFS_PROP_MINOR_0, +} ndmpd_zfs_prop_minor_t; + +#define NDMPD_ZFS_MAJOR_VERSION NDMPD_ZFS_MAJOR_0 +#define NDMPD_ZFS_MINOR_VERSION NDMPD_ZFS_MINOR_0 +#define NDMPD_ZFS_PROP_MAJOR_VERSION NDMPD_ZFS_PROP_MAJOR_0 +#define NDMPD_ZFS_PROP_MINOR_VERSION NDMPD_ZFS_PROP_MINOR_0 + +#pragma pack(1) +typedef struct { + char nzh_magic[14]; /* NDMPUTF8MAGIC\0 */ + uint32_t nzh_major; /* major version */ + uint32_t nzh_minor; /* minor version */ + uint32_t nzh_hdrlen; /* length of hdr in bytes including magic */ + /* future extensions */ +} ndmpd_zfs_header_t; +#pragma pack() + +#define PIPE_TAPE 0 +#define PIPE_ZFS 1 + +#define NDMPD_ZFS_DMP_NAME_MAX 32 + +typedef struct ndmpd_zfs_args { + zfs_type_t nz_type; /* type of ZFS dataset */ + char nz_dataset[ZFS_MAXNAMELEN]; /* dataset name */ + char nz_snapname[ZFS_MAXNAMELEN]; /* snapname (following '@') */ + char nz_fromsnap[ZFS_MAXNAMELEN]; /* snap of L-1 bkup */ + char nz_snapprop[ZFS_MAXPROPLEN]; /* contents of snap incr prop */ + boolean_t nz_ndmpd_snap; /* ndmpd-generated snap? */ + + pthread_t nz_sendrecv_thread; /* thread for send/recv */ + pthread_t nz_tape_thread; /* thread for tape r/w */ + int32_t nz_pipe_fd[2]; /* pipe for above 2 threads */ + int32_t nz_bufsize; /* tape r/w buf size */ + int64_t nz_window_len; /* DMA window length */ + + int nz_level; /* val of LEVEL env var */ + char nz_zfs_mode; /* val of ZFS_MODE env var */ + boolean_t nz_zfs_force; /* val of ZFS_FORCE env var */ + boolean_t nz_update; /* val of UPDATE env var */ + char nz_dmp_name[NDMPD_ZFS_DMP_NAME_MAX]; /* val of DMP_NAME env var */ + + ndmpd_module_params_t nz_params; + ndmp_lbr_params_t *nz_nlp; + libzfs_handle_t *nz_zlibh; /* session-specific lzfs hdl */ + ndmp_context_t nz_nctx; /* used by plugin */ + + ndmpd_zfs_header_t nz_tape_header; /* tape hdr for "zfs" backup */ +} ndmpd_zfs_args_t; + +#define ndmpd_zfs_params (&(ndmpd_zfs_args)->nz_params) + typedef struct ndmpd_session { ndmp_connection_t *ns_connection; /* NDMP connection to client */ boolean_t ns_eof; /* connection EOF flag */ @@ -439,6 +508,8 @@ typedef struct ndmpd_session { ndmpd_file_handler_t *ns_file_handler_list; /* for I/O multiplexing */ int ns_nref; ndmp_lbr_params_t *ns_ndmp_lbr_params; + struct ndmpd_zfs_args ns_ndmpd_zfs_args; + ndmpd_backup_type_t ns_butype; mutex_t ns_lock; /* @@ -911,7 +982,6 @@ extern ndmp_error ndmp_restore_get_params_v3(ndmpd_session_t *, ndmpd_module_params_t *); extern ndmp_error ndmp_backup_get_params_v3(ndmpd_session_t *, ndmpd_module_params_t *); -extern char *get_bk_path_v3(ndmpd_module_params_t *); /* * door init and fini function from ndmpd_door_serv.c @@ -938,11 +1008,11 @@ extern void ndmpd_abort_marking_v2(ndmpd_session_t *); extern int ndmpd_mark_inodes_v3(ndmpd_session_t *, ndmp_lbr_params_t *); extern ndmp_lbr_params_t *ndmp_get_nlp(void *); -module_start_func_t ndmpd_tar_backup_starter; -module_abort_func_t ndmpd_tar_backup_abort; +module_start_func_t ndmpd_tar_backup_starter; +module_abort_func_t ndmpd_tar_backup_abort; -module_start_func_t ndmpd_tar_restore_starter; -module_abort_func_t ndmpd_tar_restore_abort; +module_start_func_t ndmpd_tar_restore_starter; +module_abort_func_t ndmpd_tar_restore_abort; module_start_func_t ndmpd_tar_backup_starter_v3; module_abort_func_t ndmpd_tar_backup_abort_v3; @@ -969,8 +1039,8 @@ extern int tcp_get_peer(int, unsigned int *, int *); extern char *gethostaddr(void); extern int tlm_init(void); -extern int chkpnt_backup_successful(char *, char *); -extern int chkpnt_backup_prepare(char *, char *); +extern int chkpnt_backup_successful(char *, char *, boolean_t, int *); +extern int chkpnt_backup_prepare(char *, char *, boolean_t); extern boolean_t fs_is_chkpntvol(char *); extern boolean_t fs_is_chkpnt_enabled(char *); @@ -1005,4 +1075,42 @@ extern struct sasd_drive *sasd_drive(int); extern void *ndmp_malloc(size_t size); extern ndmp_plugin_t *ndmp_pl; + +#define NDMP_APILOG(s, t, m, ...) \ +{ \ + if (((ndmpd_session_t *)(s))->ns_protocol_version == NDMPV4) \ + (void) ndmpd_api_log_v4(s, t, m, __VA_ARGS__); \ + else if (((ndmpd_session_t *)(s))->ns_protocol_version == NDMPV3) \ + (void) ndmpd_api_log_v3(s, t, m, __VA_ARGS__); \ + else \ + (void) ndmpd_api_log_v2(s, __VA_ARGS__); \ +} + +/* + * Backup path utility functions + */ +extern char *get_backup_path_v3(ndmpd_module_params_t *); +extern char *get_backup_path_v2(ndmpd_module_params_t *); + +/* + * Functions for zfs-based backup + */ + +module_start_func_t ndmpd_zfs_backup_starter; +module_start_func_t ndmpd_zfs_restore_starter; +module_abort_func_t ndmpd_zfs_abort; + +int ndmpd_zfs_init(ndmpd_session_t *); +void ndmpd_zfs_fini(ndmpd_zfs_args_t *); + +boolean_t ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t *); +boolean_t ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t *); + +int ndmpd_zfs_pre_backup(ndmpd_zfs_args_t *); +int ndmpd_zfs_pre_restore(ndmpd_zfs_args_t *); +int ndmpd_zfs_post_backup(ndmpd_zfs_args_t *); +int ndmpd_zfs_post_restore(ndmpd_zfs_args_t *); + +void ndmpd_zfs_dma_log(ndmpd_zfs_args_t *, ndmp_log_type, char *, ...); + #endif /* _NDMPD_H */ diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_chkpnt.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_chkpnt.c index bc3cd8d3cc..d47bc38d25 100644 --- a/usr/src/cmd/ndmpd/ndmp/ndmpd_chkpnt.c +++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_chkpnt.c @@ -1,6 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -111,7 +110,7 @@ ndmp_has_backup_chkpnt(char *volname, char *jobname) } chkp.chp_found = 0; - (void) snprintf(chname, ZFS_MAXNAMELEN, "@bk-%s", jobname); + (void) snprintf(chname, ZFS_MAXNAMELEN, "@%s", jobname); chkp.chp_name = chname; (void) zfs_iter_snapshots(zhp, ndmp_has_backup, &chkp); @@ -255,8 +254,10 @@ ndmp_start_check_point(char *vol_name, char *jname) * removed before using it. */ if (ndmp_has_backup_chkpnt(vol, jname)) - (void) chkpnt_backup_successful(vol, jname); - if ((erc = chkpnt_backup_prepare(vol, jname)) < 0) + (void) chkpnt_backup_successful(vol, jname, B_FALSE, + NULL); + if ((erc = chkpnt_backup_prepare(vol, jname, B_FALSE)) + < 0) (void) ndmp_remove_chk_pnt_vol(vol); } @@ -289,7 +290,7 @@ ndmp_release_check_point(char *vol_name, char *jname) return (0); if (ndmp_remove_chk_pnt_vol(vol) == 0) - erc = chkpnt_backup_successful(vol, jname); + erc = chkpnt_backup_successful(vol, jname, B_FALSE, NULL); return (erc); } diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_comm.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_comm.c index 31b54bfa2c..13e4de9a16 100644 --- a/usr/src/cmd/ndmpd/ndmp/ndmpd_comm.c +++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_comm.c @@ -1,6 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -1653,3 +1652,62 @@ ndmp_malloc(size_t size) return (data); } + +/* + * get_backup_path_v3 + * + * Get the backup path from the NDMP environment variables. + * + * Parameters: + * params (input) - pointer to the parameters structure. + * + * Returns: + * The backup path: if anything is specified + * NULL: Otherwise + */ +char * +get_backup_path_v3(ndmpd_module_params_t *params) +{ + char *bkpath; + + bkpath = MOD_GETENV(params, "PREFIX"); + if (!bkpath) + bkpath = MOD_GETENV(params, "FILESYSTEM"); + + + if (!bkpath) { + MOD_LOGV3(params, NDMP_LOG_ERROR, + "Backup path not defined.\n"); + } else { + NDMP_LOG(LOG_DEBUG, "bkpath: \"%s\"", bkpath); + } + + return (bkpath); +} + +/* + * get_backup_path + * + * Find the backup path from the environment variables (v2) + */ +char * +get_backup_path_v2(ndmpd_module_params_t *params) +{ + char *bkpath; + + bkpath = MOD_GETENV(params, "PREFIX"); + if (bkpath == NULL) + bkpath = MOD_GETENV(params, "FILESYSTEM"); + + if (bkpath == NULL) { + MOD_LOG(params, "Error: restore path not specified.\n"); + return (NULL); + } + + if (*bkpath != '/') { + MOD_LOG(params, "Error: relative backup path not allowed.\n"); + return (NULL); + } + + return (bkpath); +} diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_common.h b/usr/src/cmd/ndmpd/ndmp/ndmpd_common.h index 0b2a75593b..5617da10e8 100644 --- a/usr/src/cmd/ndmpd/ndmp/ndmpd_common.h +++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_common.h @@ -1,6 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -64,6 +63,7 @@ #define INT_MAXCMD 12 extern mutex_t log_lock; +extern mutex_t ndmpd_zfs_fd_lock; /* Connection data structure. */ typedef struct msg_info { @@ -277,6 +277,6 @@ extern int ndmp_log_msg_id; /* * Module function prototypes. */ -typedef int module_start_func_t(ndmpd_module_params_t *); +typedef int module_start_func_t(void *); typedef int module_abort_func_t(void *); #endif /* _NDMP_COMMON_H */ diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_config.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_config.c index 751d798f28..d794fe2fa3 100644 --- a/usr/src/cmd/ndmpd/ndmp/ndmpd_config.c +++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_config.c @@ -1,6 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -429,15 +428,21 @@ void ndmpd_config_get_butype_info_v3(ndmp_connection_t *connection, void *body) { ndmp_config_get_butype_info_reply_v3 reply; - ndmp_butype_info info[2]; + ndmp_butype_info info[3]; ndmp_pval envs[8]; ulong_t attrs; ndmp_pval *envp = envs; + ndmp_pval zfs_envs[9]; + ulong_t zfs_attrs; + ndmp_pval *zfs_envp = zfs_envs; + (void) memset((void*)&reply, 0, sizeof (reply)); /* - * Supported environment variables and their default values. + * Supported environment variables and their default values + * for dump and tar. + * * The environment variables for dump and tar format are the * same, because we use the same backup engine for both. */ @@ -473,6 +478,31 @@ ndmpd_config_get_butype_info_v3(ndmp_connection_t *connection, void *body) info[1].default_env.default_env_val = envs; info[1].attrs = attrs; + /* + * Supported environment variables and their default values + * for type "zfs." + */ + + NDMP_SETENV(zfs_envp, "PREFIX", ""); + NDMP_SETENV(zfs_envp, "FILESYSTEM", ""); + NDMP_SETENV(zfs_envp, "TYPE", "zfs"); + NDMP_SETENV(zfs_envp, "HIST", "n"); + NDMP_SETENV(zfs_envp, "LEVEL", "0"); + NDMP_SETENV(zfs_envp, "ZFS_MODE", "recursive"); + NDMP_SETENV(zfs_envp, "ZFS_FORCE", "FALSE"); + NDMP_SETENV(zfs_envp, "UPDATE", "TRUE"); + NDMP_SETENV(zfs_envp, "DMP_NAME", "level"); + + zfs_attrs = NDMP_BUTYPE_BACKUP_UTF8 | + NDMP_BUTYPE_RECOVER_UTF8 | + NDMP_BUTYPE_BACKUP_INCREMENTAL; + + /* zfs backup type */ + info[2].butype_name = "zfs"; + info[2].default_env.default_env_len = ARRAY_LEN(zfs_envs, ndmp_pval); + info[2].default_env.default_env_val = zfs_envs; + info[2].attrs = zfs_attrs; + reply.error = NDMP_NO_ERR; reply.butype_info.butype_info_len = ARRAY_LEN(info, ndmp_butype_info); reply.butype_info.butype_info_val = info; @@ -899,15 +929,23 @@ void ndmpd_config_get_butype_info_v4(ndmp_connection_t *connection, void *body) { ndmp_config_get_butype_info_reply_v4 reply; - ndmp_butype_info info[2]; + ndmp_butype_info info[3]; + ndmp_pval envs[12]; ulong_t attrs; ndmp_pval *envp = envs; + ndmp_pval zfs_envs[11]; + ulong_t zfs_attrs; + ndmp_pval *zfs_envp = zfs_envs; + + (void) memset((void*)&reply, 0, sizeof (reply)); /* - * Supported environment variables and their default values. + * Supported environment variables and their default values + * for dump and tar. + * * The environment variables for dump and tar format are the * same, because we use the same backup engine for both. */ @@ -950,6 +988,33 @@ ndmpd_config_get_butype_info_v4(ndmp_connection_t *connection, void *body) info[1].default_env.default_env_val = envs; info[1].attrs = attrs; + /* + * Supported environment variables and their default values + * for type "zfs." + */ + + NDMP_SETENV(zfs_envp, "USER", ""); + NDMP_SETENV(zfs_envp, "CMD", ""); + NDMP_SETENV(zfs_envp, "FILESYSTEM", ""); + NDMP_SETENV(zfs_envp, "PATHNAME_SEPARATOR", "/"); + NDMP_SETENV(zfs_envp, "TYPE", "zfs"); + NDMP_SETENV(zfs_envp, "HIST", "n"); + NDMP_SETENV(zfs_envp, "LEVEL", "0"); + NDMP_SETENV(zfs_envp, "ZFS_MODE", "recursive"); + NDMP_SETENV(zfs_envp, "ZFS_FORCE", "n"); + NDMP_SETENV(zfs_envp, "UPDATE", "y"); + NDMP_SETENV(zfs_envp, "DMP_NAME", "level"); + + zfs_attrs = NDMP_BUTYPE_BACKUP_UTF8 | + NDMP_BUTYPE_RECOVER_UTF8 | + NDMP_BUTYPE_BACKUP_INCREMENTAL; + + /* zfs backup type */ + info[2].butype_name = "zfs"; + info[2].default_env.default_env_len = ARRAY_LEN(zfs_envs, ndmp_pval); + info[2].default_env.default_env_val = zfs_envs; + info[2].attrs = zfs_attrs; + reply.error = NDMP_NO_ERR; reply.butype_info.butype_info_len = ARRAY_LEN(info, ndmp_butype_info); reply.butype_info.butype_info_val = info; diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_data.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_data.c index 9b471e469a..24f28f1dcc 100644 --- a/usr/src/cmd/ndmpd/ndmp/ndmpd_data.c +++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_data.c @@ -1,6 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -61,23 +60,18 @@ static ndmp_error data_connect_sock_v3(ndmpd_session_t *session, ulong_t addr, static int discard_data_v3(ndmpd_session_t *session, ulong_t length); static void nlp_release_job_stat(ndmpd_session_t *session); static u_longlong_t ndmpd_data_get_info(ndmpd_session_t *session); -static ndmp_error start_backup_v3(ndmpd_session_t *session, char *bu_type, - ndmp_pval *env_val, ulong_t env_len); -static ndmp_error start_backup(ndmpd_session_t *session, char *bu_type, - ndmp_pval *env_val, ulong_t env_len); -static ndmp_error start_recover(ndmpd_session_t *session, char *bu_type, - ndmp_pval *env_val, ulong_t env_len, ndmp_name *nlist_val, - ulong_t nlist_len); -static ndmp_error start_recover_v3(ndmpd_session_t *session, char *bu_type, - ndmp_pval *env_val, ulong_t env_len, ndmp_name_v3 *nlist_val, - ulong_t nlist_len); -static ndmp_error start_backup(ndmpd_session_t *session, char *bu_type, - ndmp_pval *env_val, ulong_t env_len); -static ndmp_error start_recover(ndmpd_session_t *session, char *bu_type, - ndmp_pval *env_val, ulong_t env_len, ndmp_name *nlist_val, - ulong_t nlist_len); -static u_longlong_t ndmpd_data_get_info(ndmpd_session_t *session); -static void nlp_release_job_stat(ndmpd_session_t *session); + +static ndmp_error ndmpd_tar_start_backup_v2(ndmpd_session_t *, char *, + ndmp_pval *, ulong_t); +static ndmp_error ndmpd_tar_start_recover_v2(ndmpd_session_t *, char *, + ndmp_pval *, ulong_t, ndmp_name *, ulong_t); +static ndmp_error ndmpd_tar_start_backup_v3(ndmpd_session_t *, char *, + ndmp_pval *, ulong_t); +static ndmp_error ndmpd_tar_start_recover_v3(ndmpd_session_t *, + ndmp_pval *, ulong_t, ndmp_name_v3 *, ulong_t); + +static ndmp_error ndmpd_zfs_start_op(ndmpd_session_t *, + ndmp_pval *, ulong_t, ndmp_name_v3 *, ulong_t, enum ndmp_data_operation); /* @@ -153,8 +147,8 @@ ndmpd_data_start_backup_v2(ndmp_connection_t *connection, void *body) reply.error = NDMP_NO_ERR; session->ns_data.dd_mover = request->mover; - err = start_backup(session, request->bu_type, request->env.env_val, - request->env.env_len); + err = ndmpd_tar_start_backup_v2(session, request->bu_type, + request->env.env_val, request->env.env_len); /* * start_backup sends the reply if the backup is successfully started. @@ -169,7 +163,6 @@ ndmpd_data_start_backup_v2(ndmp_connection_t *connection, void *body) } } - /* * ndmpd_data_start_recover_v2 * @@ -193,9 +186,10 @@ ndmpd_data_start_recover_v2(ndmp_connection_t *connection, void *body) request = (ndmp_data_start_recover_request_v2 *) body; session->ns_data.dd_mover = request->mover; - err = start_recover(session, request->bu_type, request->env.env_val, - request->env.env_len, request->nlist.nlist_val, - request->nlist.nlist_len); + err = ndmpd_tar_start_recover_v2(session, request->bu_type, + request->env.env_val, request->env.env_len, + request->nlist.nlist_val, request->nlist.nlist_len); + /* * start_recover sends the reply if the recover is successfully started. * Otherwise, send the reply containing the error here. @@ -208,7 +202,6 @@ ndmpd_data_start_recover_v2(ndmp_connection_t *connection, void *body) } } - /* * ndmpd_data_get_env_v2 * @@ -401,29 +394,78 @@ ndmpd_data_start_backup_v3(ndmp_connection_t *connection, void *body) ndmp_data_start_backup_request_v3 *request; ndmp_data_start_backup_reply_v3 reply; ndmpd_session_t *session = ndmp_get_client_data(connection); - ndmp_error err; request = (ndmp_data_start_backup_request_v3 *)body; (void) memset((void*)&reply, 0, sizeof (reply)); - err = start_backup_v3(session, request->bu_type, request->env.env_val, - request->env.env_len); + if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) { + NDMP_LOG(LOG_ERR, + "Can't start new backup in current state."); + NDMP_LOG(LOG_ERR, + "Connection to the mover is not established."); + reply.error = NDMP_ILLEGAL_STATE_ERR; + goto _error; + } + + if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) { + if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) { + NDMP_LOG(LOG_ERR, "Write protected device."); + reply.error = NDMP_WRITE_PROTECT_ERR; + goto _error; + } + } + + if (strcasecmp(request->bu_type, NDMP_TAR_TYPE) == 0) { + session->ns_butype = NDMP_BUTYPE_TAR; + } else if (strcasecmp(request->bu_type, NDMP_DUMP_TYPE) == 0) { + session->ns_butype = NDMP_BUTYPE_DUMP; + } else if (strcasecmp(request->bu_type, NDMP_ZFS_TYPE) == 0) { + session->ns_butype = NDMP_BUTYPE_ZFS; + } else { + char msg_invalid[32]; + char msg_types[32]; + + (void) snprintf(msg_invalid, 32, "Invalid backup type: %s.", + request->bu_type); + (void) snprintf(msg_types, 32, + "Supported backup types are tar, dump, and zfs."); + + NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id, + msg_invalid); + NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id, + msg_types); + NDMP_LOG(LOG_ERR, msg_invalid); + NDMP_LOG(LOG_ERR, msg_types); + + reply.error = NDMP_ILLEGAL_ARGS_ERR; + goto _error; + } + + if (session->ns_butype == NDMP_BUTYPE_ZFS) { + reply.error = ndmpd_zfs_start_op(session, request->env.env_val, + request->env.env_len, NULL, 0, NDMP_DATA_OP_BACKUP); + } else { + reply.error = ndmpd_tar_start_backup_v3(session, + request->bu_type, request->env.env_val, + request->env.env_len); + } /* - * start_backup_v3 sends the reply if the backup is + * *_start_backup* sends the reply if the backup is * successfully started. Otherwise, send the reply * containing the error here. */ - if (err != NDMP_NO_ERR) { - reply.error = err; + +_error: + + if (reply.error != NDMP_NO_ERR) { ndmp_send_reply(connection, &reply, "sending data_start_backup_v3 reply"); ndmpd_data_cleanup(session); } } - /* * ndmpd_data_start_recover_v3 * @@ -442,23 +484,62 @@ ndmpd_data_start_recover_v3(ndmp_connection_t *connection, void *body) ndmp_data_start_recover_request_v3 *request; ndmp_data_start_recover_reply_v3 reply; ndmpd_session_t *session = ndmp_get_client_data(connection); - ndmp_error err; request = (ndmp_data_start_recover_request_v3 *)body; (void) memset((void*)&reply, 0, sizeof (reply)); - err = start_recover_v3(session, request->bu_type, request->env.env_val, - request->env.env_len, request->nlist.nlist_val, - request->nlist.nlist_len); + if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) { + NDMP_LOG(LOG_ERR, "Can't start new recover in current state."); + reply.error = NDMP_ILLEGAL_STATE_ERR; + goto _error; + } + + if (strcasecmp(request->bu_type, NDMP_TAR_TYPE) == 0) { + session->ns_butype = NDMP_BUTYPE_TAR; + } else if (strcasecmp(request->bu_type, NDMP_DUMP_TYPE) == 0) { + session->ns_butype = NDMP_BUTYPE_DUMP; + } else if (strcasecmp(request->bu_type, NDMP_ZFS_TYPE) == 0) { + session->ns_butype = NDMP_BUTYPE_ZFS; + } else { + char msg_invalid[32]; + char msg_types[32]; + + (void) snprintf(msg_invalid, 32, "Invalid backup type: %s.", + request->bu_type); + (void) snprintf(msg_types, 32, + "Supported backup types are tar, dump, and zfs."); + + NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id, + msg_invalid); + NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id, + msg_types); + NDMP_LOG(LOG_ERR, msg_invalid); + NDMP_LOG(LOG_ERR, msg_types); + + reply.error = NDMP_ILLEGAL_ARGS_ERR; + goto _error; + } + + if (session->ns_butype == NDMP_BUTYPE_ZFS) { + reply.error = ndmpd_zfs_start_op(session, request->env.env_val, + request->env.env_len, request->nlist.nlist_val, + request->nlist.nlist_len, NDMP_DATA_OP_RECOVER); + } else { + reply.error = ndmpd_tar_start_recover_v3(session, + request->env.env_val, request->env.env_len, + request->nlist.nlist_val, request->nlist.nlist_len); + } /* - * start_recover_v3 sends the reply if the recover is + * *_start_recover* sends the reply if the recover is * successfully started. Otherwise, send the reply * containing the error here. */ - if (err != NDMP_NO_ERR) { - reply.error = err; + +_error: + + if (reply.error != NDMP_NO_ERR) { ndmp_send_reply(connection, &reply, "sending data_start_recover_v3 reply"); ndmpd_data_error(session, NDMP_DATA_HALT_INTERNAL_ERROR); @@ -466,7 +547,6 @@ ndmpd_data_start_recover_v3(ndmp_connection_t *connection, void *body) } } - /* * ndmpd_data_abort_v3 * @@ -1281,23 +1361,23 @@ data_connect_sock_v3(ndmpd_session_t *session, ulong_t addr, ushort_t port) /* - * start_backup_v3 + * ndmpd_tar_start_backup_v3 * * Start the backup work * * Parameters: - * session (input) - session pointer. - * bu_type (input) - backup type. - * env_val (input) - environment variable array. - * env_len (input) - length of env_val. + * session (input) - session pointer. + * bu_type (input) - backup type. + * env_val (input) - environment variable array. + * env_len (input) - length of env_val. * * Returns: * NDMP_NO_ERR - backup successfully started. * otherwise - error code of backup start error. */ static ndmp_error -start_backup_v3(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val, - ulong_t env_len) +ndmpd_tar_start_backup_v3(ndmpd_session_t *session, char *bu_type, + ndmp_pval *env_val, ulong_t env_len) { int err; ndmp_lbr_params_t *nlp; @@ -1306,28 +1386,6 @@ start_backup_v3(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val, (void) memset((void*)&reply, 0, sizeof (reply)); - if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) { - NDMP_LOG(LOG_ERR, - "Can't start new backup in current state."); - NDMP_LOG(LOG_ERR, - "Connection to the mover is not established."); - return (NDMP_ILLEGAL_STATE_ERR); - } - - if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) { - if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) { - NDMP_LOG(LOG_ERR, "Write protected device."); - return (NDMP_WRITE_PROTECT_ERR); - } - } - - if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 && - strcmp(bu_type, NDMP_TAR_TYPE) != 0) { - NDMP_LOG(LOG_ERR, "Invalid backup type: %s.", bu_type); - NDMP_LOG(LOG_ERR, "Supported backup types are tar and dump."); - return (NDMP_ILLEGAL_ARGS_ERR); - } - err = ndmpd_save_env(session, env_val, env_len); if (err != NDMP_NO_ERR) return (err); @@ -1414,7 +1472,7 @@ start_backup_v3(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val, /* * perform the backup * - * Cannot wait for the thread to exit as we are replying the + * Cannot wait for the thread to exit as we are replying to the * client request here. */ err = pthread_create(NULL, NULL, @@ -1428,25 +1486,27 @@ start_backup_v3(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val, return (NDMP_NO_ERR); } - /* - * start_recover_v3 + * ndmpd_tar_start_recover_v3 * * Start the restore work * * Parameters: - * session (input) - session pointer. + * session (input) - session pointer. * bu_type (input) - backup type. * env_val (input) - environment variable array. * env_len (input) - length of env_val. + * nlist_val (input) - list of files. + * nlist_len (input) - length of nlist_val. * * Returns: * NDMP_NO_ERR - recover successfully started. * otherwise - error code of recover start error. */ static ndmp_error -start_recover_v3(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val, - ulong_t env_len, ndmp_name_v3 *nlist_val, ulong_t nlist_len) +ndmpd_tar_start_recover_v3(ndmpd_session_t *session, + ndmp_pval *env_val, ulong_t env_len, ndmp_name_v3 *nlist_val, + ulong_t nlist_len) { ndmp_data_start_recover_reply_v3 reply; ndmpd_module_params_t *params; @@ -1455,17 +1515,6 @@ start_recover_v3(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val, (void) memset((void*)&reply, 0, sizeof (reply)); - if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) { - NDMP_LOG(LOG_ERR, "Can't start new recover in current state."); - return (NDMP_ILLEGAL_STATE_ERR); - } - if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 && - strcmp(bu_type, NDMP_TAR_TYPE) != 0) { - NDMP_LOG(LOG_ERR, "Invalid backup type: %s.", bu_type); - NDMP_LOG(LOG_ERR, "Supported backup types are tar and dump."); - return (NDMP_ILLEGAL_ARGS_ERR); - } - nlp = ndmp_get_nlp(session); NDMP_FREE(nlp->nlp_params); params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t)); @@ -1566,6 +1615,115 @@ start_recover_v3(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val, return (NDMP_NO_ERR); } +static ndmp_error +ndmpd_zfs_start_op(ndmpd_session_t *session, ndmp_pval *env_val, + ulong_t env_len, ndmp_name_v3 *nlist_val, ulong_t nlist_len, + enum ndmp_data_operation op) +{ + ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args; + ndmp_data_start_backup_reply_v3 backup_reply; + ndmp_data_start_recover_reply_v3 recover_reply; + pthread_t tid; + void *reply; + char str[8]; + int err; + + if (ndmpd_zfs_init(session) != 0) + return (NDMP_UNDEFINED_ERR); + + err = ndmpd_save_env(session, env_val, env_len); + if (err != NDMP_NO_ERR) { + ndmpd_zfs_fini(ndmpd_zfs_args); + return (err); + } + + switch (op) { + case NDMP_DATA_OP_BACKUP: + if (!ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args)) { + ndmpd_zfs_fini(ndmpd_zfs_args); + return (NDMP_ILLEGAL_ARGS_ERR); + } + + if (ndmpd_zfs_pre_backup(ndmpd_zfs_args)) { + NDMP_LOG(LOG_ERR, "pre_backup error"); + return (NDMP_ILLEGAL_ARGS_ERR); + } + + session->ns_data.dd_module.dm_start_func = + ndmpd_zfs_backup_starter; + (void) strlcpy(str, "backup", 8); + break; + case NDMP_DATA_OP_RECOVER: + err = ndmpd_save_nlist_v3(session, nlist_val, nlist_len); + if (err != NDMP_NO_ERR) { + ndmpd_zfs_fini(ndmpd_zfs_args); + return (NDMP_NO_MEM_ERR); + } + + if (!ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args)) { + ndmpd_zfs_fini(ndmpd_zfs_args); + return (NDMP_ILLEGAL_ARGS_ERR); + } + + if (ndmpd_zfs_pre_restore(ndmpd_zfs_args)) { + NDMP_LOG(LOG_ERR, "pre_restore error"); + (void) ndmpd_zfs_post_restore(ndmpd_zfs_args); + return (NDMP_ILLEGAL_ARGS_ERR); + } + session->ns_data.dd_module.dm_start_func = + ndmpd_zfs_restore_starter; + (void) strlcpy(str, "recover", 8); + break; + } + + ndmpd_zfs_params->mp_operation = op; + session->ns_data.dd_operation = op; + session->ns_data.dd_module.dm_abort_func = ndmpd_zfs_abort; + session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE; + session->ns_data.dd_abort = FALSE; + + if (op == NDMP_DATA_OP_BACKUP) { + (void) memset((void*)&backup_reply, 0, sizeof (backup_reply)); + backup_reply.error = NDMP_NO_ERR; + reply = &backup_reply; + } else { + (void) memset((void*)&recover_reply, 0, sizeof (recover_reply)); + recover_reply.error = NDMP_NO_ERR; + reply = &recover_reply; + } + + if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR, + reply) < 0) { + NDMP_LOG(LOG_DEBUG, "Sending data_start_%s_v3 reply", str); + if (op == NDMP_DATA_OP_RECOVER) + ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR); + ndmpd_zfs_fini(ndmpd_zfs_args); + return (NDMP_NO_ERR); + } + + err = pthread_create(&tid, NULL, + (funct_t)session->ns_data.dd_module.dm_start_func, ndmpd_zfs_args); + + if (err) { + NDMP_LOG(LOG_ERR, "Can't start %s session (errno %d)", + str, err); + ndmpd_zfs_fini(ndmpd_zfs_args); + MOD_DONE(ndmpd_zfs_params, -1); + return (NDMP_NO_ERR); + } + + (void) pthread_detach(tid); + + if (op == NDMP_DATA_OP_BACKUP) + NS_INC(nbk); + else + NS_INC(nrs); + + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_NORMAL, + "'zfs' %s starting\n", str); + + return (NDMP_NO_ERR); +} /* * discard_data_v3 @@ -1886,7 +2044,7 @@ ndmp_data_get_mover_mode(ndmpd_session_t *session) NDMP_ADDR_TCP)) ? "remote" : "local"); break; default: - rv = "Uknonwn"; + rv = "Unknown"; NDMP_LOG(LOG_ERR, "Invalid protocol version %d.", session->ns_protocol_version); } @@ -1897,7 +2055,7 @@ ndmp_data_get_mover_mode(ndmpd_session_t *session) /* *** static functions ******************************************** */ /* - * start_backup + * ndmpd_tar_start_backup_v2 * * Request handling code common to version 1 and * version 2 data_start_backup request handlers. @@ -1913,8 +2071,8 @@ ndmp_data_get_mover_mode(ndmpd_session_t *session) * otherwise - error code of backup start error. */ static ndmp_error -start_backup(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val, - ulong_t env_len) +ndmpd_tar_start_backup_v2(ndmpd_session_t *session, char *bu_type, + ndmp_pval *env_val, ulong_t env_len) { ndmp_data_start_backup_reply reply; ndmpd_module_params_t *params; @@ -2043,9 +2201,8 @@ start_backup(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val, return (NDMP_NO_ERR); } - /* - * start_recover + * ndmpd_tar_start_recover_v2 * * The main recover/restore function * @@ -2054,16 +2211,17 @@ start_backup(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val, * bu_type (input) - backup type. * env_val (input) - environment variable array. * env_len (input) - length of env_val. - * nlist_val (input) - list of files - * nlist_len (input) - length of nlist_val + * nlist_val (input) - list of files. + * nlist_len (input) - length of nlist_val. * * Returns: * NDMP_NO_ERR - recover successfully started. * otherwise - error code of backup start error. */ static ndmp_error -start_recover(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val, - ulong_t env_len, ndmp_name *nlist_val, ulong_t nlist_len) +ndmpd_tar_start_recover_v2(ndmpd_session_t *session, char *bu_type, + ndmp_pval *env_val, ulong_t env_len, ndmp_name *nlist_val, + ulong_t nlist_len) { ndmp_data_start_recover_reply_v2 reply; ndmpd_module_params_t *params; @@ -2170,7 +2328,7 @@ start_recover(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val, /* * perform the restore * - * Cannot wait for the thread to exit as we are replying the + * Cannot wait for the thread to exit as we are replying to the * client request here. */ (void) pthread_create(NULL, NULL, @@ -2180,7 +2338,6 @@ start_recover(ndmpd_session_t *session, char *bu_type, ndmp_pval *env_val, return (NDMP_NO_ERR); } - /* * ndmpd_data_get_info * diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_fhistory.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_fhistory.c index c316444dcf..4315457621 100644 --- a/usr/src/cmd/ndmpd/ndmp/ndmpd_fhistory.c +++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_fhistory.c @@ -1,6 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -769,7 +768,8 @@ ndmpd_fhpath_v3_cb(lbr_fhlog_call_backs_t *cbp, char *path, struct stat64 *stp, if (!params || !params->mp_file_history_path_func) { err = -1; } else { - char *p = ndmp_get_relative_path(get_bk_path_v3(params), + char *p = + ndmp_get_relative_path(get_backup_path_v3(params), path); if ((err = ndmpd_api_file_history_file_v3(cbp-> fh_cookie, p, stp, off)) < 0) diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c index d4d332873a..b87eb49ff8 100644 --- a/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c +++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c @@ -1,6 +1,5 @@ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -283,6 +282,7 @@ main(int argc, char *argv[]) openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON); (void) mutex_init(&log_lock, 0, NULL); + (void) mutex_init(&ndmpd_zfs_fd_lock, 0, NULL); if (mod_init() != 0) { syslog(LOG_ERR, "Failed to load the plugin module."); @@ -339,6 +339,7 @@ main(int argc, char *argv[]) ndmpd.s_sigval = 0; } + (void) mutex_destroy(&ndmpd_zfs_fd_lock); (void) mutex_destroy(&log_lock); libzfs_fini(zlibh); mod_fini(); diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_mover.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_mover.c index 5ca0ea4174..7f3f4bb3a6 100644 --- a/usr/src/cmd/ndmpd/ndmp/ndmpd_mover.c +++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_mover.c @@ -1,6 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -99,16 +98,6 @@ int ndmp_max_mover_recsize = MAX_MOVER_RECSIZE; /* patchable */ #define TAPE_READ_ERR -1 #define TAPE_NO_WRITER_ERR -2 -#define NDMP_APILOG(s, t, m, ...) \ -{ \ - if (((ndmpd_session_t *)(s))->ns_protocol_version == NDMPV4) \ - (void) ndmpd_api_log_v4(s, t, m, __VA_ARGS__); \ - else if (((ndmpd_session_t *)(s))->ns_protocol_version == NDMPV3) \ - (void) ndmpd_api_log_v3(s, t, m, __VA_ARGS__); \ - else \ - (void) ndmpd_api_log_v2(s, __VA_ARGS__); \ -} - /* * ************************************************************************ * NDMP V2 HANDLERS @@ -1608,7 +1597,7 @@ ndmpd_local_read(ndmpd_session_t *session, char *data, ulong_t length) return (-1); } /* - * Wait for until the state is changed by + * Wait until the state is changed by * an abort or continue request. */ nlp_ref_nw(session); @@ -3351,6 +3340,10 @@ start_mover_for_backup(ndmpd_session_t *session) * Returns: * 0: not started * non-zero: started + * Note: non-zero is also returned if the backup type is + * neither TAR nor DUMP. I.e. the is_writer_running() + * check does not apply in this case and things should + * appear successful. */ static boolean_t is_writer_running(ndmpd_session_t *session) @@ -3358,6 +3351,9 @@ is_writer_running(ndmpd_session_t *session) boolean_t rv; ndmp_lbr_params_t *nlp; + if (session && (session->ns_butype > NDMP_BUTYPE_DUMP)) + return (1); + if (session == NULL) rv = 0; else if ((nlp = ndmp_get_nlp(session)) == NULL) @@ -3380,6 +3376,10 @@ is_writer_running(ndmpd_session_t *session) * Returns: * 0: not started * non-zero: started + * Note: non-zero is also returned if the backup type is + * neither TAR nor DUMP. I.e. the is_writer_running() + * check does not apply in this case and things should + * appear successful. */ static boolean_t is_writer_running_v3(ndmpd_session_t *session) @@ -3387,6 +3387,9 @@ is_writer_running_v3(ndmpd_session_t *session) boolean_t rv; ndmp_lbr_params_t *nlp; + if (session && (session->ns_butype > NDMP_BUTYPE_DUMP)) + return (1); + if (session == NULL) rv = 0; else if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP) diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_tar.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_tar.c index dd91065cac..ac71943834 100644 --- a/usr/src/cmd/ndmpd/ndmp/ndmpd_tar.c +++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_tar.c @@ -1,6 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -36,6 +35,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ +/* Copyright (c) 2007, The Storage Networking Industry Association. */ /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */ #include <sys/stat.h> @@ -1432,34 +1432,6 @@ prefixdir(char *dir, char *suffix) /* - * get_backup_path - * - * Find the backup path from the environment variables - */ -static char * -get_backup_path(ndmpd_module_params_t *params) -{ - char *bkpath; - - bkpath = MOD_GETENV(params, "PREFIX"); - if (bkpath == NULL) - bkpath = MOD_GETENV(params, "FILESYSTEM"); - - if (bkpath == NULL) { - MOD_LOG(params, "Error: restore path not specified.\n"); - return (NULL); - } - - if (*bkpath != '/') { - MOD_LOG(params, "Error: relative backup path not allowed.\n"); - return (NULL); - } - - return (bkpath); -} - - -/* * get_nfiles * * Get the count of files to be restored @@ -1664,7 +1636,7 @@ ndmp_backup_extract_params(ndmpd_session_t *session, MOD_LOG(params, "Error: Internal error: nlp == NULL.\n"); return (NDMP_ILLEGAL_ARGS_ERR); } - if ((nlp->nlp_backup_path = get_backup_path(params)) == NULL) + if ((nlp->nlp_backup_path = get_backup_path_v2(params)) == NULL) return (NDMP_FILE_NOT_FOUND_ERR); if ((rv = check_backup_dir_validity(params, @@ -1834,7 +1806,7 @@ ndmp_restore_extract_params(ndmpd_session_t *session, } /* Extract directory from where the backup was made. */ - if ((bkpath = get_backup_path(params)) == NULL) + if ((bkpath = get_backup_path_v2(params)) == NULL) return (NDMP_ILLEGAL_ARGS_ERR); nlp->nlp_restore_bk_path = bkpath; @@ -1892,8 +1864,9 @@ ndmp_restore_extract_params(ndmpd_session_t *session, * and release the snapshot at the end. */ int -ndmpd_tar_backup_starter(ndmpd_module_params_t *mod_params) +ndmpd_tar_backup_starter(void *arg) { + ndmpd_module_params_t *mod_params = arg; int err; ndmpd_session_t *session; ndmp_lbr_params_t *nlp; @@ -1998,8 +1971,9 @@ ndmpd_tar_backup_abort(void *module_cookie) */ int -ndmpd_tar_restore_starter(ndmpd_module_params_t *mod_params) +ndmpd_tar_restore_starter(void *arg) { + ndmpd_module_params_t *mod_params = arg; int err; ndmpd_session_t *session; ndmp_lbr_params_t *nlp; diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_tar3.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_tar3.c index b29b5a332b..19b3e0ef2d 100644 --- a/usr/src/cmd/ndmpd/ndmp/ndmpd_tar3.c +++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_tar3.c @@ -1,6 +1,5 @@ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -36,6 +35,8 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ +/* Copyright (c) 2007, The Storage Networking Industry Association. */ +/* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */ #include <sys/stat.h> #include <sys/types.h> #include <sys/time.h> @@ -625,39 +626,6 @@ voliswr(char *path) /* - * get_bk_path_v3 - * - * Get the backup path from the NDMP environment variables. - * - * Parameters: - * params (input) - pointer to the parameters structure. - * - * Returns: - * The backup path: if anything is specified - * NULL: Otherwise - */ -char * -get_bk_path_v3(ndmpd_module_params_t *params) -{ - char *bkpath; - - bkpath = MOD_GETENV(params, "PREFIX"); - if (!bkpath) - bkpath = MOD_GETENV(params, "FILESYSTEM"); - - - if (!bkpath) { - MOD_LOGV3(params, NDMP_LOG_ERROR, - "Backup path not defined.\n"); - } else { - NDMP_LOG(LOG_DEBUG, "bkpath: \"%s\"", bkpath); - } - - return (bkpath); -} - - -/* * is_valid_backup_dir_v3 * * Checks the validity of the backup path. Backup path should @@ -2454,6 +2422,7 @@ tar_backup_v3(ndmpd_session_t *session, ndmpd_module_params_t *params, nctx.nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH); nctx.nc_cmds = cmds; nctx.nc_params = params; + nctx.nc_ddata = (void *) session; if ((err = ndmp_pl->np_pre_backup(ndmp_pl, &nctx, nlp->nlp_backup_path)) != 0) { NDMP_LOG(LOG_ERR, "Pre-backup plug-in: %m"); @@ -3231,8 +3200,10 @@ ndmpd_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params, /* Plug-in module */ if (ndmp_pl != NULL && ndmp_pl->np_pre_restore != NULL) { + (void) memset(&nctx, 0, sizeof (ndmp_context_t)); nctx.nc_cmds = cmds; nctx.nc_params = params; + nctx.nc_ddata = (void *) session; ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, dar_index - 1); @@ -3487,7 +3458,6 @@ get_absolute_path(const char *bkpath) return (rv); } - /* * Expands the format string and logs the resulting message to the * remote DMA @@ -3591,8 +3561,10 @@ ndmpd_rs_sar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params, /* Plug-in module */ if (ndmp_pl != NULL && ndmp_pl->np_pre_restore != NULL) { + (void) memset(&nctx, 0, sizeof (ndmp_context_t)); nctx.nc_cmds = cmds; nctx.nc_params = params; + nctx.nc_ddata = (void *) session; if ((err = ndmp_plugin_pre_restore(&nctx, params, nlp->nlp_nfiles)) != 0) { @@ -3703,7 +3675,7 @@ ndmp_backup_get_params_v3(ndmpd_session_t *session, "Internal error: NULL nlp.\n"); rv = NDMP_ILLEGAL_ARGS_ERR; } else { - if (!(nlp->nlp_backup_path = get_bk_path_v3(params))) + if (!(nlp->nlp_backup_path = get_backup_path_v3(params))) rv = NDMP_FILE_NOT_FOUND_ERR; else if (!is_valid_backup_dir_v3(params, nlp->nlp_backup_path)) rv = NDMP_ILLEGAL_ARGS_ERR; @@ -3766,8 +3738,9 @@ ndmp_backup_get_params_v3(ndmpd_session_t *session, * != 0: otherwise */ int -ndmpd_tar_backup_starter_v3(ndmpd_module_params_t *params) +ndmpd_tar_backup_starter_v3(void *arg) { + ndmpd_module_params_t *params = arg; int err; ndmpd_session_t *session; ndmp_lbr_params_t *nlp; @@ -3888,7 +3861,7 @@ ndmp_restore_get_params_v3(ndmpd_session_t *session, if (!(nlp = ndmp_get_nlp(session))) { NDMP_LOG(LOG_DEBUG, "nlp is NULL"); rv = NDMP_ILLEGAL_ARGS_ERR; - } else if (!(nlp->nlp_backup_path = get_bk_path_v3(params))) + } else if (!(nlp->nlp_backup_path = get_backup_path_v3(params))) rv = NDMP_ILLEGAL_ARGS_ERR; else if ((nlp->nlp_nfiles = session->ns_data.dd_nlist_len) == 0) { NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles); @@ -3943,8 +3916,9 @@ ndmp_restore_get_params_v3(ndmpd_session_t *session, * != NDMP_NO_ERR: otherwise */ int -ndmpd_tar_restore_starter_v3(ndmpd_module_params_t *params) +ndmpd_tar_restore_starter_v3(void *arg) { + ndmpd_module_params_t *params = arg; int err; ndmpd_session_t *session; ndmp_lbr_params_t *nlp; diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_util.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_util.c index 80a08e55a8..2769147231 100644 --- a/usr/src/cmd/ndmpd/ndmp/ndmpd_util.c +++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_util.c @@ -1,6 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -2742,3 +2741,11 @@ ndmp_context_get_specific(ndmp_context_t *nctx) { return (nctx->nc_pldata); } + +ndmpd_backup_type_t +ndmp_get_backup_type(ndmp_context_t *ctx) +{ + ndmpd_session_t *session = (ndmpd_session_t *)ctx->nc_ddata; + + return (session->ns_butype); +} diff --git a/usr/src/cmd/ndmpd/ndmp/ndmpd_zfs.c b/usr/src/cmd/ndmpd/ndmp/ndmpd_zfs.c new file mode 100644 index 0000000000..6a57828a24 --- /dev/null +++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_zfs.c @@ -0,0 +1,2336 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* + * BSD 3 Clause License + * + * Copyright (c) 2007, The Storage Networking Industry Association. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * - Neither the name of The Storage Networking Industry Association (SNIA) + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* Copyright (c) 2007, The Storage Networking Industry Association. */ +/* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/lwp.h> +#include <sys/fs/zfs.h> +#include <sys/mtio.h> +#include <sys/time.h> +#include <unistd.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <libzfs.h> +#include <stdio.h> +#include "ndmpd_common.h" +#include "ndmpd.h" + +typedef struct { + char nzs_findprop[ZFS_MAXPROPLEN]; /* prop substring to find */ + char nzs_snapname[ZFS_MAXNAMELEN]; /* snap's name */ + char nzs_snapprop[ZFS_MAXPROPLEN]; /* snap's prop value */ + char nzs_snapskip[ZFS_MAXPROPLEN]; /* snap to skip */ + uint32_t nzs_prop_major; /* property major version */ + uint32_t nzs_prop_minor; /* property minor version */ +} ndmpd_zfs_snapfind_t; + +mutex_t ndmpd_zfs_fd_lock; + +static int ndmpd_zfs_open_fds(ndmpd_zfs_args_t *); +static void ndmpd_zfs_close_fds(ndmpd_zfs_args_t *); + +static void ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t *, int); + +static int ndmpd_zfs_header_write(ndmpd_session_t *); +static int ndmpd_zfs_header_read(ndmpd_zfs_args_t *); + +static int ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t *); +static int ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t *); + +static int ndmpd_zfs_restore(ndmpd_zfs_args_t *); +static int ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t *); +static int ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t *); + +static int ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *, int **, int **); + +static int ndmpd_zfs_is_spanning(ndmpd_zfs_args_t *); + +static boolean_t ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *); +static int ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *, char *, int); +static int ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *); + +static boolean_t ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *); +static int ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *); +static int ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *); + +static int ndmpd_zfs_getenv(ndmpd_zfs_args_t *); +static int ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *); +static int ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *); +static int ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *); +static int ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *); +static int ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *); +static boolean_t ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *, char *); +static boolean_t ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *); + +static int ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *); +static int ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *, int); +static int ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *); +static int ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *, + boolean_t, ndmpd_zfs_snapfind_t *); +static boolean_t ndmpd_zfs_snapshot_ndmpd_generated(char *); +static int ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *, ndmpd_zfs_snapfind_t *); + +static int ndmpd_zfs_snapshot_prop_find(zfs_handle_t *, void *); +static int ndmpd_zfs_snapshot_prop_get(zfs_handle_t *, char *); +static int ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *); +static int ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *, char *, + boolean_t *); +static int ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *, char *, int, + boolean_t); +static int ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *, + ndmpd_zfs_snapfind_t *); +static boolean_t ndmpd_zfs_prop_version_check(char *, uint32_t *, uint32_t *); + +static int ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *, char *, int); + +static void ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *); + +static int ndmpd_zfs_backup(ndmpd_zfs_args_t *); + +#define snapshot_create chkpnt_backup_prepare +#define snapshot_destroy chkpnt_backup_successful + +/* + * Syntax for com.sun.ndmp:incr property value: + * #.#.n|u/$LEVEL.$DMP_NAME.$ZFS_MODE(/ ...) + * + * where + * #.# is the version number + * 'n' means ndmp-generated; 'u' means user-supplied + * $LEVEL: backup (incremental) level [0-9] + * $DMP_NAME: set name [default: "level"] + * $ZFS_MODE: d | r | p [for dataset, recursive, or package] + * + * Examples: + * + * 0.0.n/0.bob.p + * 0.0.u/1.bob.p/0.jane.d + */ + +#define NDMPD_ZFS_PROP_INCR "com.sun.ndmp:incr" + +/* + * NDMPD_ZFS_LOG_ZERR + * + * As coded, there should be no races in the retrieval of the ZFS errno + * from the ndmpd_zfs_args->nz_zlibh. I.e., for a given ndmpd_zfs backup + * or restore, there should only ever be one ZFS library call taking place + * at any one moment in time. + */ + +#define NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, ...) { \ + NDMP_LOG(LOG_ERR, __VA_ARGS__); \ + NDMP_LOG(LOG_ERR, "%s--%s", \ + libzfs_error_action((ndmpd_zfs_args)->nz_zlibh), \ + libzfs_error_description((ndmpd_zfs_args)->nz_zlibh)); \ + ndmpd_zfs_zerr_dma_log((ndmpd_zfs_args)); \ +} + +int +ndmpd_zfs_init(ndmpd_session_t *session) +{ + ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args; + int version = session->ns_protocol_version; + + bzero(ndmpd_zfs_args, sizeof (*ndmpd_zfs_args)); + + if ((version < NDMPV3) || (version > NDMPV4)) { + NDMP_LOG(LOG_ERR, "Unknown or unsupported version %d", version); + return (-1); + } + + if ((ndmpd_zfs_args->nz_zlibh = libzfs_init()) == NULL) { + NDMP_LOG(LOG_ERR, "libzfs init error [%d]", errno); + return (-1); + } + + if (ndmpd_zfs_open_fds(ndmpd_zfs_args) < 0) { + NDMP_LOG(LOG_ERR, "open_fds() failure(): %d\n", errno); + return (-1); + } + + ndmpd_zfs_args->nz_bufsize = ndmp_buffer_get_size(session); + ndmpd_zfs_args->nz_window_len = session->ns_mover.md_window_length; + + ndmpd_zfs_args->nz_nlp = ndmp_get_nlp(session); + + assert(ndmpd_zfs_args->nz_nlp != NULL); + + ndmpd_zfs_args->nz_nlp->nlp_bytes_total = 0; + + session->ns_data.dd_module.dm_module_cookie = ndmpd_zfs_args; + session->ns_data.dd_data_size = 0; + session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0; + session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0; + + session->ns_data.dd_bytes_left_to_read = 0; + session->ns_data.dd_position = 0; + session->ns_data.dd_discard_length = 0; + session->ns_data.dd_read_offset = 0; + session->ns_data.dd_read_length = 0; + + ndmpd_zfs_params->mp_get_env_func = ndmpd_api_get_env; + ndmpd_zfs_params->mp_add_env_func = ndmpd_api_add_env; + ndmpd_zfs_params->mp_set_env_func = ndmpd_api_set_env; + ndmpd_zfs_params->mp_dispatch_func = ndmpd_api_dispatch; + ndmpd_zfs_params->mp_daemon_cookie = (void *)session; + ndmpd_zfs_params->mp_protocol_version = session->ns_protocol_version; + ndmpd_zfs_params->mp_stats = &session->ns_data.dd_module.dm_stats; + ndmpd_zfs_params->mp_add_file_handler_func = + ndmpd_api_add_file_handler; + ndmpd_zfs_params->mp_remove_file_handler_func = + ndmpd_api_remove_file_handler; + ndmpd_zfs_params->mp_seek_func = 0; + + switch (version) { + case NDMPV3: + ndmpd_zfs_params->mp_write_func = ndmpd_api_write_v3; + ndmpd_zfs_params->mp_read_func = ndmpd_api_read_v3; + ndmpd_zfs_params->mp_get_name_func = ndmpd_api_get_name_v3; + ndmpd_zfs_params->mp_done_func = ndmpd_api_done_v3; + ndmpd_zfs_params->mp_log_func_v3 = ndmpd_api_log_v3; + ndmpd_zfs_params->mp_file_recovered_func = + ndmpd_api_file_recovered_v3; + break; + case NDMPV4: + ndmpd_zfs_params->mp_write_func = ndmpd_api_write_v3; + ndmpd_zfs_params->mp_read_func = ndmpd_api_read_v3; + ndmpd_zfs_params->mp_get_name_func = ndmpd_api_get_name_v3; + ndmpd_zfs_params->mp_done_func = ndmpd_api_done_v3; + ndmpd_zfs_params->mp_log_func_v3 = ndmpd_api_log_v4; + ndmpd_zfs_params->mp_file_recovered_func = + ndmpd_api_file_recovered_v4; + break; + default: + /* error already returned above for this case */ + break; + } + + return (0); +} + +void +ndmpd_zfs_fini(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + libzfs_fini(ndmpd_zfs_args->nz_zlibh); + + ndmpd_zfs_close_fds(ndmpd_zfs_args); +} + +static int +ndmpd_zfs_open_fds(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + int err; + + err = pipe(ndmpd_zfs_args->nz_pipe_fd); + if (err) + NDMP_LOG(LOG_ERR, "pipe(2) failed: %s:\n", strerror(errno)); + + return (err); +} + +/* + * ndmpd_zfs_close_fds() + * + * In the abort case, use dup2() to redirect the end of the pipe that is + * being written to (to a new pipe). Close the ends of the new pipe to cause + * EPIPE to be returned to the writing thread. This will cause the writer + * and reader to terminate without having any of the writer's data erroneously + * go to any reopened descriptor. + */ + +static void +ndmpd_zfs_close_fds(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + ndmpd_session_t *session = (ndmpd_session_t *) + (ndmpd_zfs_params->mp_daemon_cookie); + int pipe_end; + int fds[2]; + + if (session->ns_data.dd_state != NDMP_DATA_STATE_ACTIVE) { + ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS); + ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE); + return; + } + + (void) mutex_lock(&ndmpd_zfs_fd_lock); + + if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP) { + pipe_end = PIPE_ZFS; + } else { + pipe_end = PIPE_TAPE; + } + + if (ndmpd_zfs_args->nz_pipe_fd[pipe_end] != -1) { + if (pipe(fds) != 0) { + (void) mutex_unlock(&ndmpd_zfs_fd_lock); + NDMP_LOG(LOG_ERR, "pipe(2) failed: %s:\n", + strerror(errno)); + return; + } + + (void) dup2(fds[0], ndmpd_zfs_args->nz_pipe_fd[pipe_end]); + (void) close(fds[0]); + (void) close(fds[1]); + + ndmpd_zfs_args->nz_pipe_fd[pipe_end] = -1; + } + + (void) mutex_unlock(&ndmpd_zfs_fd_lock); +} + +static void +ndmpd_zfs_close_one_fd(ndmpd_zfs_args_t *ndmpd_zfs_args, int pipe_end) +{ + (void) mutex_lock(&ndmpd_zfs_fd_lock); + (void) close(ndmpd_zfs_args->nz_pipe_fd[pipe_end]); + ndmpd_zfs_args->nz_pipe_fd[pipe_end] = -1; + (void) mutex_unlock(&ndmpd_zfs_fd_lock); +} + +static int +ndmpd_zfs_header_write(ndmpd_session_t *session) +{ + ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args; + int32_t bufsize = ndmpd_zfs_args->nz_bufsize; + ndmpd_zfs_header_t *tape_header = &ndmpd_zfs_args->nz_tape_header; + char *buf; + + buf = ndmp_malloc(bufsize); + if (buf == NULL) { + NDMP_LOG(LOG_DEBUG, "buf NULL"); + return (-1); + } + + (void) strlcpy(tape_header->nzh_magic, NDMPUTF8MAGIC, + sizeof (NDMPUTF8MAGIC)); + tape_header->nzh_major = LE_32(NDMPD_ZFS_MAJOR_VERSION); + tape_header->nzh_minor = LE_32(NDMPD_ZFS_MINOR_VERSION); + tape_header->nzh_hdrlen = LE_32(bufsize); + + bzero(buf, bufsize); + (void) memcpy(buf, tape_header, sizeof (ndmpd_zfs_header_t)); + + NDMP_LOG(LOG_DEBUG, "header (major, minor, length): %u %u %u", + NDMPD_ZFS_MAJOR_VERSION, + NDMPD_ZFS_MINOR_VERSION, + bufsize); + + if (MOD_WRITE(ndmpd_zfs_params, buf, bufsize) != 0) { + free(buf); + NDMP_LOG(LOG_ERR, "MOD_WRITE error"); + return (-1); + } + + free(buf); + + session->ns_data.dd_module.dm_stats.ms_bytes_processed = bufsize; + + return (0); +} + +static int +ndmpd_zfs_header_read(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + int32_t bufsize = ndmpd_zfs_args->nz_bufsize; + ndmpd_zfs_header_t *tape_header = &ndmpd_zfs_args->nz_tape_header; + uint32_t hdrlen; + int32_t header_left; + int err; + char *buf; + + buf = ndmp_malloc(bufsize); + if (buf == NULL) { + NDMP_LOG(LOG_DEBUG, "buf NULL"); + return (-1); + } + + bzero(buf, bufsize); + + /* + * Read nz_bufsize worth of bytes first (the size of a mover record). + */ + + err = MOD_READ(ndmpd_zfs_params, buf, bufsize); + + if (err != 0) { + NDMP_LOG(LOG_ERR, "MOD_READ error: %d", err); + free(buf); + return (-1); + } + + (void) memcpy(tape_header, buf, sizeof (ndmpd_zfs_header_t)); + + + if (strcmp(tape_header->nzh_magic, NDMPUTF8MAGIC) != 0) { + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "bad magic string\n"); + goto _err; + } + + if (tape_header->nzh_major > LE_32(NDMPD_ZFS_MAJOR_VERSION)) { + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "major number larger than supported: (%d %d)\n", + LE_32(tape_header->nzh_major), NDMPD_ZFS_MAJOR_VERSION); + goto _err; + } + + /* + * Major version 0 (regardless of minor version): + * Header must be a multiple of the mover record size. + */ + + hdrlen = LE_32(tape_header->nzh_hdrlen); + if (hdrlen > bufsize) { + header_left = hdrlen - bufsize; + while (header_left > 0) { + err = MOD_READ(ndmpd_zfs_params, buf, bufsize); + if (err == -1) { + ndmpd_zfs_dma_log(ndmpd_zfs_args, + NDMP_LOG_ERROR, "bad header\n"); + goto _err; + } + header_left -= bufsize; + } + } + + NDMP_LOG(LOG_DEBUG, "tape header: %s; %u %u; %u ", + tape_header->nzh_magic, + LE_32(tape_header->nzh_major), + LE_32(tape_header->nzh_minor), + LE_32(tape_header->nzh_hdrlen)); + + ndmpd_zfs_args->nz_nlp->nlp_bytes_total = hdrlen; + + free(buf); + return (0); + +_err: + + NDMP_LOG(LOG_ERR, "tape header: %s; %u %u; %u ", + tape_header->nzh_magic, + LE_32(tape_header->nzh_major), + LE_32(tape_header->nzh_minor), + LE_32(tape_header->nzh_hdrlen)); + + free(buf); + return (-1); +} + +int +ndmpd_zfs_backup_starter(void *arg) +{ + ndmpd_zfs_args_t *ndmpd_zfs_args = arg; + ndmpd_session_t *session = (ndmpd_session_t *) + (ndmpd_zfs_params->mp_daemon_cookie); + int cleanup_err = 0; + int err = 0; + + ndmp_session_ref(session); + + if (ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args) != 0) { + err = -1; + goto _done; + } + + err = ndmpd_zfs_backup(ndmpd_zfs_args); + + cleanup_err = ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args, err); + + NDMP_LOG(LOG_DEBUG, + "data bytes_total(including header):%llu", + session->ns_data.dd_module.dm_stats.ms_bytes_processed); + + err |= cleanup_err; + +_done: + NS_DEC(nbk); + MOD_DONE(ndmpd_zfs_params, err ? err : cleanup_err); + ndmp_session_unref(session); + ndmpd_zfs_fini(ndmpd_zfs_args); + + return (err); +} + +static int +ndmpd_zfs_backup(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + ndmpd_session_t *session = (ndmpd_session_t *) + (ndmpd_zfs_params->mp_daemon_cookie); + int *read_err = NULL; + int *write_err = NULL; + int result = 0; + int err; + + if (session->ns_eof) + return (-1); + + if (!session->ns_data.dd_abort) { + if (ndmpd_zfs_header_write(session)) { + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "ndmpd_zfs header write error\n"); + return (-1); + } + + err = ndmpd_zfs_reader_writer(ndmpd_zfs_args, + &read_err, &write_err); + + if (err || read_err || write_err || session->ns_eof) + result = EPIPE; + } + + if (session->ns_data.dd_abort) { + ndmpd_audit_backup(session->ns_connection, + ndmpd_zfs_args->nz_dataset, + session->ns_data.dd_data_addr.addr_type, + ndmpd_zfs_args->nz_dataset, EINTR); + NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.", + ndmpd_zfs_args->nz_dataset); + + (void) ndmpd_zfs_post_backup(ndmpd_zfs_args); + err = -1; + } else { + ndmpd_audit_backup(session->ns_connection, + ndmpd_zfs_args->nz_dataset, + session->ns_data.dd_data_addr.addr_type, + ndmpd_zfs_args->nz_dataset, result); + + err = ndmpd_zfs_post_backup(ndmpd_zfs_args); + if (err || result) + err = -1; + + if (err == 0) { + NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" finished.", + ndmpd_zfs_args->nz_dataset); + } else { + NDMP_LOG(LOG_DEBUG, "An error occurred while backing up" + " \"%s\"", ndmpd_zfs_args->nz_dataset); + } + } + + return (err); +} + +/* + * ndmpd_zfs_backup_send_read() + * + * This routine executes zfs_send() to create the backup data stream. + * The value of ZFS_MODE determines the type of zfs_send(): + * dataset ('d'): Only the dataset specified (i.e., top level) is backed up + * recursive ('r'): The dataset and its child file systems are backed up + * package ('p'): Same as 'r', except all intermediate snapshots are also + * backed up + * + * Volumes do not have descednants, so 'd' and 'r' produce equivalent results. + */ + +static int +ndmpd_zfs_backup_send_read(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + ndmpd_session_t *session = (ndmpd_session_t *) + (ndmpd_zfs_params->mp_daemon_cookie); + sendflags_t flags = { 0 }; + char *fromsnap = NULL; + zfs_handle_t *zhp; + int err; + + zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, + ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type); + + if (!zhp) { + if (!session->ns_data.dd_abort) + NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open"); + return (-1); + } + + switch (ndmpd_zfs_args->nz_zfs_mode) { + case ('d'): + flags.props = B_TRUE; + break; + case ('r'): + flags.replicate = B_TRUE; + break; + case ('p'): + flags.doall = B_TRUE; + flags.replicate = B_TRUE; + break; + default: + NDMP_LOG(LOG_ERR, "unknown zfs_mode: %c", + ndmpd_zfs_args->nz_zfs_mode); + zfs_close(zhp); + return (-1); + } + + if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) { + if (ndmpd_zfs_args->nz_fromsnap[0] == '\0') { + NDMP_LOG(LOG_ERR, "no fromsnap"); + zfs_close(zhp); + return (-1); + } + fromsnap = ndmpd_zfs_args->nz_fromsnap; + } + + err = zfs_send(zhp, fromsnap, ndmpd_zfs_args->nz_snapname, flags, + ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL, NULL); + + if (err && !session->ns_data.dd_abort) + NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_send: %d", err); + + zfs_close(zhp); + + return (err); +} + +/* + * ndmpd_zfs_backup_tape_write() + * + * The data begins on a mover record boundary (because + * the header is the size of a mover record--i.e. + * ndmpd_zfs_args->nz_bufsize). + */ + +static int +ndmpd_zfs_backup_tape_write(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + ndmpd_session_t *session = (ndmpd_session_t *) + (ndmpd_zfs_params->mp_daemon_cookie); + int bufsize = ndmpd_zfs_args->nz_bufsize; + u_longlong_t *bytes_totalp; + int count; + char *buf; + + buf = ndmp_malloc(bufsize); + if (buf == NULL) { + NDMP_LOG(LOG_DEBUG, "buf NULL"); + return (-1); + } + + bytes_totalp = + &(session->ns_data.dd_module.dm_stats.ms_bytes_processed); + + for (;;) { + bzero(buf, bufsize); + + count = read(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf, + bufsize); + + if (count == 0) /* EOF */ { + NDMP_LOG(LOG_DEBUG, + "zfs_send stream size: %llu bytes (sans header)", + *bytes_totalp - bufsize); + free(buf); + return (0); + } + + if (count == -1) { + NDMP_LOG(LOG_DEBUG, "pipe read error (errno %d)", + errno); + free(buf); + return (-1); + } + + if (MOD_WRITE(ndmpd_zfs_params, buf, count) != 0) { + (void) ndmpd_zfs_abort((void *) ndmpd_zfs_args); + NDMP_LOG(LOG_ERR, "MOD_WRITE error"); + free(buf); + return (-1); + } + + *bytes_totalp += count; + } + /* NOTREACHED */ +} + +int +ndmpd_zfs_restore_starter(void *arg) +{ + ndmpd_zfs_args_t *ndmpd_zfs_args = arg; + ndmpd_session_t *session = (ndmpd_session_t *) + (ndmpd_zfs_params->mp_daemon_cookie); + int err; + + ndmp_session_ref(session); + + err = ndmpd_zfs_restore(ndmpd_zfs_args); + + MOD_DONE(ndmpd_zfs_params, err); + + NS_DEC(nrs); + + ndmp_session_unref(session); + + ndmpd_zfs_fini(ndmpd_zfs_args); + + return (err); +} + +static int +ndmpd_zfs_restore(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + ndmpd_session_t *session = (ndmpd_session_t *) + (ndmpd_zfs_params->mp_daemon_cookie); + int *read_err = NULL; + int *write_err = NULL; + int result = 0; + int err; + + if (!session->ns_data.dd_abort) { + if (ndmpd_zfs_header_read(ndmpd_zfs_args)) { + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "ndmpd_zfs header read error\n"); + return (-1); + } + + err = ndmpd_zfs_reader_writer(ndmpd_zfs_args, + &write_err, &read_err); + + if (err || read_err || write_err || session->ns_eof) + result = EIO; + } + + if (session->ns_data.dd_abort) { + NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.", + ndmpd_zfs_args->nz_dataset); + ndmpd_audit_restore(session->ns_connection, + ndmpd_zfs_args->nz_dataset, + session->ns_data.dd_data_addr.addr_type, + ndmpd_zfs_args->nz_dataset, EINTR); + (void) ndmpd_zfs_post_restore(ndmpd_zfs_args); + err = -1; + } else { + ndmpd_audit_restore(session->ns_connection, + ndmpd_zfs_args->nz_dataset, + session->ns_data.dd_data_addr.addr_type, + ndmpd_zfs_args->nz_dataset, result); + err = ndmpd_zfs_post_restore(ndmpd_zfs_args); + if (err || result) + err = -1; + + if (err == 0) { + NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished", + ndmpd_zfs_args->nz_dataset); + } else { + NDMP_LOG(LOG_DEBUG, "An error occurred while restoring" + " to \"%s\"", ndmpd_zfs_args->nz_dataset); + } + } + + return (err); +} + +static int +ndmpd_zfs_restore_tape_read(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + ndmpd_session_t *session = (ndmpd_session_t *) + (ndmpd_zfs_params->mp_daemon_cookie); + int bufsize = ndmpd_zfs_args->nz_bufsize; + u_longlong_t *bytes_totalp; + char *buf; + int count; + int err; + + buf = ndmp_malloc(bufsize); + if (buf == NULL) { + NDMP_LOG(LOG_DEBUG, "buf NULL"); + return (-1); + } + + bytes_totalp = &ndmpd_zfs_args->nz_nlp->nlp_bytes_total; + + for (;;) { + err = MOD_READ(ndmpd_zfs_params, buf, bufsize); + + if (err == -1) { + NDMP_LOG(LOG_DEBUG, "end of data (%llu) bytes", + *bytes_totalp); + (void) write(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], + buf, bufsize); + break; + } + + count = write(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE], buf, + bufsize); + + if (count == -1) { + free(buf); + + if ((errno == EPIPE) && !session->ns_data.dd_abort) { + NDMP_LOG(LOG_DEBUG, "EPIPE; count == -1; " + "[%llu bytes] returning success", + *bytes_totalp); + return (0); + } + + if (session->ns_data.dd_abort) + NDMP_LOG(LOG_DEBUG, "abort set"); + + NDMP_LOG(LOG_DEBUG, "pipe write error:" + "errno: %d", errno); + + return (-1); + } + + *bytes_totalp += count; + + /* + * A short write to the pipe indicates the + * other peer is terminated so we should exit + */ + + if (count != bufsize) { + NDMP_LOG(LOG_DEBUG, "count != bufsize:" + "count: %d; bufsize: %d", + count, bufsize); + free(buf); + return (0); + } + + /* Checks for local mover */ + if (*bytes_totalp == ndmpd_zfs_args->nz_window_len) { + NDMP_LOG(LOG_DEBUG, "Reached EOW at %lld", + *bytes_totalp); + if (ndmpd_zfs_is_spanning(ndmpd_zfs_args) == 0) { + NDMP_LOG(LOG_DEBUG, "Exit"); + break; + } + NDMP_LOG(LOG_DEBUG, "Continue through spanning"); + } + } + + free(buf); + return (0); +} + +/* + * ndmpd_zfs_restore_recv_write() + * + * This routine executes zfs_receive() to restore the backup. + */ + +static int +ndmpd_zfs_restore_recv_write(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + ndmpd_session_t *session = (ndmpd_session_t *) + (ndmpd_zfs_params->mp_daemon_cookie); + recvflags_t flags; + int err; + + bzero(&flags, sizeof (recvflags_t)); + + flags.nomount = B_TRUE; + + if (ndmpd_zfs_args->nz_zfs_force) + flags.force = B_TRUE; + + err = zfs_receive(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset, + flags, ndmpd_zfs_args->nz_pipe_fd[PIPE_ZFS], NULL); + + if (err && !session->ns_data.dd_abort) + NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_receive: %d", err); + + return (err); +} + +/* + * ndmpd_zfs_is_spanning() + * + * Check to see if the tape is at spanning point + */ + +static int +ndmpd_zfs_is_spanning(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + ndmpd_session_t *session = (ndmpd_session_t *) + (ndmpd_zfs_params->mp_daemon_cookie); + int count = session->ns_mover.md_record_size; + char *buf; + + if ((buf = ndmp_malloc(count)) == NULL) + return (0); + + if (read(session->ns_tape.td_fd, buf, count) == 0) { + free(buf); + return (1); + } + + (void) ndmp_mtioctl(session->ns_tape.td_fd, MTBSR, 1); + free(buf); + return (0); +} + +/* + * ndmpd_zfs_reader_writer() + * + * Two separate threads are used for actual backup or restore. + */ + +static int +ndmpd_zfs_reader_writer(ndmpd_zfs_args_t *ndmpd_zfs_args, + int **sendrecv_errp, int **tape_errp) +{ + funct_t sendrecv_func; + funct_t tape_func; + int sendrecv_err; + int tape_err; + + switch (ndmpd_zfs_params->mp_operation) { + case NDMP_DATA_OP_BACKUP: + sendrecv_func = (funct_t)ndmpd_zfs_backup_send_read; + tape_func = (funct_t)ndmpd_zfs_backup_tape_write; + break; + case NDMP_DATA_OP_RECOVER: + sendrecv_func = (funct_t)ndmpd_zfs_restore_recv_write; + tape_func = (funct_t)ndmpd_zfs_restore_tape_read; + break; + } + + sendrecv_err = pthread_create(&ndmpd_zfs_args->nz_sendrecv_thread, + NULL, sendrecv_func, ndmpd_zfs_args); + + if (sendrecv_err == 0) { + tape_err = pthread_create(&ndmpd_zfs_args->nz_tape_thread, + NULL, tape_func, ndmpd_zfs_args); + + if (tape_err) { + /* + * The close of the tape side of the pipe will cause + * nz_sendrecv_thread to error in the zfs_send/recv() + * call and to return. Hence we do not need + * to explicitly cancel the sendrecv_thread here + * (the pthread_join() below is sufficient). + */ + + (void) close(ndmpd_zfs_args->nz_pipe_fd[PIPE_TAPE]); + NDMP_LOG(LOG_ERR, "Could not start tape thread; " + "aborting z-op"); + } + + (void) pthread_join(ndmpd_zfs_args->nz_sendrecv_thread, + (void **) sendrecv_errp); + } + + if ((tape_err == 0) && + (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_RECOVER)) + ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE); + + ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_ZFS); + + if ((sendrecv_err == 0) && (tape_err == 0)) { + (void) pthread_join(ndmpd_zfs_args->nz_tape_thread, + (void **) tape_errp); + } + + if ((tape_err == 0) && + (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP)) + ndmpd_zfs_close_one_fd(ndmpd_zfs_args, PIPE_TAPE); + + return (sendrecv_err ? sendrecv_err : tape_err); +} + +int +ndmpd_zfs_abort(void *arg) +{ + ndmpd_zfs_args_t *ndmpd_zfs_args = arg; + char str[8]; + + if (ndmpd_zfs_params->mp_operation == NDMP_DATA_OP_BACKUP) + (void) strlcpy(str, "backup", 8); + else + (void) strlcpy(str, "recover", 8); + + NDMP_LOG(LOG_ERR, "ndmpd_zfs_abort() called...aborting %s operation", + str); + + ndmpd_zfs_close_fds(ndmpd_zfs_args); + + return (0); +} + +/* + * ndmpd_zfs_pre_backup() + * + * Note: The memset to 0 of nctxp ensures that nctx->nc_cmds == NULL. + * This ensures that ndmp_include_zfs() will fail, which is + * a requirement for "zfs"-type backup. + */ + +int +ndmpd_zfs_pre_backup(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + ndmpd_session_t *session = (ndmpd_session_t *) + (ndmpd_zfs_params->mp_daemon_cookie); + ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx; + int err; + + if (ndmp_pl == NULL || ndmp_pl->np_pre_backup == NULL) + return (0); + + (void) memset(nctxp, 0, sizeof (ndmp_context_t)); + nctxp->nc_plversion = ndmp_pl->np_plversion; + nctxp->nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH); + nctxp->nc_ddata = (void *) session; + + err = ndmp_pl->np_pre_backup(ndmp_pl, nctxp, + ndmpd_zfs_args->nz_dataset); + + if (err != 0) { + NDMP_LOG(LOG_DEBUG, "Pre-backup plug-in: %m"); + (void) ndmpd_zfs_post_backup(ndmpd_zfs_args); + } + + return (err); +} + +int +ndmpd_zfs_post_backup(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx; + int err = 0; + + if (ndmp_pl == NULL || ndmp_pl->np_post_backup == NULL) + return (0); + + err = ndmp_pl->np_post_backup(ndmp_pl, nctxp, err); + + if (err == -1) + NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m"); + + return (err); +} + +int +ndmpd_zfs_pre_restore(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + ndmpd_session_t *session = (ndmpd_session_t *) + (ndmpd_zfs_params->mp_daemon_cookie); + ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx; + char bkpath[ZFS_MAXNAMELEN]; + int err; + + if (ndmp_pl == NULL || ndmp_pl->np_pre_restore == NULL) + return (0); + + err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, bkpath, ZFS_MAXNAMELEN); + + if (err != 0) { + NDMP_LOG(LOG_DEBUG, "error getting bkup path: %d", err); + return (-1); + } + + err = ndmpd_zfs_restore_getpath(ndmpd_zfs_args); + + if (err != 0) { + NDMP_LOG(LOG_DEBUG, "error getting restore path: %d", err); + return (-1); + } + + (void) memset(nctxp, 0, sizeof (ndmp_context_t)); + nctxp->nc_ddata = (void *) session; + + err = ndmp_pl->np_pre_restore(ndmp_pl, nctxp, bkpath, + ndmpd_zfs_args->nz_dataset); + + if (err != 0) { + NDMP_LOG(LOG_DEBUG, "Pre-restore plug-in: %m"); + return (-1); + } + + return (0); +} + +int +ndmpd_zfs_post_restore(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + ndmp_context_t *nctxp = &ndmpd_zfs_args->nz_nctx; + int err = 0; + + if (ndmp_pl == NULL || ndmp_pl->np_post_restore == NULL) + return (0); + + err = ndmp_pl->np_post_restore(ndmp_pl, nctxp, err); + + if (err == -1) + NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m"); + + return (err); +} + +boolean_t +ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + ndmpd_zfs_snapfind_t snapdata; + + if (ndmpd_zfs_backup_getenv(ndmpd_zfs_args) != 0) + return (B_FALSE); + + if (!ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args)) + return (B_FALSE); + + if (ndmpd_zfs_is_incremental(ndmpd_zfs_args)) { + (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args, + snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_TRUE); + + snapdata.nzs_snapname[0] = '\0'; + snapdata.nzs_snapprop[0] = '\0'; + + if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata)) + return (B_FALSE); + + if (snapdata.nzs_snapname[0] == '\0') { /* not found */ + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "Snapshot for level %d does not exist\n", + ndmpd_zfs_args->nz_level-1); + return (B_FALSE); + } + + (void) strlcpy(ndmpd_zfs_args->nz_fromsnap, + snapdata.nzs_snapname, ZFS_MAXNAMELEN); + } + + return (B_TRUE); +} + +/* + * ndmpd_zfs_backup_pathvalid() + * + * Make sure the path is of an existing dataset + */ + +static boolean_t +ndmpd_zfs_backup_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + char zpath[ZFS_MAXNAMELEN]; + char propstr[ZFS_MAXPROPLEN]; + zfs_handle_t *zhp; + zfs_type_t ztype = 0; + int err; + + if (ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath, ZFS_MAXNAMELEN) + != 0) + return (B_FALSE); + + if (ndmpd_zfs_args->nz_snapname[0] != '\0') { + zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, zpath, + ZFS_TYPE_SNAPSHOT); + + if (!zhp) { + NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, + "zfs_open (snap)"); + ndmpd_zfs_args->nz_snapname[0] = '\0'; + ndmpd_zfs_args->nz_dataset[0] = '\0'; + return (B_FALSE); + } + + err = ndmpd_zfs_snapshot_prop_get(zhp, propstr); + + zfs_close(zhp); + + if (err) { + NDMP_LOG(LOG_DEBUG, + "ndmpd_zfs_snapshot_prop_get failed"); + return (-1); + } + + if (propstr && ndmpd_zfs_snapshot_ndmpd_generated(propstr)) { + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "cannot use an ndmpd-generated snapshot\n"); + return (B_FALSE); + } + } + + zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, + ndmpd_zfs_args->nz_dataset, ZFS_TYPE_DATASET); + + if (zhp) { + ztype = zfs_get_type(zhp); + zfs_close(zhp); + } + + if ((ztype == ZFS_TYPE_VOLUME) || + (ztype == ZFS_TYPE_FILESYSTEM)) { + ndmpd_zfs_args->nz_type = ztype; + return (B_TRUE); + } + + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "Invalid file system or volume.\n"); + + return (B_FALSE); +} + +/* + * ndmpd_zfs_backup_getpath() + * + * Retrieve the backup path from the environment, which should + * be of the form "/dataset[@snap]". The leading slash is required + * by certain DMA's but can otherwise be ignored. + * + * (Note: "dataset" can consist of more than one component, + * e.g. "pool", "pool/volume", "pool/fs/fs2".) + * + * The dataset name and the snapshot name (if any) will be + * stored in ndmpd_zfs_args. + */ + +static int +ndmpd_zfs_backup_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args, char *zpath, + int zlen) +{ + char *env_path; + char *at; + + env_path = get_backup_path_v3(ndmpd_zfs_params); + if (env_path == NULL) + return (-1); + + if (env_path[0] != '/') { + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "Invalid path: %s (leading slash required)\n", env_path); + return (-1); + } + + (void) strlcpy(zpath, &env_path[1], zlen); + (void) strlcpy(ndmpd_zfs_args->nz_dataset, &env_path[1], + ZFS_MAXNAMELEN); + + at = strchr(ndmpd_zfs_args->nz_dataset, '@'); + if (at) { + *at = '\0'; + (void) strlcpy(ndmpd_zfs_args->nz_snapname, ++at, + ZFS_MAXNAMELEN); + } else { + ndmpd_zfs_args->nz_snapname[0] = '\0'; + } + + return (0); +} + +static int +ndmpd_zfs_backup_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + return (ndmpd_zfs_getenv(ndmpd_zfs_args)); +} + +boolean_t +ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + if (ndmpd_zfs_restore_getenv(ndmpd_zfs_args) != 0) + return (B_FALSE); + + if (!ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args)) + return (B_FALSE); + + return (B_TRUE); +} + +static boolean_t +ndmpd_zfs_restore_pathvalid(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + zfs_handle_t *zhp; + char *at; + + if (ndmpd_zfs_restore_getpath(ndmpd_zfs_args) != 0) + return (B_FALSE); + + at = strchr(ndmpd_zfs_args->nz_dataset, '@'); + + if (at) { + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_WARNING, + "%s ignored in restore path\n", at); + *at = '\0'; + } + + ndmpd_zfs_args->nz_type = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM; + + zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, + ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_type); + + if (zhp) { + zfs_close(zhp); + + if (!ndmpd_zfs_is_incremental(ndmpd_zfs_args)) { + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "Restore dataset exists.\n" + "A nonexistent dataset must be specified " + "for 'zfs' non-incremental restore.\n"); + return (B_FALSE); + } + } + + NDMP_LOG(LOG_DEBUG, "restore path: %s\n", ndmpd_zfs_args->nz_dataset); + + return (B_TRUE); +} + +/* + * ndmpd_zfs_restore_getpath() + * + * Be sure to not include the leading slash, which is required for + * compatibility with backup applications (NBU) but which is not part + * of the ZFS syntax. (Note that this done explicitly in all paths + * below except those calling ndmpd_zfs_backup_getpath(), because it is + * already stripped in that function.) + * + * In addition, the DMA might add a trailing slash to the path. + * Strip all such slashes. + */ + +static int +ndmpd_zfs_restore_getpath(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + int version = ndmpd_zfs_params->mp_protocol_version; + char zpath[ZFS_MAXNAMELEN]; + mem_ndmp_name_v3_t *namep_v3; + char *dataset = ndmpd_zfs_args->nz_dataset; + char *nm; + char *p; + int len; + int err; + + dataset = ndmpd_zfs_args->nz_dataset; + + namep_v3 = (mem_ndmp_name_v3_t *)MOD_GETNAME(ndmpd_zfs_params, 0); + + if (namep_v3 == NULL) { + NDMP_LOG(LOG_DEBUG, "Can't get Nlist[0]"); + return (-1); + } + + if (namep_v3->nm3_dpath) { + if (namep_v3->nm3_dpath[0] != '/') { + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "Invalid path: %s (leading slash required)\n", + namep_v3->nm3_dpath); + return (-1); + } + + (void) strlcpy(dataset, &(namep_v3->nm3_dpath[1]), + ZFS_MAXNAMELEN); + + if (namep_v3->nm3_newnm) { + (void) strlcat(dataset, "/", ZFS_MAXNAMELEN); + (void) strlcat(dataset, namep_v3->nm3_newnm, + ZFS_MAXNAMELEN); + + } else { + if (version == NDMPV3) { + /* + * The following does not apply for V4. + * + * Find the last component of nm3_opath. + * nm3_opath has no trailing '/'. + */ + p = strrchr(namep_v3->nm3_opath, '/'); + nm = p? p : namep_v3->nm3_opath; + (void) strlcat(dataset, "/", ZFS_MAXNAMELEN); + (void) strlcat(dataset, nm, ZFS_MAXNAMELEN); + } + } + } else { + err = ndmpd_zfs_backup_getpath(ndmpd_zfs_args, zpath, + ZFS_MAXNAMELEN); + if (err) + return (err); + } + + len = strlen(dataset); + while (dataset[len-1] == '/') { + dataset[len-1] = '\0'; + len--; + } + + return (0); +} + +static int +ndmpd_zfs_restore_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + return (ndmpd_zfs_getenv(ndmpd_zfs_args)); +} + +static int +ndmpd_zfs_getenv(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + + if (ndmpd_zfs_getenv_level(ndmpd_zfs_args) != 0) + return (-1); + + if (ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args) != 0) + return (-1); + + if (ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args) != 0) + return (-1); + + if (ndmpd_zfs_getenv_update(ndmpd_zfs_args) != 0) + return (-1); + + if (ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args) != 0) + return (-1); + + return (0); +} + +static int +ndmpd_zfs_getenv_zfs_mode(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + char *envp; + + envp = MOD_GETENV(ndmpd_zfs_params, "ZFS_MODE"); + + if (envp == NULL) { + NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE) not specified, " + "defaulting to recursive"); + ndmpd_zfs_args->nz_zfs_mode = 'r'; + return (0); + } + + if ((strcmp(envp, "dataset") == 0) || (strcmp(envp, "d") == 0)) { + ndmpd_zfs_args->nz_zfs_mode = 'd'; + } else if ((strcmp(envp, "recursive") == 0) || + (strcmp(envp, "r") == 0)) { + ndmpd_zfs_args->nz_zfs_mode = 'r'; + } else if ((strcmp(envp, "package") == 0) || (strcmp(envp, "p") == 0)) { + ndmpd_zfs_args->nz_zfs_mode = 'p'; + } else { + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "Invalid ZFS_MODE value \"%s\".\n", envp); + return (-1); + } + + NDMP_LOG(LOG_DEBUG, "env(ZFS_MODE): \"%c\"", + ndmpd_zfs_args->nz_zfs_mode); + + return (0); +} + +static int +ndmpd_zfs_getenv_zfs_force(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + char *envp_force; + + envp_force = MOD_GETENV(ndmpd_zfs_params, "ZFS_FORCE"); + + if (envp_force == NULL) { + NDMP_LOG(LOG_DEBUG, + "env(ZFS_FORCE) not specified, defaulting to FALSE"); + ndmpd_zfs_args->nz_zfs_force = B_FALSE; + return (0); + } + + /* + * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4). + */ + + if (strchr("tTyY", *envp_force)) + ndmpd_zfs_args->nz_zfs_force = B_TRUE; + + NDMP_LOG(LOG_DEBUG, "env(ZFS_FORCE): \"%s\"", envp_force); + + return (0); +} + +static int +ndmpd_zfs_getenv_level(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + char *envp; + + envp = MOD_GETENV(ndmpd_zfs_params, "LEVEL"); + + if (envp == NULL) { + NDMP_LOG(LOG_DEBUG, "env(LEVEL) not specified, " + "defaulting to 0"); + ndmpd_zfs_args->nz_level = 0; + return (0); + } + + if (envp[1] != '\0') { + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "Invalid backup level \"%s\".\n", envp); + return (-1); + } + + if (!isdigit(*envp)) { + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "Invalid backup level \"%s\".\n", envp); + return (-1); + } + + ndmpd_zfs_args->nz_level = atoi(envp); + + NDMP_LOG(LOG_DEBUG, "env(LEVEL): \"%d\"", + ndmpd_zfs_args->nz_level); + + return (0); +} + +static int +ndmpd_zfs_getenv_update(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + char *envp_update; + + envp_update = MOD_GETENV(ndmpd_zfs_params, "UPDATE"); + + if (envp_update == NULL) { + NDMP_LOG(LOG_DEBUG, + "env(UPDATE) not specified, defaulting to TRUE"); + ndmpd_zfs_args->nz_update = B_TRUE; + return (0); + } + + /* + * The value can be either 't' ("true" for v3) or 'y' ("yes" for v4). + */ + + if (strchr("tTyY", *envp_update)) + ndmpd_zfs_args->nz_update = B_TRUE; + + NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp_update); + + return (0); +} + +static int +ndmpd_zfs_getenv_dmp_name(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + char *envp; + + envp = MOD_GETENV(ndmpd_zfs_params, "DMP_NAME"); + + if (envp == NULL) { + NDMP_LOG(LOG_DEBUG, + "env(DMP_NAME) not specified, defaulting to 'level'"); + (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, "level", + NDMPD_ZFS_DMP_NAME_MAX); + return (0); + } + + if (!ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args, envp)) + return (-1); + + (void) strlcpy(ndmpd_zfs_args->nz_dmp_name, envp, + NDMPD_ZFS_DMP_NAME_MAX); + + NDMP_LOG(LOG_DEBUG, "env(DMP_NAME): \"%s\"", envp); + + return (0); +} + +/* + * ndmpd_zfs_dmp_name_valid() + * + * This function verifies that the dmp_name is valid. + * + * The dmp_name is restricted to alphanumeric characters plus + * the underscore and hyphen, and must be 31 characters or less. + * This is due to its use in the NDMPD_ZFS_PROP_INCR property + * and in the ZFS snapshot name (if an ndmpd-generated snapshot + * is required). + */ + +static boolean_t +ndmpd_zfs_dmp_name_valid(ndmpd_zfs_args_t *ndmpd_zfs_args, char *dmp_name) +{ + char *c; + + if (strlen(dmp_name) >= NDMPD_ZFS_DMP_NAME_MAX) { + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "DMP_NAME %s is longer than %d\n", + dmp_name, NDMPD_ZFS_DMP_NAME_MAX-1); + return (B_FALSE); + } + + for (c = dmp_name; *c != '\0'; c++) { + if (!isalpha(*c) && !isdigit(*c) && + (*c != '_') && (*c != '-')) { + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "DMP_NAME %s contains illegal character %c\n", + dmp_name, *c); + return (B_FALSE); + } + } + + NDMP_LOG(LOG_DEBUG, "DMP_NAME is valid: %s\n", dmp_name); + return (B_TRUE); +} + +/* + * ndmpd_zfs_is_incremental() + * + * This can only be called after ndmpd_zfs_getenv_level() + * has been called. + */ + +static boolean_t +ndmpd_zfs_is_incremental(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + return (ndmpd_zfs_args->nz_level != 0); +} + +/* + * ndmpd_zfs_snapshot_prepare() + * + * If no snapshot was supplied by the user, create a snapshot + * for use by ndmpd. + */ + +static int +ndmpd_zfs_snapshot_prepare(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + ndmpd_session_t *session = (ndmpd_session_t *) + (ndmpd_zfs_params->mp_daemon_cookie); + boolean_t recursive = B_FALSE; + int zfs_err = 0; + + if (session->ns_data.dd_abort) { + NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.", + ndmpd_zfs_args->nz_dataset); + return (-1); + } + + if (ndmpd_zfs_args->nz_snapname[0] == '\0') { + ndmpd_zfs_args->nz_ndmpd_snap = B_TRUE; + + if (ndmpd_zfs_snapshot_create(ndmpd_zfs_args) != 0) { + ndmpd_zfs_args->nz_snapname[0] = '\0'; + + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "Error creating snapshot for %s\n", + ndmpd_zfs_args->nz_dataset); + + return (-1); + } + } + + if (ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args)) { + NDMP_LOG(LOG_DEBUG, + "ndmpd_zfs_snapshot_prop_add error\n"); + + if (ndmpd_zfs_args->nz_ndmpd_snap) { + + if (ndmpd_zfs_args->nz_zfs_mode != 'd') + recursive = B_TRUE; + + (void) snapshot_destroy(ndmpd_zfs_args->nz_dataset, + ndmpd_zfs_args->nz_snapname, recursive, &zfs_err); + } + + return (-1); + } + + return (0); +} + +/* + * ndmpd_zfs_snapshot_cleanup() + * + * If UPDATE = y, find the old snapshot (if any) corresponding to + * {LEVEL, DMPNAME, ZFS_MODE}. If it was ndmpd-generated, + * remove the snapshot. Otherwise, update its NDMPD_ZFS_PROP_INCR + * property to remove {L, D, Z}. + * + * If UPDATE = n, if an ndmpd-generated snapshot was used for backup, + * remove the snapshot. Otherwise, update its NDMPD_ZFS_PROP_INCR + * property to remove {L, D, Z}. + */ + +static int +ndmpd_zfs_snapshot_cleanup(ndmpd_zfs_args_t *ndmpd_zfs_args, int err) +{ + ndmpd_session_t *session = (ndmpd_session_t *) + (ndmpd_zfs_params->mp_daemon_cookie); + ndmpd_zfs_snapfind_t snapdata; + boolean_t ndmpd_generated = B_FALSE; + + bzero(&snapdata, sizeof (ndmpd_zfs_snapfind_t)); + + (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args, + snapdata.nzs_findprop, ZFS_MAXPROPLEN, B_FALSE); + + if (ndmpd_zfs_args->nz_update && !session->ns_data.dd_abort && !err) { + /* + * Find the existing snapshot, if any, to "unuse." + * Indicate that the current snapshot used for backup + * should be skipped in the search. (The search is + * sorted by creation time but this cannot be relied + * upon for user-supplied snapshots.) + */ + + (void) snprintf(snapdata.nzs_snapskip, ZFS_MAXNAMELEN, "%s", + ndmpd_zfs_args->nz_snapname); + + if (ndmpd_zfs_snapshot_find(ndmpd_zfs_args, &snapdata)) { + NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_find error\n"); + goto _remove_tmp_snap; + } + + if (snapdata.nzs_snapname[0] != '\0') { /* snapshot found */ + ndmpd_generated = ndmpd_zfs_snapshot_ndmpd_generated + (snapdata.nzs_snapprop); + + if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args, + ndmpd_generated, &snapdata) != 0) { + NDMP_LOG(LOG_DEBUG, + "ndmpd_zfs_snapshot_unuse error\n"); + goto _remove_tmp_snap; + } + } + + if (session->ns_data.dd_abort) + goto _remove_tmp_snap; + + return (0); + } + +_remove_tmp_snap: + + (void) snprintf(snapdata.nzs_snapname, ZFS_MAXNAMELEN, "%s", + ndmpd_zfs_args->nz_snapname); + + (void) strlcpy(snapdata.nzs_snapprop, ndmpd_zfs_args->nz_snapprop, + ZFS_MAXPROPLEN); + + snapdata.nzs_snapskip[0] = '\0'; + + if (ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args, + ndmpd_zfs_args->nz_ndmpd_snap, &snapdata) != 0) { + NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_unuse error\n"); + return (-1); + } + + if (!ndmpd_zfs_args->nz_update) + return (0); + + return (-1); +} + +static int +ndmpd_zfs_snapshot_create(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + boolean_t recursive = B_FALSE; + + if (ndmpd_zfs_snapname_create(ndmpd_zfs_args, + ndmpd_zfs_args->nz_snapname, ZFS_MAXNAMELEN -1) < 0) { + NDMP_LOG(LOG_ERR, "Error (%d) creating snapshot name for %s", + errno, ndmpd_zfs_args->nz_dataset); + return (-1); + } + + if (ndmpd_zfs_args->nz_zfs_mode != 'd') + recursive = B_TRUE; + + if (snapshot_create(ndmpd_zfs_args->nz_dataset, + ndmpd_zfs_args->nz_snapname, recursive) != 0) { + NDMP_LOG(LOG_ERR, "could not create snapshot %s@%s", + ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname); + return (-1); + } + + NDMP_LOG(LOG_DEBUG, "created snapshot %s@%s", + ndmpd_zfs_args->nz_dataset, ndmpd_zfs_args->nz_snapname); + + return (0); +} + +/* + * ndmpd_zfs_snapshot_unuse() + * + * Given a pre-existing snapshot of the given {L, D, Z}: + * If snapshot is ndmpd-generated, remove snapshot. + * If not ndmpd-generated, or if the ndmpd-generated snapshot + * cannot be destroyed, remove the {L, D, Z} substring from the + * snapshot's NDMPD_ZFS_PROP_INCR property. + * + * In the event of a failure, it may be that two snapshots will + * have the {L, D, Z} property set on them. This is not desirable, + * so return an error and log the failure. + */ + +static int +ndmpd_zfs_snapshot_unuse(ndmpd_zfs_args_t *ndmpd_zfs_args, + boolean_t ndmpd_generated, ndmpd_zfs_snapfind_t *snapdata_p) +{ + boolean_t recursive = B_FALSE; + int zfs_err = 0; + int err = 0; + + if (ndmpd_generated) { + if (ndmpd_zfs_args->nz_zfs_mode != 'd') + recursive = B_TRUE; + + err = snapshot_destroy(ndmpd_zfs_args->nz_dataset, + snapdata_p->nzs_snapname, recursive, &zfs_err); + + if (err) { + NDMP_LOG(LOG_ERR, "snapshot_destroy: %s@%s;" + " err: %d; zfs_err: %d", + ndmpd_zfs_args->nz_dataset, + snapdata_p->nzs_snapname, err, zfs_err); + return (-1); + } + } + + if (!ndmpd_generated || zfs_err) { + if (ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args, snapdata_p)) + return (-1); + } + + return (0); +} + +static boolean_t +ndmpd_zfs_snapshot_ndmpd_generated(char *snapprop) +{ + char origin; + + (void) sscanf(snapprop, "%*u.%*u.%c%*s", &origin); + + return (origin == 'n'); +} + +/* + * ndmpd_zfs_snapshot_find() + * + * Find a snapshot with a particular value for + * the NDMPD_ZFS_PROP_INCR property. + */ + +static int +ndmpd_zfs_snapshot_find(ndmpd_zfs_args_t *ndmpd_zfs_args, + ndmpd_zfs_snapfind_t *snapdata) +{ + zfs_handle_t *zhp; + int err; + + zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, ndmpd_zfs_args->nz_dataset, + ndmpd_zfs_args->nz_type); + + if (!zhp) { + NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open"); + return (-1); + } + + err = zfs_iter_snapshots_sorted(zhp, ndmpd_zfs_snapshot_prop_find, + snapdata); + + zfs_close(zhp); + + if (err) { + NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_iter_snapshots: %d", + err); + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "Error iterating snapshots\n"); + return (-1); + } + + return (0); +} + +/* + * ndmpd_zfs_snapshot_prop_find() + * + * Find a snapshot with a particular value for + * NDMPD_ZFS_PROP_INCR. Fill in data for the first one + * found (sorted by creation time). However, skip the + * the snapshot indicated in nzs_snapskip, if any. + */ + +static int +ndmpd_zfs_snapshot_prop_find(zfs_handle_t *zhp, void *arg) +{ + ndmpd_zfs_snapfind_t *snapdata_p = (ndmpd_zfs_snapfind_t *)arg; + char propstr[ZFS_MAXPROPLEN]; + char findprop_plus_slash[ZFS_MAXPROPLEN]; + char *justsnap; + int err = 0; + + if (snapdata_p->nzs_snapname[0] != '\0') { + NDMP_LOG(LOG_DEBUG, "no need to get prop for snapshot %s", + (char *)zfs_get_name(zhp)); + goto _done; + } + + err = ndmpd_zfs_snapshot_prop_get(zhp, propstr); + + if (err) { + NDMP_LOG(LOG_DEBUG, "ndmpd_zfs_snapshot_prop_get failed"); + goto _done; + } + + if (propstr[0] == '\0') { + NDMP_LOG(LOG_DEBUG, "snapshot %s: propr not set", + (char *)zfs_get_name(zhp)); + goto _done; + } + + (void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s", + snapdata_p->nzs_findprop); + + if (!strstr((const char *)propstr, + (const char *)findprop_plus_slash)) { + NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s not found)", + (char *)zfs_get_name(zhp), propstr, + snapdata_p->nzs_findprop); + goto _done; + } + + if (!ndmpd_zfs_prop_version_check(propstr, + &snapdata_p->nzs_prop_major, &snapdata_p->nzs_prop_minor)) { + NDMP_LOG(LOG_DEBUG, "snapshot %s: property %s (%s found)", + (char *)zfs_get_name(zhp), propstr, + snapdata_p->nzs_findprop); + NDMP_LOG(LOG_DEBUG, "did not pass version check"); + goto _done; + } + + justsnap = strchr(zfs_get_name(zhp), '@') + 1; + + if (strcmp(justsnap, snapdata_p->nzs_snapskip) != 0) { + (void) strlcpy(snapdata_p->nzs_snapname, justsnap, + ZFS_MAXNAMELEN); + + (void) strlcpy(snapdata_p->nzs_snapprop, propstr, + ZFS_MAXPROPLEN); + + NDMP_LOG(LOG_DEBUG, "found match: %s [%s]\n", + snapdata_p->nzs_snapname, snapdata_p->nzs_snapprop); + } + +_done: + zfs_close(zhp); + return (err); +} + +/* + * ndmpd_zfs_snapshot_prop_get() + * + * Retrieve NDMPD_ZFS_PROP_INCR property from snapshot + */ + +static int +ndmpd_zfs_snapshot_prop_get(zfs_handle_t *zhp, char *propstr) +{ + nvlist_t *userprop; + nvlist_t *propval; + char *strval; + int err; + + propstr[0] = '\0'; + + userprop = zfs_get_user_props(zhp); + + if (userprop == NULL) + return (0); + + err = nvlist_lookup_nvlist(userprop, NDMPD_ZFS_PROP_INCR, &propval); + + if (err != 0) { + if (err == ENOENT) + return (0); + + NDMP_LOG(LOG_DEBUG, "nvlist_lookup_nvlist error: %d\n", err); + + return (-1); + } + + err = nvlist_lookup_string(propval, ZPROP_VALUE, &strval); + + if (err != 0) { + if (err == ENOENT) + return (0); + + NDMP_LOG(LOG_DEBUG, "nvlist_lookup_string error: %d\n", err); + + return (-1); + } + + (void) strlcpy(propstr, strval, ZFS_MAXPROPLEN); + + return (0); +} + +/* + * ndmpd_zfs_snapshot_prop_add() + * + * Update snapshot's NDMPD_ZFS_PROP_INCR property with + * the current LEVEL, DMPNAME, and ZFSMODE values + * (add property if it doesn't exist) + */ + +static int +ndmpd_zfs_snapshot_prop_add(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + char fullname[ZFS_MAXNAMELEN]; + char propstr[ZFS_MAXPROPLEN]; + zfs_handle_t *zhp; + boolean_t set; + int err; + + (void) snprintf(fullname, ZFS_MAXNAMELEN, "%s@%s", + ndmpd_zfs_args->nz_dataset, + ndmpd_zfs_args->nz_snapname); + + zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT); + + if (!zhp) { + NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open (snap)"); + return (-1); + } + + bzero(propstr, ZFS_MAXPROPLEN); + + if (ndmpd_zfs_snapshot_prop_get(zhp, propstr)) { + NDMP_LOG(LOG_DEBUG, "error getting property"); + zfs_close(zhp); + return (-1); + } + + if (ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args, propstr, &set)) { + zfs_close(zhp); + return (-1); + } + + if (set) { + err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, propstr); + if (err) { + NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", + err); + NDMP_LOG(LOG_ERR, "error setting property %s", + propstr); + zfs_close(zhp); + return (-1); + } + } + + zfs_close(zhp); + + (void) strlcpy(ndmpd_zfs_args->nz_snapprop, propstr, ZFS_MAXPROPLEN); + + return (0); +} + +static int +ndmpd_zfs_snapshot_prop_create(ndmpd_zfs_args_t *ndmpd_zfs_args, + char *propstr, boolean_t *set) +{ + char subprop[ZFS_MAXPROPLEN]; + + *set = B_TRUE; + + (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args, + subprop, ZFS_MAXPROPLEN, B_FALSE); + + if (propstr[0] == '\0') { + (void) snprintf(propstr, ZFS_MAXPROPLEN, "%u.%u.%c/%s", + NDMPD_ZFS_PROP_MAJOR_VERSION, + NDMPD_ZFS_PROP_MINOR_VERSION, + (ndmpd_zfs_args->nz_ndmpd_snap) ? 'n' : 'u', + subprop); + return (0); + } + + if (strstr((const char *)propstr, (const char *)subprop)) { + NDMP_LOG(LOG_DEBUG, "Did not add entry %s as it already exists", + subprop); + *set = B_FALSE; + return (0); + } + + if ((strlen(propstr) + strlen(subprop) + 2) >= ZFS_MAXPROPLEN) { + NDMP_LOG(LOG_ERR, "snapshot %s: user property " + "%s would overflow; cannot complete operation", + ndmpd_zfs_args->nz_snapname, + NDMPD_ZFS_PROP_INCR); + return (-1); + } + + (void) strlcat(propstr, "/", ZFS_MAXPROPLEN); + (void) strlcat(propstr, subprop, ZFS_MAXPROPLEN); + + return (0); +} + +static int +ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args_t *ndmpd_zfs_args, + char *subprop, int len, boolean_t prev_level) +{ + return (snprintf(subprop, len, "%d.%s.%c", + prev_level ? ndmpd_zfs_args->nz_level-1 : ndmpd_zfs_args->nz_level, + ndmpd_zfs_args->nz_dmp_name, + ndmpd_zfs_args->nz_zfs_mode)); +} + +/* + * ndmpd_zfs_snapshot_prop_remove() + * + * Remove specified substring from the snapshot's + * NDMPD_ZFS_PROP_INCR property + */ + +static int +ndmpd_zfs_snapshot_prop_remove(ndmpd_zfs_args_t *ndmpd_zfs_args, + ndmpd_zfs_snapfind_t *snapdata_p) +{ + char findprop_plus_slash[ZFS_MAXPROPLEN]; + char fullname[ZFS_MAXNAMELEN]; + char newprop[ZFS_MAXPROPLEN]; + char tmpstr[ZFS_MAXPROPLEN]; + zfs_handle_t *zhp; + char *ptr; + int err; + + (void) snprintf(fullname, ZFS_MAXNAMELEN, "%s@%s", + ndmpd_zfs_args->nz_dataset, + snapdata_p->nzs_snapname); + + zhp = zfs_open(ndmpd_zfs_args->nz_zlibh, fullname, ZFS_TYPE_SNAPSHOT); + + if (!zhp) { + NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_open"); + return (-1); + } + + bzero(newprop, ZFS_MAXPROPLEN); + + /* + * If the substring to be removed is the only {L, D, Z} + * in the property, remove the entire property + */ + + tmpstr[0] = '\0'; + + (void) sscanf(snapdata_p->nzs_snapprop, "%*u.%*u.%*c/%1023s", tmpstr); + + if (strcmp(tmpstr, snapdata_p->nzs_findprop) == 0) { + + err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop); + + zfs_close(zhp); + + if (err) { + NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", + err); + NDMP_LOG(LOG_ERR, "error setting property %s", newprop); + return (-1); + } + + return (0); + } + + (void) snprintf(findprop_plus_slash, ZFS_MAXPROPLEN, "/%s", + snapdata_p->nzs_findprop); + + ptr = strstr((const char *)snapdata_p->nzs_snapprop, + (const char *)findprop_plus_slash); + + if (ptr == NULL) { + /* + * This shouldn't happen. Just return success. + */ + zfs_close(zhp); + + return (0); + } + + /* + * Remove "nzs_findprop" substring from property + * + * Example property: + * 0.0.u/1.bob.p/0.jane.d + * + * Note that there will always be a prefix to the + * strstr() result. Hence the below code works for + * all cases. + */ + + ptr--; + (void) strncpy(newprop, snapdata_p->nzs_snapprop, + (char *)ptr - snapdata_p->nzs_snapprop); + ptr += strlen(snapdata_p->nzs_findprop) + 1; + (void) strlcat(newprop, ptr, ZFS_MAXPROPLEN); + + err = zfs_prop_set(zhp, NDMPD_ZFS_PROP_INCR, newprop); + + zfs_close(zhp); + + if (err) { + NDMPD_ZFS_LOG_ZERR(ndmpd_zfs_args, "zfs_prop_set: %d", err); + NDMP_LOG(LOG_ERR, "error modifying property %s", newprop); + return (-1); + } + + return (0); +} + +static boolean_t +ndmpd_zfs_prop_version_check(char *propstr, uint32_t *major, uint32_t *minor) +{ + (void) sscanf(propstr, "%u.%u.%*c%*s", major, minor); + + if (*major > NDMPD_ZFS_PROP_MAJOR_VERSION) { + NDMP_LOG(LOG_ERR, "unsupported prop major (%u > %u)", + *major, NDMPD_ZFS_PROP_MAJOR_VERSION); + return (B_FALSE); + } + + if (*minor > NDMPD_ZFS_PROP_MINOR_VERSION) { + NDMP_LOG(LOG_ERR, "later prop minor (%u > %u)", + *minor, NDMPD_ZFS_PROP_MINOR_VERSION); + } + + NDMP_LOG(LOG_DEBUG, "passed version check: " + "supported prop major (%u <= %u); (snapprop minor: %u [%u])", + *major, NDMPD_ZFS_PROP_MAJOR_VERSION, + *minor, NDMPD_ZFS_PROP_MINOR_VERSION); + + return (B_TRUE); +} + +static int +ndmpd_zfs_snapname_create(ndmpd_zfs_args_t *ndmpd_zfs_args, + char *snapname, int namelen) +{ + char subprop[ZFS_MAXPROPLEN]; + struct timeval tp; + int err = 0; + + (void) ndmpd_zfs_prop_create_subprop(ndmpd_zfs_args, + subprop, ZFS_MAXPROPLEN, B_FALSE); + + (void) gettimeofday(&tp, NULL); + + err = snprintf(snapname, namelen, + "ndmp.%s.%ld.%ld", + subprop, + tp.tv_sec, + tp.tv_usec); + + if (err > namelen) { + NDMP_LOG(LOG_ERR, "name of snapshot [%s...] would exceed %d", + snapname, namelen); + return (-1); + } + + return (0); +} + +static void +ndmpd_zfs_zerr_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args) +{ + switch (libzfs_errno(ndmpd_zfs_args->nz_zlibh)) { + case EZFS_EXISTS: + case EZFS_BUSY: + case EZFS_NOENT: + case EZFS_INVALIDNAME: + case EZFS_MOUNTFAILED: + case EZFS_UMOUNTFAILED: + case EZFS_NAMETOOLONG: + case EZFS_BADRESTORE: + + /* use existing error text */ + + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "%s: %s: %s\n", + ndmpd_zfs_args->nz_dataset, + libzfs_error_action(ndmpd_zfs_args->nz_zlibh), + libzfs_error_description(ndmpd_zfs_args->nz_zlibh)); + + break; + + case EZFS_NOMEM: + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "Unable to obtain memory for operation\n"); + break; + + case EZFS_PROPSPACE: + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "A bad ZFS quota or reservation was encountered.\n"); + break; + + case EZFS_BADSTREAM: + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "The backup stream is invalid.\n"); + break; + + case EZFS_ZONED: + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "An error related to the local zone occurred.\n"); + break; + + case EZFS_NOSPC: + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "No more space is available\n"); + break; + + case EZFS_IO: + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "An I/O error occurred.\n"); + break; + + default: + ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_ERROR, + "An internal ndmpd error occurred. " + "Please contact support\n"); + break; + } +} + +void +ndmpd_zfs_dma_log(ndmpd_zfs_args_t *ndmpd_zfs_args, ndmp_log_type log_type, + char *format, ...) +{ + static char buf[1024]; + va_list ap; + + va_start(ap, format); + + /*LINTED variable format specifier */ + (void) vsnprintf(buf, sizeof (buf), format, ap); + va_end(ap); + + MOD_LOGV3(ndmpd_zfs_params, log_type, buf); + + if ((log_type) == NDMP_LOG_ERROR) { + NDMP_LOG(LOG_ERR, buf); + } else { + NDMP_LOG(LOG_INFO, buf); + } +} diff --git a/usr/src/cmd/ndmpd/tlm/tlm_lib.c b/usr/src/cmd/ndmpd/tlm/tlm_lib.c index 2734ebc187..b4704dfa61 100644 --- a/usr/src/cmd/ndmpd/tlm/tlm_lib.c +++ b/usr/src/cmd/ndmpd/tlm/tlm_lib.c @@ -1,6 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -663,7 +662,7 @@ tlm_get_chkpnt_time(char *path, int auto_checkpoint, time_t *tp, char *jname) if (auto_checkpoint) { NDMP_LOG(LOG_DEBUG, "volname [%s]", volname); - (void) snprintf(chk_name, PATH_MAX, "bk-%s", jname); + (void) snprintf(chk_name, PATH_MAX, "%s", jname); return (chkpnt_creationtime_bypattern(volname, chk_name, tp)); } cp_nm = strchr(volname, '@'); @@ -710,13 +709,13 @@ tlm_log_list(char *title, char **lpp) * Insert the backup snapshot name into the path. * * Input: - * name: Origional path name. + * name: Original path name. * * Output: - * name: Origional name modified to include a snapshot. + * name: Original name modified to include a snapshot. * * Returns: - * Origional name modified to include a snapshot. + * Original name modified to include a snapshot. */ char * tlm_build_snapshot_name(char *name, char *sname, char *jname) @@ -747,7 +746,7 @@ tlm_build_snapshot_name(char *name, char *sname, char *jname) (void) mutex_unlock(&zlib_mtx); rest = name + strlen(mountpoint); - (void) snprintf(sname, TLM_MAX_PATH_NAME, "%s/%s/bk-%s%s", mountpoint, + (void) snprintf(sname, TLM_MAX_PATH_NAME, "%s/%s/%s%s", mountpoint, TLM_SNAPSHOT_DIR, jname, rest); return (sname); @@ -1174,7 +1173,7 @@ tlm_ioctl(int fd, int cmd, void *data) * Create a snapshot on the volume */ int -chkpnt_backup_prepare(char *volname, char *jname) +chkpnt_backup_prepare(char *volname, char *jname, boolean_t recursive) { char chk_name[PATH_MAX]; char *p; @@ -1190,17 +1189,18 @@ chkpnt_backup_prepare(char *volname, char *jname) while (*p == '/') p++; - (void) snprintf(chk_name, PATH_MAX, "%s@bk-%s", p, jname); + (void) snprintf(chk_name, PATH_MAX, "%s@%s", p, jname); (void) mutex_lock(&zlib_mtx); - if ((rv = zfs_snapshot(zlibh, chk_name, 0, NULL)) == -1) { + if ((rv = zfs_snapshot(zlibh, chk_name, recursive, NULL)) + == -1) { if (errno == EEXIST) { (void) mutex_unlock(&zlib_mtx); return (0); } NDMP_LOG(LOG_DEBUG, - "chkpnt_backup_prepare: %s failed (err=%d)", - chk_name, errno); + "chkpnt_backup_prepare: %s failed (err=%d): %s", + chk_name, errno, libzfs_error_description(zlibh)); (void) mutex_unlock(&zlib_mtx); return (rv); } @@ -1212,12 +1212,18 @@ chkpnt_backup_prepare(char *volname, char *jname) * Remove the 'backup' snapshot if backup was successful */ int -chkpnt_backup_successful(char *volname, char *jname) +chkpnt_backup_successful(char *volname, char *jname, boolean_t recursive, + int *zfs_err) { char chk_name[PATH_MAX]; zfs_handle_t *zhp; + zfs_type_t ztype; + int err; char *p; + if (zfs_err) + *zfs_err = 0; + if (!volname || !*volname) return (-1); @@ -1228,16 +1234,40 @@ chkpnt_backup_successful(char *volname, char *jname) while (*p == '/') p++; - (void) snprintf(chk_name, PATH_MAX, "%s@bk-%s", p, jname); + if (recursive) { + ztype = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM; + } else { + (void) snprintf(chk_name, PATH_MAX, "%s@%s", p, jname); + p = chk_name; + ztype = ZFS_TYPE_SNAPSHOT; + } (void) mutex_lock(&zlib_mtx); - if ((zhp = zfs_open(zlibh, chk_name, ZFS_TYPE_SNAPSHOT)) == NULL) { + if ((zhp = zfs_open(zlibh, p, ztype)) == NULL) { NDMP_LOG(LOG_DEBUG, "chkpnt_backup_successful: open %s failed", - chk_name); + p); (void) mutex_unlock(&zlib_mtx); return (-1); } - (void) zfs_destroy(zhp, B_FALSE); + + if (recursive) { + err = zfs_destroy_snaps(zhp, jname, B_FALSE); + } else { + err = zfs_destroy(zhp, B_FALSE); + } + + if (err) { + NDMP_LOG(LOG_ERR, "%s (recursive destroy: %d): %d; %s; %s", + p, + recursive, + libzfs_errno(zlibh), + libzfs_error_action(zlibh), + libzfs_error_description(zlibh)); + + if (zfs_err) + *zfs_err = err; + } + zfs_close(zhp); (void) mutex_unlock(&zlib_mtx); diff --git a/usr/src/lib/libndmp/common/libndmp.h b/usr/src/lib/libndmp/common/libndmp.h index 0d535bb46c..2a85462809 100644 --- a/usr/src/lib/libndmp/common/libndmp.h +++ b/usr/src/lib/libndmp/common/libndmp.h @@ -1,6 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -36,6 +35,8 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ +/* Copyright (c) 2007, The Storage Networking Industry Association. */ +/* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */ #ifndef _LIBNDMP_H #define _LIBNDMP_H @@ -64,9 +65,10 @@ extern int ndmp_errno; typedef struct ndmp_context { char *nc_plname; uint_t nc_plversion; - void *nc_pldata; + void *nc_pldata; /* data private to the plugin */ void *nc_cmds; void *nc_params; + void *nc_ddata; /* data private to the daemon */ } ndmp_context_t; typedef struct ndmp_plugin { @@ -92,6 +94,14 @@ typedef enum ndmp_log_dma_type { NDMP_LOGD_WARNING = 3 } ndmp_log_dma_type_t; +typedef enum { + NDMP_BUTYPE_TAR = 0, + NDMP_BUTYPE_DUMP, + NDMP_BUTYPE_ZFS +} ndmpd_backup_type_t; + +extern ndmpd_backup_type_t ndmp_get_backup_type(ndmp_context_t *); + /* libndmp error codes */ #define ENDMP_BASE 2000 enum { |