OpenSolaris_b135/cmd/ndmpd/ndmp/ndmpd_mark.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * 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.
 */
#include <sys/stat.h>
#include <sys/types.h>
#include <cstack.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include "ndmpd.h"
#include <bitmap.h>
#include <traverse.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "tlm_buffers.h"


/*
 * Parameter passed to traverse for marking inodes
 * when traversing backup hierarchy in V2.  It
 * includes:
 *    mp_bmd: the bitmap describptor.
 *    mp_ddate: backup date.
 *    mp_session: pointer to the session structure.
 *    mp_nlp: pointer to the nlp.
 *    mp_tacl: pointer to the acl.
 */
typedef struct mark_param {
	int mp_bmd;
	time_t mp_ddate;
	ndmpd_session_t *mp_session;
	ndmp_lbr_params_t *mp_nlp;
	tlm_acls_t *mp_tacl;
} mark_param_t;


/*
 * Set this variable to non-zero to print the inodes
 * marked after traversing file system.
 */
static int ndmpd_print_inodes = 0;


/*
 * Flag passed to traverse_post.
 */
static int ndmpd_mark_flags = 0;


/*
 * Verbose traversing prints the file/dir path names
 * if they are being marked.
 */
static int ndmpd_verbose_traverse = 0;


/*
 * Set this flag to count the number of inodes marked
 * after traversing backup hierarchy.
 */
static int ndmpd_mark_count_flag = 0;


/*
 * Set this variable to non-zero value to force traversing
 * backup hierarchy for tar format.
 */
static int ndmp_tar_force_traverse = 0;


/*
 * Set this variable to non-zero value to skip processing
 * directories both for tar and dump.
 */
static int ndmp_skip_traverse = 0;


/*
 * count_bits_cb
 *
 * Call back for counting the set bits in the dbitmap.
 *
 * Parameters:
 *   bmd (input) - bitmap descriptor
 *   bn (input) - the bit number
 *   arg (input) - pointer to the argument
 *
 * Returns:
 *   0: always
 */
static int
count_bits_cb(int bmd, u_longlong_t bn, void *arg)
{
	if (dbm_getone(bmd, bn)) {
		(*(u_longlong_t *)arg)++;
		if (ndmpd_print_inodes)
			NDMP_LOG(LOG_DEBUG, "%llu", bn);
	}

	return (0);
}


/*
 * count_set_bits
 *
 * Count bits set in the bitmap.
 *
 * Parameters:
 *   path (input) - the backup path
 *   bmd (input) - bitmap descriptor
 *
 * Returns:
 *   void
 */
void
count_set_bits(char *path, int bmd)
{
	u_longlong_t cnt;

	if (!ndmpd_mark_count_flag)
		return;

	cnt = 0;
	(void) dbm_apply_ifset(bmd, count_bits_cb, &cnt);
	NDMP_LOG(LOG_DEBUG, "%s %llu inodes marked", path, cnt);
}


/*
 * traverse
 *
 * Starts the post-traverse the backup hierarchy.  Checks
 * for exceptional cases, like aborting operation and if
 * asked, report detailed information after traversing.
 *
 * Parameters:
 *   session (input) - pointer to the session
 *   nlp (input) - pointer to the nlp structure
 *   ftp (input) - pointer to the traverse parameters
 *
 * Returns:
 *   0: on success
 *   != 0: otherwise
 */
int
traverse(ndmpd_session_t *session, ndmp_lbr_params_t *nlp,
    fs_traverse_t *ftp)
{
	int rv;
	time_t s, e;

	if (!session || !nlp || !ftp) {
		NDMP_LOG(LOG_DEBUG, "Invalid argument");
		return (-1);
	}
	NDMP_LOG(LOG_DEBUG, "Processing directories of \"%s\"",
	    nlp->nlp_backup_path);

	(void) time(&s);
	if (traverse_post(ftp) != 0) {
		rv = -1;
		if (!session->ns_data.dd_abort && !NLP_ISSET(nlp,
		    NLPF_ABORTED)) {
			NDMP_LOG(LOG_DEBUG,
			    "Traversing backup path hierarchy \"%s\"",
			    nlp->nlp_backup_path);
		}
	} else {
		(void) dbm_setone(nlp->nlp_bkmap, (u_longlong_t)ROOT_INODE);
		rv = 0;
		(void) time(&e);
		NDMP_LOG(LOG_DEBUG,
		    "\"%s\" traversed in %u sec", nlp->nlp_backup_path,
		    (uint_t)(e-s));

		count_set_bits(nlp->nlp_backup_path, nlp->nlp_bkmap);
	}

	return (rv);
}


/*
 * mark_cb
 *
 * The callback function, called by traverse_post to mark bits
 * in the bitmap.
 *
 * Set the bit of the entry if it's been modified (obviously
 * should be backed up) plus its parent directory.
 *
 * If the entry is a directory and is not modified itself,
 * but it's marked, then there is something below it that
 * is being backed up.  It shows the the path, leads to
 * an object that will be backed up. So the path should
 * be marked too.
 *
 * The backup path itself is always marked.
 *
 * Parameters:
 *   arg (input) - pointer to the mark parameter
 *   pnp (input) - pointer to the path node
 *   enp (input) - pointer to the entry node
 *
 * Returns:
 *   0: as long as traversing should continue
 *   != 0: if traversing should stop
 */
int
mark_cb(void *arg, fst_node_t *pnp, fst_node_t *enp)
{
	int bmd;
	int rv;
	u_longlong_t bl;
	time_t ddate;
	fs_fhandle_t *pfhp, *efhp;
	struct stat64 *pstp, *estp;
	mark_param_t *mpp;
	ndmp_lbr_params_t *nlp;
	tlm_acls_t *tacl;

	rv = 0;
	mpp = (mark_param_t *)arg;
	tacl = mpp->mp_tacl;
	nlp = ndmp_get_nlp(mpp->mp_session);
	if (!mpp) {
		NDMP_LOG(LOG_DEBUG, "NULL argument passed");
		rv = -1;
	} else if (mpp->mp_session->ns_eof) {
		NDMP_LOG(LOG_INFO, "Connection to the client is closed");
		rv = -1;
	} else if (mpp->mp_session->ns_data.dd_abort ||
	    (nlp && NLP_ISSET(nlp, NLPF_ABORTED))) {
		NDMP_LOG(LOG_INFO, "Processing directories aborted.");
		rv = -1;
	}

	if (rv != 0)
		return (rv);

	ddate = mpp->mp_ddate;
	bmd = mpp->mp_bmd;
	bl = dbm_getlen(bmd);

	pfhp = pnp->tn_fh;
	pstp = pnp->tn_st;

	/* sanity check on fh and stat of the path passed */
	if (pstp->st_ino > bl) {
		NDMP_LOG(LOG_DEBUG, "Invalid path inode #%u",
		    (uint_t)pstp->st_ino);
		return (-1);
	}
	if (pstp->st_ino != pfhp->fh_fid) {
		NDMP_LOG(LOG_DEBUG, "Path ino mismatch %u %u",
		    (uint_t)pstp->st_ino, (uint_t)pfhp->fh_fid);
		return (-1);
	}

	/*
	 * Always mark the backup path inode number.
	 */
	if (!enp->tn_path) {
		(void) dbm_setone(bmd, pstp->st_ino);
		return (0);
	}

	efhp = enp->tn_fh;
	estp = enp->tn_st;

	/* sanity check on fh and stat of the entry passed */
	if (estp->st_ino > bl) {
		NDMP_LOG(LOG_DEBUG, "Invalid entry inode #%u",
		    (uint_t)estp->st_ino);
		return (-1);
	}
	if (estp->st_ino != efhp->fh_fid) {
		NDMP_LOG(LOG_DEBUG, "Entry ino mismatch %u %u", estp->st_ino,
		    (uint_t)pfhp->fh_fid);
		return (-1);
	}

	/* check the dates and mark the bitmap inode */
	if (ddate == 0) {
		/* base backup */
		(void) dbm_setone(bmd, (u_longlong_t)estp->st_ino);
		(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
		if (ndmpd_verbose_traverse) {
			NDMP_LOG(LOG_DEBUG, "Base Backup");
			NDMP_LOG(LOG_DEBUG, "\"%s/%s\"",
			    pnp->tn_path, enp->tn_path);
		}

	} else if (estp->st_mtime > ddate) {
		(void) dbm_setone(bmd, (u_longlong_t)estp->st_ino);
		(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
		if (ndmpd_verbose_traverse) {
			NDMP_LOG(LOG_DEBUG,
			    "m(%u,%u,%u,%u)", (uint_t)pstp->st_ino,
			    (uint_t)estp->st_ino, (uint_t)estp->st_mtime,
			    (uint_t)ddate);
			NDMP_LOG(LOG_DEBUG, "\"%s/%s\"",
			    pnp->tn_path, enp->tn_path);
		}
	} else if (iscreated(nlp, NULL, tacl, ddate)) {
		(void) dbm_setone(bmd, (u_longlong_t)estp->st_ino);
		(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
		if (ndmpd_verbose_traverse) {
			NDMP_LOG(LOG_DEBUG,
			    "cr(%u,%u,%u,%u)", (uint_t)pstp->st_ino,
			    (uint_t)estp->st_ino, (uint_t)estp->st_mtime,
			    (uint_t)ddate);
			NDMP_LOG(LOG_DEBUG, "\"%s/%s\"",
			    pnp->tn_path, enp->tn_path);
		}
	} else if (estp->st_ctime > ddate) {
		if (!NLP_IGNCTIME(nlp)) {
			(void) dbm_setone(bmd, (u_longlong_t)estp->st_ino);
			(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
		}
		if (ndmpd_verbose_traverse) {
			if (NLP_IGNCTIME(nlp)) {
				NDMP_LOG(LOG_DEBUG,
				    "ign c(%u,%u,%u,%u)", (uint_t)pstp->st_ino,
				    (uint_t)estp->st_ino,
				    (uint_t)estp->st_ctime, (uint_t)ddate);
			} else {
				NDMP_LOG(LOG_DEBUG,
				    "c(%u,%u,%u,%u)", (uint_t)pstp->st_ino,
				    (uint_t)estp->st_ino,
				    (uint_t)estp->st_ctime, (uint_t)ddate);
			}
			NDMP_LOG(LOG_DEBUG, "\"%s/%s\"",
			    pnp->tn_path, enp->tn_path);
		}
	} else if (S_ISDIR(estp->st_mode) &&
	    dbm_getone(bmd, (u_longlong_t)estp->st_ino)) {
		(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
		if (ndmpd_verbose_traverse) {
			NDMP_LOG(LOG_DEBUG, "d(%u,%u)",
			    (uint_t)pstp->st_ino, (uint_t)estp->st_ino);
			NDMP_LOG(LOG_DEBUG, "\"%s, %s\"",
			    pnp->tn_path, enp->tn_path);
		}
	}

	return (0);
}


/*
 * mark_inodes_v2
 *
 * Traverse the file system in post-order and mark
 * all the modified objects and also directories leading
 * to them.
 *
 * Parameters:
 *   session (input) - pointer to the session
 *   nlp (input) - pointer to the nlp structure
 *   path (input) - the physical path to traverse
 *
 * Returns:
 *   0: on success.
 *   != 0: on error.
 */
int
mark_inodes_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp, char *path)
{
	fs_traverse_t ft;
	mark_param_t mp;

	if (!session || !nlp || !path || !*path) {
		NDMP_LOG(LOG_DEBUG, "Invalid argument");
		return (-1);
	}

	NDMP_LOG(LOG_DEBUG, "path \"%s\"", path);

	mp.mp_bmd = nlp->nlp_bkmap;
	mp.mp_ddate = nlp->nlp_ldate;
	mp.mp_session = session;
	mp.mp_nlp = nlp;

	ft.ft_path = path;
	ft.ft_lpath = nlp->nlp_backup_path;
	ft.ft_callbk = mark_cb;
	ft.ft_arg = &mp;
	ft.ft_logfp = (ft_log_t)ndmp_log;
	ft.ft_flags = ndmpd_mark_flags;

	return (traverse(session, nlp, &ft));
}


/*
 * create_bitmap
 *
 * Create a dbitmap and return its descriptor.
 *
 * Parameters:
 *   path (input) - path for which the bitmap should be created
 *   value (input) - the initial value for the bitmap
 *
 * Returns:
 *   the dbitmap descriptor
 */
static int
create_bitmap(char *path, int value)
{
	char bm_fname[PATH_MAX];
	char buf[TLM_MAX_PATH_NAME];
	char *livepath;
	ulong_t ninode;

	NDMP_LOG(LOG_DEBUG, "path \"%s\"", path);

	if (fs_is_chkpntvol(path))
		livepath = (char *)tlm_remove_checkpoint(path, buf);
	else
		livepath = path;
	ninode = 1024 * 1024 * 1024;
	if (ninode == 0)
		return (-1);
	(void) ndmpd_mk_temp(bm_fname);

	NDMP_LOG(LOG_DEBUG, "path \"%s\"ninode %u bm_fname \"%s\"",
	    livepath, ninode, bm_fname);

	return (dbm_alloc(bm_fname, (u_longlong_t)ninode, value));
}


/*
 * create_allset_bitmap
 *
 * A helper function to create a bitmap with all the
 * values set to 1.
 *
 * Parameters:
 *   nlp (input) - pointer to the nlp structure
 *
 * Returns:
 *   the dbitmap descriptor
 */
static int
create_allset_bitmap(ndmp_lbr_params_t *nlp)
{
	int rv;

	nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 1);
	NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);

	if (nlp->nlp_bkmap < 0) {
		NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
		rv = -1;
	} else
		rv = 0;

	return (rv);
}


/*
 * mark_common_v2
 *
 * Create the inode bitmap.  If last date of the the
 * backup is epoch, then all the objects should be backed
 * up; there is no need to traverse the backup hierarchy
 * and mark the inodes.  All the bits should be marked.
 *
 * Otherwise, the backup hierarchy should be traversed and
 * the objects should be marked.
 *
 * Parameters:
 *   session (input) - pointer to the session
 *   nlp (input) - pointer to the nlp structure
 *
 * Returns:
 *   0: on success.
 *   != 0: on error.
 */
static int
mark_common_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
{
	char buf[TLM_MAX_PATH_NAME], *chkpath;
	int rv;

	/*
	 * Everything is needed for full backup.
	 */
	if (nlp->nlp_ldate == (time_t)0)
		return (create_allset_bitmap(nlp));

	rv = 0;
	nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0);
	NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);

	if (nlp->nlp_bkmap < 0) {
		NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
		rv = -1;
	} else {
		if (fs_is_chkpntvol(nlp->nlp_backup_path))
			chkpath = nlp->nlp_backup_path;
		else
			chkpath = tlm_build_snapshot_name(
			    nlp->nlp_backup_path, buf,
			    nlp->nlp_jstat->js_job_name);
		rv = mark_inodes_v2(session, nlp, chkpath);
		(void) dbm_setone(nlp->nlp_bkmap, (u_longlong_t)ROOT_INODE);
	}

	return (rv);
}


/*
 * mark_tar_inodes_v2
 *
 * Create the bitmap for tar backup format.
 *
 * Parameters:
 *   session (input) - pointer to the session
 *   nlp (input) - pointer to the nlp structure
 *
 * Returns:
 *   0: on success.
 *   != 0: on error.
 */
static int
mark_tar_inodes_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
{
	int rv;

	if (ndmp_tar_force_traverse)
		rv = mark_common_v2(session, nlp);
	else
		rv = create_allset_bitmap(nlp);

	return (rv);
}


/*
 * mark_dump_inodes_v2
 *
 * Create the bitmap for dump backup format.
 *
 * Parameters:
 *   session (input) - pointer to the session
 *   nlp (input) - pointer to the nlp structure
 *
 * Returns:
 *   0: on success.
 *   != 0: on error.
 */
static int
mark_dump_inodes_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
{
	return (mark_common_v2(session, nlp));
}


/*
 * ndmpd_mark_inodes_v2
 *
 * Mark the inodes of the backup hierarchy if necessary.
 *
 * Parameters:
 *   session (input) - pointer to the session
 *   nlp (input) - pointer to the nlp structure
 *
 * Returns:
 *   0: on success.
 *   != 0: on error.
 */
int
ndmpd_mark_inodes_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
{
	int rv;

	if (ndmp_skip_traverse) {
		NDMP_LOG(LOG_INFO, "Skip processing directories \"%s\"",
		    nlp->nlp_backup_path);
		rv = create_allset_bitmap(nlp);
	} else {
		if (NLP_ISTAR(nlp))
			rv = mark_tar_inodes_v2(session, nlp);
		else if (NLP_ISDUMP(nlp))
			rv = mark_dump_inodes_v2(session, nlp);
		else {
			NDMP_LOG(LOG_DEBUG, "Unknown backup type for \"%s\"",
			    nlp->nlp_backup_path);
			rv = -1;
		}
	}

	return (rv);
}


/*
 * ndmpd_abort_making_v2
 *
 * Abort the process of marking inodes.
 *
 * Parameters:
 *   session (input) - pointer to the session
 *
 * Returns:
 *   void
 */
void
ndmpd_abort_marking_v2(ndmpd_session_t *session)
{
	ndmp_lbr_params_t *nlp;

	nlp = ndmp_get_nlp(session);
	if (nlp)
		NLP_SET(nlp, NLPF_ABORTED);
}


/*
 * mark_tokv3
 *
 * Traverse the backup hierarchy and mark the bits for the
 * modified objects of directories leading to a modified
 * object for the token-based backup.
 *
 * Parameters:
 *   session (input) - pointer to the session
 *   nlp (input) - pointer to the nlp structure
 *   path (input) - the physical path to traverse
 *
 * Returns:
 *   0: on success
 *   != 0: otherwise
 */
int
mark_tokv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp, char *path)
{
	fs_traverse_t ft;
	mark_param_t mp;

	if (!session || !nlp || !path || !*path) {
		NDMP_LOG(LOG_DEBUG, "Invalid argument");
		return (-1);
	}
	if (nlp->nlp_tokdate == (time_t)0)
		return (create_allset_bitmap(nlp));

	nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0);
	if (nlp->nlp_bkmap < 0) {
		NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
		return (-1);
	}
	NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);

	mp.mp_bmd = nlp->nlp_bkmap;
	mp.mp_ddate = nlp->nlp_tokdate;
	mp.mp_session = session;
	mp.mp_nlp = nlp;

	ft.ft_path = path;
	ft.ft_lpath = nlp->nlp_backup_path;
	ft.ft_callbk = mark_cb;
	ft.ft_arg = &mp;
	ft.ft_logfp = (ft_log_t)ndmp_log;
	ft.ft_flags = ndmpd_mark_flags;

	return (traverse(session, nlp, &ft));
}


/*
 * marklbrv3_cb
 *
 * The callback function, called by traverse_post to mark
 * bits in the bitmap.
 *
 * It's so much like mark_cb for time-based (token-based
 * and level-type) backup types, except that it looks at
 * the archive bit of the objects instead of their timestamp.
 *
 * Parameters:
 *   arg (input) - pointer to the mark parameter
 *   pnp (input) - pointer to the path node
 *   enp (input) - pointer to the entry node
 *
 * Returns:
 *   0: as long as traversing should continue
 *   != 0: if traversing should stop
 */
int
marklbrv3_cb(void *arg, fst_node_t *pnp, fst_node_t *enp)
{
	int bmd;
	u_longlong_t bl;
	fs_fhandle_t *pfhp, *efhp;
	struct stat64 *pstp, *estp;
	mark_param_t *mpp;
	ndmp_lbr_params_t *nlp;

	mpp = (mark_param_t *)arg;
	if (!mpp) {
		NDMP_LOG(LOG_DEBUG, "NULL argument passed");
		return (-1);
	}
	nlp = ndmp_get_nlp(mpp->mp_session);
	if (mpp->mp_session->ns_data.dd_abort ||
	    (nlp && NLP_ISSET(nlp, NLPF_ABORTED))) {
		NDMP_LOG(LOG_INFO, "Processing directories aborted.");
		return (-1);
	}

	bmd = mpp->mp_bmd;
	bl = dbm_getlen(bmd);

	pfhp = pnp->tn_fh;
	pstp = pnp->tn_st;

	/* sanity check on fh and stat of the path passed */
	if (pstp->st_ino > bl) {
		NDMP_LOG(LOG_DEBUG, "Invalid path inode #%u",
		    (uint_t)pstp->st_ino);
		return (-1);
	}
	if (pstp->st_ino != pfhp->fh_fid) {
		NDMP_LOG(LOG_DEBUG, "Path ino mismatch %u %u",
		    (uint_t)pstp->st_ino, (uint_t)pfhp->fh_fid);
		return (-1);
	}

	/*
	 * Always mark the backup path inode number.
	 */
	if (!enp->tn_path) {
		(void) dbm_setone(bmd, pstp->st_ino);
		if (ndmpd_verbose_traverse) {
			NDMP_LOG(LOG_DEBUG, "d(%u)", (uint_t)pstp->st_ino);
			NDMP_LOG(LOG_DEBUG, "\"%s\"", pnp->tn_path);
		}
		return (0);
	}

	efhp = enp->tn_fh;
	estp = enp->tn_st;

	/* sanity check on fh and stat of the entry passed */
	if (estp->st_ino > bl) {
		NDMP_LOG(LOG_DEBUG, "Invalid entry inode #%u",
		    (uint_t)estp->st_ino);
		return (-1);
	}
	if (estp->st_ino != efhp->fh_fid) {
		NDMP_LOG(LOG_DEBUG, "Entry ino mismatch %u %u", estp->st_ino,
		    (uint_t)pfhp->fh_fid);
		return (-1);
	}

	if (S_ISDIR(estp->st_mode) &&
	    dbm_getone(bmd, (u_longlong_t)estp->st_ino)) {
		(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
		if (ndmpd_verbose_traverse) {
			NDMP_LOG(LOG_DEBUG, "d(%u,%u)",
			    (uint_t)pstp->st_ino, (uint_t)estp->st_ino);
			NDMP_LOG(LOG_DEBUG, "\"%s, %s\"",
			    pnp->tn_path, enp->tn_path);
		}
	}

	return (0);
}


/*
 * mark_lbrv3
 *
 * Traverse the backup hierarchy and mark the bits for the
 * modified objects of directories leading to a modified
 * object for the LBR-type backup.
 *
 * Parameters:
 *   session (input) - pointer to the session
 *   nlp (input) - pointer to the nlp structure
 *   path (input) - the physical path to traverse
 *
 * Returns:
 *   0: on success
 *   != 0: otherwise
 */
int
mark_lbrv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp, char *path)
{
	char c;
	fs_traverse_t ft;
	mark_param_t mp;

	if (!session || !nlp || !path || !*path) {
		NDMP_LOG(LOG_DEBUG, "Invalid argument");
		return (-1);
	}
	/* full and archive backups backup everything */
	c = toupper(nlp->nlp_clevel);
	if (c == 'F' || c == 'A')
		return (create_allset_bitmap(nlp));

	nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0);
	if (nlp->nlp_bkmap < 0) {
		NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
		return (-1);
	}
	NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);

	mp.mp_bmd = nlp->nlp_bkmap;
	mp.mp_ddate = 0;
	mp.mp_session = session;
	mp.mp_nlp = nlp;

	ft.ft_path = path;
	ft.ft_lpath = nlp->nlp_backup_path;
	ft.ft_callbk = marklbrv3_cb;
	ft.ft_arg = &mp;
	ft.ft_logfp = (ft_log_t)ndmp_log;
	ft.ft_flags = ndmpd_mark_flags;

	return (traverse(session, nlp, &ft));
}


/*
 * mark_levelv3
 *
 * Traverse the backup hierarchy and mark the bits for the
 * modified objects of directories leading to a modified
 * object for the level-type backup.
 *
 * Parameters:
 *   session (input) - pointer to the session
 *   nlp (input) - pointer to the nlp structure
 *   path (input) - the physical path to traverse
 *
 * Returns:
 *   0: on success
 *   != 0: otherwise
 */
int
mark_levelv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp, char *path)
{
	fs_traverse_t ft;
	mark_param_t mp;
	tlm_acls_t traverse_acl;

	if (!session || !nlp || !path || !*path) {
		NDMP_LOG(LOG_DEBUG, "Invalid argument");
		return (-1);
	}
	if (nlp->nlp_ldate == (time_t)0)
		return (create_allset_bitmap(nlp));

	nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0);
	if (nlp->nlp_bkmap < 0) {
		NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
		return (-1);
	}
	NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);

	/*
	 * We do not want to allocate memory for acl every time we
	 * process a file.
	 */
	(void) memset(&traverse_acl, 0, sizeof (traverse_acl));
	mp.mp_tacl = &traverse_acl;

	mp.mp_bmd = nlp->nlp_bkmap;
	mp.mp_ddate = nlp->nlp_ldate;
	mp.mp_session = session;
	mp.mp_nlp = nlp;

	ft.ft_path = path;
	ft.ft_lpath = nlp->nlp_backup_path;
	ft.ft_callbk = mark_cb;
	ft.ft_arg = &mp;
	ft.ft_logfp = (ft_log_t)ndmp_log;
	ft.ft_flags = ndmpd_mark_flags;

	return (traverse(session, nlp, &ft));
}


/*
 * mark_commonv3
 *
 * Create the inode bitmap.  If last date of the the
 * backup is epoch, then all the objects should be backed
 * up; there is no need to traverse the backup hierarchy
 * and mark the inodes.  All the bits should be marked.
 *
 * Otherwise, the backup hierarchy should be traversed and
 * the objects should be marked.
 *
 * Parameters:
 *   session (input) - pointer to the session
 *   nlp (input) - pointer to the nlp structure
 *
 * Returns:
 *   0: on success.
 *   != 0: on error.
 */
int
mark_commonv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
{
	char buf[TLM_MAX_PATH_NAME], *chkpath;
	int rv;

	if (NLP_ISCHKPNTED(nlp))
		chkpath = nlp->nlp_backup_path;
	else
		chkpath = tlm_build_snapshot_name(nlp->nlp_backup_path, buf,
		    nlp->nlp_jstat->js_job_name);

	if (NLP_ISSET(nlp, NLPF_TOKENBK))
		rv = mark_tokv3(session, nlp, chkpath);
	else if (NLP_ISSET(nlp, NLPF_LBRBK))
		rv = mark_lbrv3(session, nlp, chkpath);
	else if (NLP_ISSET(nlp, NLPF_LEVELBK)) {
		rv = mark_levelv3(session, nlp, chkpath);
	} else {
		rv = -1;
		NDMP_LOG(LOG_DEBUG, "Unknown backup type for \"%s\"",
		    nlp->nlp_backup_path);
	}

	return (rv);
}


/*
 * mark_tar_inodesv3
 *
 * Mark bits for tar backup format of V3.  Normally, the
 * backup hierarchy is not traversed for tar format
 * unless it's forced by setting the ndmp_tar_force_traverse
 * to a non-zero value.
 *
 * Parameters:
 *   session (input) - pointer to the session
 *   nlp (input) - pointer to the nlp structure
 *
 * Returns:
 *   0: on success
 *   != 0: otherwise
 */
int
mark_tar_inodesv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
{
	int rv;

	if (ndmp_tar_force_traverse)
		rv = mark_commonv3(session, nlp);
	else
		rv = create_allset_bitmap(nlp);

	return (rv);
}


/*
 * ndmpd_mark_inodes_v3
 *
 * Mark the inodes of the backup hierarchy if necessary.
 *
 * Parameters:
 *   session (input) - pointer to the session
 *   nlp (input) - pointer to the nlp structure
 *
 * Returns:
 *   0: on success.
 *   != 0: on error.
 */
int
ndmpd_mark_inodes_v3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
{
	int rv;

	if (ndmp_skip_traverse) {
		NDMP_LOG(LOG_INFO, "Skip processing directories \"%s\"",
		    nlp->nlp_backup_path);
		rv = create_allset_bitmap(nlp);
	} else {
		if (NLP_ISTAR(nlp))
			rv = mark_tar_inodesv3(session, nlp);
		else if (NLP_ISDUMP(nlp)) {
			rv = mark_commonv3(session, nlp);
		} else {
			NDMP_LOG(LOG_DEBUG, "Unknown backup type for \"%s\"",
			    nlp->nlp_backup_path);
			rv = -1;
		}
	}

	return (rv);
}