Print this page
NEX-13374 NDMP should be able to backup unmounted ZFS filesystems
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Revert "NEX-5801 Snapshots left over after failed backups"
This reverts commit f182fb95f09036db71fbfc6f0a6b90469b761f21.
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-2990 ndmpd dumping core when used with ndmpcopy
NEX-2911 NDMP logging should use syslog and is too chatty
NEX-2911 NDMP logging should use syslog and is too chatty
NEX-1512 NDMP fails in Restore files with Symantec Netbackup
NEX-1263 socket buffer sizes in NDMP are set to very low value
Reviewed by: sarah.jelinek@nexenta.com
Reviewed by: marcel.telka@nexenta.com
Reviewed by: albert.lee@nexenta.com
Reviewed by: hans.rosenfeld@nexenta.com
NEX-727 Netbackup Catalog verification hangs waiting for NDMP server
NEX-559 NDMP cannot backup/restore a file which spans multiple tapes

@@ -35,13 +35,14 @@
  * 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 */
-/* Copyright 2014 Nexenta Systems, Inc. All rights reserved. */
+/* Copyright 2017 Nexenta Systems, Inc. All rights reserved. */
 
 #include <sys/types.h>
+#include <syslog.h>
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>

@@ -151,18 +152,17 @@
         EXCL_TMP,
         NULL, /* reserved for a copy of the "backup.directory" */
         NULL
 };
 
-
 /*
- * The counter for creating unique names with "ndmp.%d" format.
+ * The counter for creating unique names with "NDMP_RCF_BASENAME.%d" format.
  */
-#define NDMP_RCF_BASENAME       "ndmp."
 static int ndmp_job_cnt = 0;
 
 static int scsi_test_unit_ready(int dev_id);
+static int ndmpd_mkdir(const char *);
 
 /*
  * ndmpd_add_file_handler
  *
  * Adds a file handler to the file handler list.

@@ -306,15 +306,15 @@
 
                 closed = ndmp_connection_closed(moverfd);
                 if (closed) {
                         /* Connection closed or internal error */
                         if (closed > 0) {
-                                NDMP_LOG(LOG_DEBUG,
+                                syslog(LOG_DEBUG,
                                     "ndmp mover: connection closed by peer");
                                 reason = NDMP_MOVER_HALT_CONNECT_CLOSED;
                         } else {
-                                NDMP_LOG(LOG_DEBUG,
+                                syslog(LOG_DEBUG,
                                     "ndmp mover: Internal error");
                                 reason = NDMP_MOVER_HALT_INTERNAL_ERROR;
                         }
                         ndmpd_mover_error(session, reason);
 

@@ -401,12 +401,10 @@
                 int connection_fd = ndmp_get_fd(session->ns_connection);
 
                 if (errno == EINTR)
                         return (0);
 
-                NDMP_LOG(LOG_DEBUG, "Select error: %m");
-
                 nlp = ndmp_get_nlp(session);
                 (void) mutex_lock(&nlp->nlp_mtx);
                 for (handler = session->ns_file_handler_list; handler != 0;
                     handler = handler->fh_next) {
                         if ((handler->fh_class & class_mask) == 0)

@@ -520,11 +518,11 @@
                 if (valbuf == 0) {
                         free(namebuf);
                         return (NDMP_NO_MEM_ERR);
                 }
 
-                NDMP_LOG(LOG_DEBUG, "env(%s): \"%s\"",
+                syslog(LOG_DEBUG, "env(%s): \"%s\"",
                     namebuf, valbuf);
 
                 (void) mutex_lock(&session->ns_lock);
                 session->ns_data.dd_env[i].name = namebuf;
                 session->ns_data.dd_env[i].value = valbuf;

@@ -592,11 +590,12 @@
 
         if (nlistlen == 0)
                 return (NDMP_NO_ERR);
 
         session->ns_data.dd_nlist_len = 0;
-        session->ns_data.dd_nlist = ndmp_malloc(sizeof (ndmp_name)*nlistlen);
+        session->ns_data.dd_nlist =
+            ndmp_malloc(sizeof (ndmp_name)*(nlistlen + 1));
         if (session->ns_data.dd_nlist == 0)
                 return (NDMP_NO_MEM_ERR);
 
         for (i = 0; i < nlistlen; i++) {
                 namebuf = ndmp_malloc(strlen(nlist[i].name) + 1);

@@ -744,15 +743,10 @@
                 tp->nm3_node = quad_to_long_long(sp->node);
                 tp->nm3_fh_info = quad_to_long_long(sp->fh_info);
                 tp->nm3_err = NDMP_NO_ERR;
                 session->ns_data.dd_nlist_len++;
 
-                NDMP_LOG(LOG_DEBUG, "orig \"%s\"", tp->nm3_opath);
-                NDMP_LOG(LOG_DEBUG, "dest \"%s\"", NDMP_SVAL(tp->nm3_dpath));
-                NDMP_LOG(LOG_DEBUG, "name \"%s\"", NDMP_SVAL(tp->nm3_newnm));
-                NDMP_LOG(LOG_DEBUG, "node %lld", tp->nm3_node);
-                NDMP_LOG(LOG_DEBUG, "fh_info %lld", tp->nm3_fh_info);
         }
 
         if (rv != NDMP_NO_ERR)
                 ndmpd_free_nlist_v3(session);
 

@@ -783,11 +777,11 @@
         case 4:
                 ndmpd_free_nlist_v3(session);
                 break;
 
         default:
-                NDMP_LOG(LOG_DEBUG, "Unknown version %d",
+                syslog(LOG_DEBUG, "Unknown version %d",
                     session->ns_protocol_version);
         }
 }
 
 

@@ -861,11 +855,11 @@
  */
 void
 ndmp_send_reply(ndmp_connection_t *connection, void *reply, char *msg)
 {
         if (ndmp_send_response(connection, NDMP_NO_ERR, reply) < 0)
-                NDMP_LOG(LOG_DEBUG, "%s", msg);
+                syslog(LOG_DEBUG, "%s", msg);
 }
 
 
 /*
  * ndmp_mtioctl

@@ -883,11 +877,11 @@
         struct mtop mp;
 
         mp.mt_op = cmd;
         mp.mt_count = count;
         if (ioctl(fd, MTIOCTOP, &mp) < 0) {
-                NDMP_LOG(LOG_ERR, "Failed to send command to tape: %m.");
+                syslog(LOG_ERR, "Failed to send command to tape: %m.");
                 return (-1);
         }
 
         return (0);
 }

@@ -932,29 +926,29 @@
         val = atoi((const char *)ndmpd_get_prop_default(NDMP_SOCKET_CSS, "60"));
         if (val <= 0)
                 val = 60;
         val <<= 10; /* convert the value from kilobytes to bytes */
         if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &val, sizeof (val)) < 0)
-                NDMP_LOG(LOG_ERR, "SO_SNDBUF failed: %m");
+                syslog(LOG_ERR, "SO_SNDBUF failed: %m");
 
         /* set receive buffer size */
         val = atoi((const char *)ndmpd_get_prop_default(NDMP_SOCKET_CRS, "60"));
         if (val <= 0)
                 val = 60;
         val <<= 10; /* convert the value from kilobytes to bytes */
         if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &val, sizeof (val)) < 0)
-                NDMP_LOG(LOG_ERR, "SO_RCVBUF failed: %m");
+                syslog(LOG_ERR, "SO_RCVBUF failed: %m");
 
         /* don't wait to group tcp data */
         val = 1;
         if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val)) != 0)
-                NDMP_LOG(LOG_ERR, "TCP_NODELAY failed: %m");
+                syslog(LOG_ERR, "TCP_NODELAY failed: %m");
 
         /* tcp keep-alive */
         val = 1;
         if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof (val)) != 0)
-                NDMP_LOG(LOG_ERR, "SO_KEEPALIVE failed: %m");
+                syslog(LOG_ERR, "SO_KEEPALIVE failed: %m");
 }
 
 /*
  * ndmp_get_max_tok_seq
  *

@@ -997,19 +991,19 @@
                     "60"));
                 if (xfer_size > 0)
                         xfer_size *= KILOBYTE;
                 else
                         xfer_size = REMOTE_RECORD_SIZE;
-                NDMP_LOG(LOG_DEBUG, "Remote operation: %d", xfer_size);
+                syslog(LOG_DEBUG, "Remote operation: %d", xfer_size);
         } else {
-                NDMP_LOG(LOG_DEBUG,
+                syslog(LOG_DEBUG,
                     "Local operation: %lu", session->ns_mover.md_record_size);
                 if ((xfer_size = session->ns_mover.md_record_size) == 0)
                         xfer_size = MAX_RECORD_SIZE;
         }
 
-        NDMP_LOG(LOG_DEBUG, "xfer_size: %d", xfer_size);
+        syslog(LOG_DEBUG, "xfer_size: %d", xfer_size);
         return (xfer_size);
 }
 
 
 /*

@@ -1026,11 +1020,11 @@
  */
 int
 ndmp_lbr_init(ndmpd_session_t *session)
 {
         if (session->ns_ndmp_lbr_params != NULL) {
-                NDMP_LOG(LOG_DEBUG, "ndmp_lbr_params already allocated.");
+                syslog(LOG_DEBUG, "ndmp_lbr_params already allocated.");
                 return (0);
         }
 
         session->ns_ndmp_lbr_params = ndmp_malloc(sizeof (ndmp_lbr_params_t));
         if (session->ns_ndmp_lbr_params == NULL)

@@ -1099,22 +1093,22 @@
                 return (-1);
 
         (void) mutex_lock(&nlp->nlp_mtx);
         while (session->ns_mover.md_state == NDMP_MOVER_STATE_PAUSED) {
                 if (session->ns_eof) {
-                        NDMP_LOG(LOG_ERR, "EOF detected");
+                        syslog(LOG_ERR, "EOF detected");
                         break;
                 }
                 if (session->ns_data.dd_abort) {
-                        NDMP_LOG(LOG_DEBUG, "Received data abort");
+                        syslog(LOG_DEBUG, "Received data abort");
                         break;
                 }
                 if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
                         /* remote backup/restore error */
                         if (session->ns_mover.md_sock == -1 &&
                             session->ns_mover.md_listen_sock == -1) {
-                                NDMP_LOG(LOG_ERR,
+                                syslog(LOG_ERR,
                                     "Remote data connection terminated");
                                 break;
                         }
                 } else {
                         /* local backup/restore error */

@@ -1121,11 +1115,11 @@
                         if ((lcmd = nlp->nlp_cmds.tcs_command) != NULL) {
                                 if (lcmd->tc_reader == TLM_STOP ||
                                     lcmd->tc_reader == TLM_ABORT ||
                                     lcmd->tc_writer == TLM_STOP ||
                                     lcmd->tc_writer == TLM_ABORT) {
-                                        NDMP_LOG(LOG_ERR,
+                                        syslog(LOG_ERR,
                                             "Local data connection terminated");
                                         break;
                                 }
                         }
                 }

@@ -1154,13 +1148,13 @@
 
         rv = (buf == NULL || buf->tb_eot || buf->tb_eof ||
             buf->tb_errno != 0);
         if (rv) {
                 if (buf == NULL) {
-                        NDMP_LOG(LOG_DEBUG, "buf == NULL");
+                        syslog(LOG_DEBUG, "buf == NULL");
                 } else {
-                        NDMP_LOG(LOG_DEBUG, "eot: %u, eof: %u, errno: %d",
+                        syslog(LOG_DEBUG, "eot: %u, eof: %u, errno: %d",
                             buf->tb_eot, buf->tb_eof, buf->tb_errno);
                 }
         }
 
         return (rv);

@@ -1208,11 +1202,11 @@
                 if ((cmd.uscsi_bufaddr =
                     ndmp_malloc(request->datain_len)) == 0) {
                         reply.error = NDMP_NO_MEM_ERR;
                         if (ndmp_send_response(session->ns_connection,
                             NDMP_NO_ERR, (void *)&reply) < 0)
-                                NDMP_LOG(LOG_DEBUG, "error sending"
+                                syslog(LOG_DEBUG, "error sending"
                                     " scsi_execute_cdb reply.");
                         return;
                 }
 
                 cmd.uscsi_buflen = request->datain_len;

@@ -1232,16 +1226,10 @@
             1 : (request->timeout / 1000);
 
         cmd.uscsi_cdb = (caddr_t)request->cdb.cdb_val;
         cmd.uscsi_cdblen = request->cdb.cdb_len;
 
-        NDMP_LOG(LOG_DEBUG, "cmd: 0x%x, len: %d, flags: %d, datain_len: %d",
-            request->cdb.cdb_val[0] & 0xff, request->cdb.cdb_len,
-            request->flags, request->datain_len);
-        NDMP_LOG(LOG_DEBUG, "dataout_len: %d, timeout: %d",
-            request->dataout.dataout_len, request->timeout);
-
         if (request->cdb.cdb_len > 12) {
                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
                 ndmp_send_reply(session->ns_connection, (void *) &reply,
                     "sending execute_cdb reply");
                 if (request->flags == NDMP_SCSI_DATA_IN)

@@ -1261,14 +1249,14 @@
                         free(cmd.uscsi_bufaddr);
                 return;
         }
 
         if (ioctl(fd, USCSICMD, &cmd) < 0) {
-                if (errno != EIO && errno != 0)
-                        NDMP_LOG(LOG_ERR,
+                if (errno != EIO && errno != 0) {
+                        syslog(LOG_ERR,
                             "Failed to send command to device: %m");
-                NDMP_LOG(LOG_DEBUG, "ioctl(USCSICMD) error: %m");
+                }
                 if (cmd.uscsi_status == 0)
                         reply.error = NDMP_IO_ERR;
         }
 
         reply.status = cmd.uscsi_status;

@@ -1283,11 +1271,11 @@
         reply.ext_sense.ext_sense_len = cmd.uscsi_rqlen - cmd.uscsi_rqresid;
         reply.ext_sense.ext_sense_val = rq_buf;
 
         if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
             (void *)&reply) < 0)
-                NDMP_LOG(LOG_DEBUG, "Error sending scsi_execute_cdb reply.");
+                syslog(LOG_DEBUG, "Error sending scsi_execute_cdb reply.");
 
         if (request->flags == NDMP_SCSI_DATA_IN)
                 free(cmd.uscsi_bufaddr);
 }
 

@@ -1307,12 +1295,11 @@
 void
 ndmp_stop_local_reader(ndmpd_session_t *session, tlm_commands_t *cmds)
 {
         ndmp_lbr_params_t *nlp;
 
-        if (session != NULL && session->ns_data.dd_sock == -1) {
-                /* 2-way restore */
+        if (session != NULL) {
                 if (cmds != NULL && cmds->tcs_reader_count > 0) {
                         if ((nlp = ndmp_get_nlp(session)) != NULL) {
                                 (void) mutex_lock(&nlp->nlp_mtx);
                                 cmds->tcs_command->tc_reader = TLM_STOP;
                                 (void) cond_broadcast(&nlp->nlp_cv);

@@ -1339,11 +1326,11 @@
         if (session != NULL) {
                 if (session->ns_data.dd_sock >= 0) {
                         /*
                          * 3-way restore.
                          */
-                        NDMP_LOG(LOG_DEBUG,
+                        syslog(LOG_DEBUG,
                             "data.sock: %d", session->ns_data.dd_sock);
                         (void) close(session->ns_data.dd_sock);
                         session->ns_data.dd_sock = -1;
                 }
         }

@@ -1356,16 +1343,11 @@
  * Wait for a reader until get done (busy wait)
  */
 void
 ndmp_wait_for_reader(tlm_commands_t *cmds)
 {
-        if (cmds == NULL) {
-                NDMP_LOG(LOG_DEBUG, "cmds == NULL");
-        } else {
-                NDMP_LOG(LOG_DEBUG,
-                    "reader_count: %d", cmds->tcs_reader_count);
-
+        if (cmds != NULL) {
                 while (cmds->tcs_reader_count > 0)
                         (void) sleep(1);
         }
 }
 

@@ -1388,11 +1370,10 @@
 {
         struct ol_head *olhp;
         struct open_list *olp;
 
         if (dev == NULL || *dev == '\0') {
-                NDMP_LOG(LOG_DEBUG, "Invalid argument");
                 return (NULL);
         }
 
         (void) mutex_lock(&ol_mutex);
         olhp = &ol_head;

@@ -1429,21 +1410,17 @@
         int err;
         struct ol_head *olhp;
         struct open_list *olp;
 
         if (dev == NULL || *dev == '\0') {
-                NDMP_LOG(LOG_DEBUG, "Invalid argument");
                 return (EINVAL);
         }
-        NDMP_LOG(LOG_DEBUG,
-            "conn: 0x%08x, dev: %s, sid: %d, lun: %d", conn, dev, sid, lun);
 
         err = 0;
         olhp = &ol_head;
 
         if ((olp = ndmp_open_list_find(dev, sid, lun)) != NULL) {
-                NDMP_LOG(LOG_DEBUG, "already in list");
                 /*
                  * The adapter handle can be opened many times by the clients.
                  * Only when the target is set, we must check and reject the
                  * open request if the device is already being used by another
                  * session.

@@ -1453,11 +1430,11 @@
                 else
                         err = EBUSY;
         } else if ((olp = ndmp_malloc(sizeof (struct open_list))) == NULL) {
                 err = ENOMEM;
         } else if ((olp->ol_devnm = strdup(dev)) == NULL) {
-                NDMP_LOG(LOG_ERR, "Out of memory.");
+                syslog(LOG_ERR, "Out of memory.");
                 free(olp);
                 err = ENOMEM;
         } else {
                 olp->cl_conn = conn;
                 olp->ol_nref = 1;

@@ -1493,22 +1470,20 @@
 ndmp_open_list_del(char *dev, int sid, int lun)
 {
         struct open_list *olp;
 
         if (dev == NULL || *dev == '\0') {
-                NDMP_LOG(LOG_DEBUG, "Invalid argument");
+                syslog(LOG_DEBUG, "Invalid argument");
                 return (EINVAL);
         }
         if ((olp = ndmp_open_list_find(dev, sid, lun)) == NULL) {
-                NDMP_LOG(LOG_DEBUG, "%s not found", dev);
+                syslog(LOG_DEBUG, "%s not found", dev);
                 return (ENOENT);
         }
 
         (void) mutex_lock(&ol_mutex);
         if (--olp->ol_nref <= 0) {
-                NDMP_LOG(LOG_DEBUG,
-                    "Removed dev: %s, sid: %d, lun: %d", dev, sid, lun);
                 LIST_REMOVE(olp, ol_q);
                 free(olp->ol_devnm);
                 free(olp);
         }
         (void) mutex_unlock(&ol_mutex);

@@ -1537,15 +1512,11 @@
 
         (void) mutex_lock(&ol_mutex);
         olp = LIST_FIRST(olhp);
         while (olp != NULL) {
                 next = LIST_NEXT(olp, ol_q);
-                NDMP_LOG(LOG_DEBUG, "olp->conn 0x%08x", olp->cl_conn);
                 if (olp->cl_conn == conn) {
-                        NDMP_LOG(LOG_DEBUG,
-                            "Removed dev: %s, sid: %d, lun: %d",
-                            olp->ol_devnm, olp->ol_sid, olp->ol_lun);
                         LIST_REMOVE(olp, ol_q);
                         if (olp->ol_fd > 0)
                                 (void) close(olp->ol_fd);
                         free(olp->ol_devnm);
                         free(olp);

@@ -1573,22 +1544,20 @@
         ndmp_lbr_params_t *nlp;
         tlm_commands_t *cmds;
 
         session->ns_tape.td_pos = 0;
         if ((nlp = ndmp_get_nlp(session)) == NULL) {
-                NDMP_LOG(LOG_DEBUG, "nlp == NULL");
+                syslog(LOG_DEBUG, "nlp == NULL");
         } else {
                 cmds = &nlp->nlp_cmds;
-                if (cmds->tcs_command == NULL) {
-                        NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL");
-                } else {
+                if (cmds->tcs_command != NULL) {
                         cmds->tcs_reader = cmds->tcs_writer = TLM_ABORT;
                         cmds->tcs_command->tc_reader = TLM_ABORT;
                         cmds->tcs_command->tc_writer = TLM_ABORT;
                         while (cmds->tcs_reader_count > 0 ||
                             cmds->tcs_writer_count > 0) {
-                                NDMP_LOG(LOG_DEBUG,
+                                syslog(LOG_DEBUG,
                                     "trying to stop buffer worker");
                                 (void) sleep(1);
                         }
                 }
         }

@@ -1611,20 +1580,18 @@
 {
         ndmp_lbr_params_t *nlp;
         tlm_commands_t *cmds;
 
         if ((nlp = ndmp_get_nlp(session)) == NULL) {
-                NDMP_LOG(LOG_DEBUG, "nlp == NULL");
+                syslog(LOG_DEBUG, "nlp == NULL");
         } else {
                 cmds = &nlp->nlp_cmds;
-                if (cmds->tcs_command == NULL) {
-                        NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL");
-                } else {
+                if (cmds->tcs_command != NULL) {
                         cmds->tcs_reader = TLM_ABORT;
                         cmds->tcs_command->tc_reader = TLM_ABORT;
                         while (cmds->tcs_reader_count > 0) {
-                                NDMP_LOG(LOG_DEBUG,
+                                syslog(LOG_DEBUG,
                                     "trying to stop reader thread");
                                 (void) sleep(1);
                         }
                 }
         }

@@ -1647,23 +1614,21 @@
 {
         ndmp_lbr_params_t *nlp;
         tlm_commands_t *cmds;
 
         if ((nlp = ndmp_get_nlp(session)) == NULL) {
-                NDMP_LOG(LOG_DEBUG, "nlp == NULL");
+                syslog(LOG_DEBUG, "nlp == NULL");
         } else {
                 cmds = &nlp->nlp_cmds;
-                if (cmds->tcs_command == NULL) {
-                        NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL");
-                } else {
+                if (cmds->tcs_command != NULL) {
                         (void) mutex_lock(&nlp->nlp_mtx);
                         cmds->tcs_writer = TLM_ABORT;
                         cmds->tcs_command->tc_writer = TLM_ABORT;
                         (void) cond_broadcast(&nlp->nlp_cv);
                         (void) mutex_unlock(&nlp->nlp_mtx);
                         while (cmds->tcs_writer_count > 0) {
-                                NDMP_LOG(LOG_DEBUG,
+                                syslog(LOG_DEBUG,
                                     "trying to stop writer thread");
                                 (void) sleep(1);
                         }
                 }
         }

@@ -1689,11 +1654,11 @@
         tlm_commands_t *cmds;
 
         if ((nlp = ndmp_get_nlp(session)) != NULL) {
                 cmds = &nlp->nlp_cmds;
                 if (cmds->tcs_command != NULL) {
-                        NDMP_LOG(LOG_DEBUG, "cmds->tcs_command->tc_ref: %d",
+                        syslog(LOG_DEBUG, "cmds->tcs_command->tc_ref: %d",
                             cmds->tcs_command->tc_ref);
                         tlm_release_reader_writer_ipc(cmds->tcs_command);
                 }
         }
 }

@@ -1714,12 +1679,10 @@
 ndmp_waitfor_op(ndmpd_session_t *session)
 {
         if (session != NULL) {
                 while (session->ns_nref > 0) {
                         (void) sleep(1);
-                        NDMP_LOG(LOG_DEBUG,
-                            "waiting for session nref: %d", session->ns_nref);
                 }
         }
 }
 
 

@@ -1927,30 +1890,30 @@
 ndmp_connect_sock_v3(ulong_t addr, ushort_t port)
 {
         int sock;
         struct sockaddr_in sin;
 
-        NDMP_LOG(LOG_DEBUG, "addr %s:%d", inet_ntoa(IN_ADDR(addr)), port);
 
         sock = socket(AF_INET, SOCK_STREAM, 0);
         if (sock < 0) {
-                NDMP_LOG(LOG_DEBUG, "Socket error: %m");
+                syslog(LOG_DEBUG, "Socket error: %m");
                 return (-1);
         }
 
         (void) memset((void *) &sin, 0, sizeof (sin));
         sin.sin_family = AF_INET;
         sin.sin_addr.s_addr = htonl(addr);
         sin.sin_port = htons(port);
         if (connect(sock, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
-                NDMP_LOG(LOG_DEBUG, "Connect error: %m");
+                syslog(LOG_DEBUG, "Connect error: %m");
                 (void) close(sock);
                 return (-1);
         }
 
+        syslog(LOG_DEBUG, "Remote addr %s:%d", inet_ntoa(IN_ADDR(addr)), port);
+
         set_socket_options(sock);
-        NDMP_LOG(LOG_DEBUG, "sock %d", sock);
 
         return (sock);
 }
 
 /*

@@ -1986,36 +1949,36 @@
         if (!p)
                 p = get_default_nic_addr();
 
         /* Fail if no IP can be obtained */
         if (!p) {
-                NDMP_LOG(LOG_ERR, "Undetermined network port.");
+                syslog(LOG_ERR, "Undetermined network port.");
                 return (-1);
         }
 
         *addr = inet_addr(p);
 
         sd = socket(AF_INET, SOCK_STREAM, 0);
         if (sd < 0) {
-                NDMP_LOG(LOG_DEBUG, "Socket error: %m");
+                syslog(LOG_DEBUG, "Socket error: %m");
                 return (-1);
         }
         sin.sin_family = AF_INET;
         sin.sin_addr.s_addr = INADDR_ANY;
         sin.sin_port = 0;
         length = sizeof (sin);
 
         if (bind(sd, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
-                NDMP_LOG(LOG_DEBUG, "Bind error: %m");
+                syslog(LOG_DEBUG, "Bind error: %m");
                 (void) close(sd);
                 sd = -1;
         } else if (getsockname(sd, (struct sockaddr *)&sin, &length) < 0) {
-                NDMP_LOG(LOG_DEBUG, "getsockname error: %m");
+                syslog(LOG_DEBUG, "getsockname error: %m");
                 (void) close(sd);
                 sd = -1;
         } else if (listen(sd, 5) < 0) {
-                NDMP_LOG(LOG_DEBUG, "Listen error: %m");
+                syslog(LOG_DEBUG, "Listen error: %m");
                 (void) close(sd);
                 sd = -1;
         } else
                 *port = sin.sin_port;
 

@@ -2060,31 +2023,77 @@
 
 
 /*
  * ndmp_new_job_name
  *
- * Create a job name for each backup/restore to keep track
+ * Copy, at most, 'n' characters of the current backup
+ * job name to the buffer in parameter 's1'.
  *
  * Parameters:
- *   jname (output) - job name
  *
+ *   s1 (input) - pointer to a user supplied buffer
+ *   n  (input) - number of bytes to copy
+ *
  * Returns:
- *   jname
+ *   count of bytes in name
  */
-char *
-ndmp_new_job_name(char *jname)
-{
-        if (jname != NULL) {
-                (void) snprintf(jname, TLM_MAX_BACKUP_JOB_NAME, "%s%d",
-                    NDMP_RCF_BASENAME, ndmp_job_cnt++);
-                NDMP_LOG(LOG_DEBUG, "jname: \"%s\"", jname);
-        }
 
-        return (jname);
+int
+ndmp_new_job_name(char *s1, size_t n) {
+
+        if (n >= TLM_MAX_BACKUP_JOB_NAME) {
+                /*
+                 * TLM_MAX_BACKUP_JOB_NAME is the fixed length of
+                 * the encoded job name in the format `NdmpBackup.nnnn\0`,
+                 * where nnnn is a job sequence number.  A null byte
+                 * is included. It is okay if the buffer is bigger than that.
+                 */
+                return (snprintf(s1, n, "%10s.%04d",
+                    NDMP_RCF_BASENAME, ndmp_job_cnt++%1000));
+        }
+        return (0);
 }
 
+/*
+ * Check if the volume is already checkpointed. Assume it is not
+ * by setting nlp_snapname to '\0' at first. It will be filled
+ * in  with the checkpoint (snapshot name) if one is found.
+ */
+boolean_t
+fs_is_checkpointed(ndmp_lbr_params_t *nlp)
+{
+        zfs_handle_t *zhp;
+        snap_data_t si;
 
+        (void) mutex_lock(&zlib_mtx);
+        if ((zhp = zfs_open(zlibh, nlp->nlp_vol, ZFS_TYPE_DATASET)) != NULL) {
+                nlp->nlp_snapname[0] = '\0';
+                si.creation_time = (time_t)0;
+                si.last_snapshot = nlp->nlp_snapname;
+                if (ndmp_find_latest_autosync(zhp, (void *) &si) != 0) {
+                        syslog(LOG_ERR,
+                            "Find AutoSync failed (err=%d): %s",
+                            errno, libzfs_error_description(zlibh));
+                        zfs_close(zhp);
+                        (void) mutex_unlock(&zlib_mtx);
+                        return (B_FALSE);
+                }
+                zfs_close(zhp);
+                if (strlen(nlp->nlp_snapname) == 0) {
+                        syslog(LOG_DEBUG, "Apparently not an "
+                            "Auto-Sync - continue as normal backup");
+                        (void) mutex_unlock(&zlib_mtx);
+                        return (B_FALSE);
+                }
+        }
+        (void) mutex_unlock(&zlib_mtx);
+        syslog(LOG_DEBUG, "It is an autosync:");
+        syslog(LOG_DEBUG, "nlp->nlp_vol = [%s]", nlp->nlp_vol);
+        syslog(LOG_DEBUG, "nlp->nlp_snapname = [%s]", nlp->nlp_snapname);
+        return (B_TRUE);
+}
+
 /*
  * fs_is_valid_logvol
  *
  * Check if the log path exists
  *

@@ -2099,13 +2108,13 @@
 fs_is_valid_logvol(char *path)
 {
         struct stat64 st;
 
         if (stat64(path, &st) < 0)
-                return (FALSE);
+                return (B_FALSE);
 
-        return (TRUE);
+        return (B_TRUE);
 }
 
 
 /*
  * ndmpd_mk_temp

@@ -2118,45 +2127,101 @@
  *
  * Returns:
  *   buf
  */
 char *
-ndmpd_mk_temp(char *buf)
+ndmpd_mk_temp(char * fname, char *buf)
 {
-        char fname[TLM_MAX_BACKUP_JOB_NAME];
         const char *dir;
         char *rv;
 
         if (!buf)
                 return (NULL);
 
         dir = ndmpd_get_prop(NDMP_DEBUG_PATH);
         if (dir == 0 || *dir == '\0') {
-                NDMP_LOG(LOG_DEBUG, "NDMP work path not specified");
+                syslog(LOG_DEBUG, "NDMP work path not specified");
                 return (0);
         }
 
+        /*
+         * Make sure the NDMP work directory exists.
+         */
+        if (ndmpd_mkdir(dir) < 0) {
+                syslog(LOG_DEBUG,
+                    "Could not create NDMP work path %s", dir);
+                return (0);
+        }
+
         if (!fs_is_valid_logvol((char *)dir)) {
-                NDMP_LOG(LOG_ERR,
-                    "Log file path cannot be on system volumes.");
+                syslog(LOG_ERR,
+                    "Log file path cannot be on system volumes");
                 return (0);
         }
 
         dir += strspn(dir, " \t");
         if (!*dir) {
-                NDMP_LOG(LOG_DEBUG, "NDMP work path not specified");
+                syslog(LOG_DEBUG, "NDMP work path not specified");
                 return (0);
         }
 
         rv = buf;
-        (void) ndmp_new_job_name(fname);
+
         (void) tlm_cat_path(buf, (char *)dir, fname);
 
         return (rv);
 }
 
+/*
+ * ndmp_mkdir
+ *
+ * If the temporary bitmap database directory doesn't exist
+ * create it.  This keep from having to create directory
+ * by hand when it is changed with svcadm.
+ *
+ * Parameters:
+ *   dir (input) - the path to create
+ *
+ * Returns:
+ *   0 - success.
+ *  -1 - error.
+ */
+static int
+ndmpd_mkdir(const char *dir)
+{
+        char tmp[PATH_MAX];
+        char *p = NULL;
+        size_t len;
 
+        (void) snprintf(tmp, sizeof (tmp), "%s", dir);
+        len = strlen(tmp);
+        if (tmp[len - 1] == '/')
+                tmp[len - 1] = '\0';
+        for (p = tmp + 1; *p; p++) {
+                if (*p == '/') {
+                        *p = '\0';
+                        if (mkdir(tmp, S_IRWXU) < 0) {
+                                if (errno != EEXIST) {
+                                syslog(LOG_ERR,
+                                    "failed to create intermediate path %s\n",
+                                    tmp);
+                                return (-1);
+                                }
+                        }
+                        *p = '/';
+                }
+        }
+        if (mkdir(tmp, S_IRWXU) < 0) {
+                if (errno != EEXIST) {
+                syslog(LOG_ERR,
+                    "failed to create full path %s\n", tmp);
+                return (-1);
+                }
+        }
+        return (0);
+}
+
 /*
  * ndmpd_make_bk_dir_path
  *
  * Make a directory path for temporary files under the NDMP
  * working directory.

@@ -2191,12 +2256,72 @@
 
         (void) tlm_cat_path(buf, path, name);
         return (buf);
 }
 
+static int
+ndmp_match_checkpoint_name(zfs_handle_t *zhp, void *arg)
+{
+        snap_data_t *sd = (snap_data_t *)arg;
+        time_t snap_creation;
+        nvlist_t *userprops = NULL;
 
+        if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
+                if ((userprops = zfs_get_user_props(zhp)) != NULL) {
+                        /*
+                         * Destination AutoSync snap-shots have
+                         * 'nms:autosyncmark' property whereas the
+                         * source dataset snap-shot has has
+                         * 'nms:service' property. This finds either
+                         * for use as backup.
+                         */
+                        if (nvlist_exists(userprops, "nms:autosyncmark") ||
+                            nvlist_exists(userprops,
+                                "com.nexenta.nef:hprsvcid") ||
+                            nvlist_exists(userprops, "nms:service")) {
+                                snap_creation = (time_t)zfs_prop_get_int(zhp,
+                                    ZFS_PROP_CREATION);
+                                if (snap_creation > sd->creation_time) {
+                                        (void) strncpy(
+                                            (char *) sd->last_snapshot,
+                                            zfs_get_name(zhp),
+                                            ZFS_MAX_DATASET_NAME_LEN);
+                                        sd->creation_time = snap_creation;
+                                }
+                        }
+                }
+        }
+        zfs_close(zhp);
+        return (0);
+}
+
 /*
+ * ndmp_find_latest_autosync
+ *
+ * Given a dataset zfs_handlt_t find the latest "AutoSync" snapshot
+ */
+int
+ndmp_find_latest_autosync(zfs_handle_t *zhp, void *arg)
+{
+        int err;
+        snap_data_t *si = (snap_data_t *)arg;
+
+        err = zfs_iter_dependents(zhp, B_FALSE,
+            ndmp_match_checkpoint_name, (void *)si);
+        if (err) {
+                syslog(LOG_DEBUG,
+                    "Trying to find AutoSync zfs_iter_snapshots: %d", err);
+                si->last_snapshot = '\0';
+                return (-1);
+        } else {
+                syslog(LOG_DEBUG, "Found most recent AutoSync -> [%s]\n",
+                    si->last_snapshot);
+        }
+        return (0);
+}
+
+/*
  * ndmp_is_chkpnt_root
  *
  * Is this a root checkpoint (snapshot) directory.
  * Note: a temporary function
  */

@@ -2204,11 +2329,11 @@
 ndmp_is_chkpnt_root(char *path)
 {
         struct stat64 st;
 
         if (stat64(path, &st) != 0) {
-                NDMP_LOG(LOG_DEBUG, "Couldn't stat path \"%s\"", path);
+                syslog(LOG_DEBUG, "Couldn't stat path \"%s\"", path);
                 return (TRUE);
         }
         return (FALSE);
 }
 

@@ -2258,17 +2383,15 @@
         int rv;
         struct stat64 st;
 
         if (stat64(nlp->nlp_backup_path, &st) != 0) {
                 rv = -1;
-                NDMP_LOG(LOG_DEBUG, "Getting inode # of \"%s\"",
+                syslog(LOG_ERR, "Failed to get inode # of \"%s\"",
                     nlp->nlp_backup_path);
         } else {
                 rv = 0;
                 nlp->nlp_bkdirino = st.st_ino;
-                NDMP_LOG(LOG_DEBUG, "nlp_bkdirino: %lu",
-                    (uint_t)nlp->nlp_bkdirino);
         }
 
         return (rv);
 }
 

@@ -2287,15 +2410,15 @@
 {
         char *cp;
         int err, len, actual_size;
 
         if (cmd == NULL) {
-                NDMP_LOG(LOG_DEBUG, "cmd == NULL");
+                syslog(LOG_DEBUG, "cmd == NULL");
                 return (FALSE);
         }
         if (cmd->tc_buffers == NULL) {
-                NDMP_LOG(LOG_DEBUG, "cmd->tc_buffers == NULL");
+                syslog(LOG_DEBUG, "cmd->tc_buffers == NULL");
                 return (FALSE);
         }
 
         /* wait until the first buffer gets full. */
         tlm_buffer_in_buf_wait(cmd->tc_buffers);

@@ -2302,16 +2425,16 @@
 
         err = actual_size = 0;
         cp = tlm_get_read_buffer(RECORDSIZE, &err, cmd->tc_buffers,
             &actual_size);
         if (cp == NULL) {
-                NDMP_LOG(LOG_DEBUG, "Can't read from buffers, err: %d", err);
+                syslog(LOG_DEBUG, "Can't read from buffers, err: %d", err);
                 return (FALSE);
         }
         len = strlen(NDMPUTF8MAGIC);
         if (actual_size < len) {
-                NDMP_LOG(LOG_DEBUG, "Not enough data in the buffers");
+                syslog(LOG_DEBUG, "Not enough data in the buffers");
                 return (FALSE);
         }
 
         return ((strncmp(cp, NDMPUTF8MAGIC, len) == 0) ? TRUE : FALSE);
 }

@@ -2321,32 +2444,26 @@
  * ndmp_get_cur_bk_time
  *
  * Get the backup checkpoint time.
  */
 int
-ndmp_get_cur_bk_time(ndmp_lbr_params_t *nlp, time_t *tp, char *jname)
+ndmp_get_cur_bk_time(ndmp_lbr_params_t *nlp, time_t *tp)
 {
         int err;
 
-        if (!nlp || !nlp->nlp_backup_path || !tp) {
-                NDMP_LOG(LOG_DEBUG, "Invalid argument");
+        if (!nlp || !tp) {
+                syslog(LOG_ERR, "Invalid argument");
                 return (-1);
         }
 
-        if (!fs_is_chkpnt_enabled(nlp->nlp_backup_path)) {
-                NDMP_LOG(LOG_DEBUG, "Not a chkpnt volume %s",
-                    nlp->nlp_backup_path);
-                *tp = time(NULL);
-                return (0);
-        }
-
-        err = tlm_get_chkpnt_time(nlp->nlp_backup_path, !NLP_ISCHKPNTED(nlp),
-            tp, jname);
+        err = tlm_get_chkpnt_time(nlp->nlp_snapname, tp);
         if (err != 0) {
-                NDMP_LOG(LOG_DEBUG, "Can't checkpoint time");
+                syslog(LOG_ERR, "Can't checkpoint time from [%s]",
+                    nlp->nlp_snapname);
         } else {
-                NDMP_LOG(LOG_DEBUG, "%s", cctime(tp));
+                syslog(LOG_DEBUG, "Checkpoint time of [%s] is [%s]",
+                    nlp->nlp_snapname, cctime(tp));
         }
 
         return (err);
 }
 

@@ -2414,27 +2531,27 @@
         } else {
                 fd = dev_id;
         }
         do {
                 if (scsi_test_unit_ready(fd) >= 0) {
-                        NDMP_LOG(LOG_DEBUG, "Unit is ready");
+                        syslog(LOG_DEBUG, "Unit is ready");
 
                         if (dev_id <= 0)
                                 (void) close(fd);
 
                         return (TRUE);
                 }
 
-                NDMP_LOG(LOG_DEBUG, "Unit not ready");
+                syslog(LOG_DEBUG, "Unit not ready");
                 (void) usleep(TUR_WAIT);
 
         } while (--try > 0);
 
         if (dev_id <= 0)
                 (void) close(fd);
 
-        NDMP_LOG(LOG_DEBUG, "Unit didn't get ready");
+        syslog(LOG_DEBUG, "Unit didn't get ready");
         return (FALSE);
 }
 
 
 /*

@@ -2460,13 +2577,13 @@
         ucmd.uscsi_timeout = 60;        /* Allow maximum 1 min */
 
         retval = ioctl(dev_id, USCSICMD, &ucmd);
 
         if (retval != 0 && errno != EIO) {
-                NDMP_LOG(LOG_ERR,
+                syslog(LOG_ERR,
                     "Failed to send inquiry request to device: %m.");
-                NDMP_LOG(LOG_DEBUG, "Inquiry request failed for"
+                syslog(LOG_DEBUG, "Inquiry request failed for"
                     " dev_id:%d err=%d -%m", dev_id, errno);
                 retval = -errno;
         } else
                 retval = -(ucmd.uscsi_status);
 

@@ -2504,10 +2621,27 @@
         ndmp_fhinode = ndmpd_get_prop_yorn(NDMP_FHIST_INCR_ENV) ? TRUE : FALSE;
 
         /* Get the value from ndmp SMF property. */
         ndmp_dar_support = ndmpd_get_prop_yorn(NDMP_DAR_SUPPORT);
 
+        ndmp_autosync_support = ndmpd_get_prop_yorn(NDMP_AUTOSYNC_SUPPORT);
+        ndmp_hpr_support = ndmpd_get_prop_yorn(NDMP_HPR_SUPPORT);
+        /*
+         * The HPR snapshot feature superscedes autosync and the two can't be
+         * active together on the same system.
+         */
+        if (ndmp_hpr_support) {
+                ndmp_autosync_support = 0;
+                syslog(LOG_DEBUG, "NDMP_HPR_SUPPORT set to [%d]",
+                    ndmp_hpr_support);
+        }
+
+        if (ndmp_autosync_support) {
+                syslog(LOG_DEBUG, "NDMP_AUTOSYNC_SUPPORT set to [%d]",
+                    ndmp_autosync_support);
+        }
+
         if ((ndmp_ver = atoi(ndmpd_get_prop(NDMP_VERSION_ENV))) == 0)
                 ndmp_ver = NDMPVER;
 }
 
 /*