xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_mark.c (revision 55d6cb5d63bcf69dfa47b8c41c770a2d34f169b0)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * BSD 3 Clause License
8  *
9  * Copyright (c) 2007, The Storage Networking Industry Association.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 	- Redistributions of source code must retain the above copyright
15  *	  notice, this list of conditions and the following disclaimer.
16  *
17  * 	- Redistributions in binary form must reproduce the above copyright
18  *	  notice, this list of conditions and the following disclaimer in
19  *	  the documentation and/or other materials provided with the
20  *	  distribution.
21  *
22  *	- Neither the name of The Storage Networking Industry Association (SNIA)
23  *	  nor the names of its contributors may be used to endorse or promote
24  *	  products derived from this software without specific prior written
25  *	  permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <cstack.h>
42 #include <ctype.h>
43 #include <dirent.h>
44 #include <errno.h>
45 #include "ndmpd.h"
46 #include <bitmap.h>
47 #include <traverse.h>
48 #include <limits.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <time.h>
53 #include "tlm_buffers.h"
54 
55 
56 /*
57  * Parameter passed to traverse for marking inodes
58  * when traversing backup hierarchy in V2.  It
59  * includes:
60  *    mp_bmd: the bitmap describptor.
61  *    mp_ddate: backup date.
62  *    mp_session: pointer to the session structure.
63  *    mp_nlp: pointer to the nlp.
64  *    mp_tacl: pointer to the acl.
65  */
66 typedef struct mark_param {
67 	int mp_bmd;
68 	time_t mp_ddate;
69 	ndmpd_session_t *mp_session;
70 	ndmp_lbr_params_t *mp_nlp;
71 	tlm_acls_t *mp_tacl;
72 } mark_param_t;
73 
74 
75 /*
76  * Set this variable to non-zero to print the inodes
77  * marked after traversing file system.
78  */
79 static int ndmpd_print_inodes = 0;
80 
81 
82 /*
83  * Flag passed to traverse_post.
84  */
85 static int ndmpd_mark_flags = 0;
86 
87 
88 /*
89  * Verbose traversing prints the file/dir path names
90  * if they are being marked.
91  */
92 static int ndmpd_verbose_traverse = 0;
93 
94 
95 /*
96  * Set this flag to count the number of inodes marked
97  * after traversing backup hierarchy.
98  */
99 static int ndmpd_mark_count_flag = 0;
100 
101 
102 /*
103  * Set this variable to non-zero value to force traversing
104  * backup hierarchy for tar format.
105  */
106 static int ndmp_tar_force_traverse = 0;
107 
108 
109 /*
110  * Set this variable to non-zero value to skip processing
111  * directories both for tar and dump.
112  */
113 static int ndmp_skip_traverse = 0;
114 
115 
116 /*
117  * count_bits_cb
118  *
119  * Call back for counting the set bits in the dbitmap.
120  *
121  * Parameters:
122  *   bmd (input) - bitmap descriptor
123  *   bn (input) - the bit number
124  *   arg (input) - pointer to the argument
125  *
126  * Returns:
127  *   0: always
128  */
129 static int
130 count_bits_cb(int bmd, u_longlong_t bn, void *arg)
131 {
132 	if (dbm_getone(bmd, bn)) {
133 		(*(u_longlong_t *)arg)++;
134 		if (ndmpd_print_inodes)
135 			NDMP_LOG(LOG_DEBUG, "%llu", bn);
136 	}
137 
138 	return (0);
139 }
140 
141 
142 /*
143  * count_set_bits
144  *
145  * Count bits set in the bitmap.
146  *
147  * Parameters:
148  *   path (input) - the backup path
149  *   bmd (input) - bitmap descriptor
150  *
151  * Returns:
152  *   void
153  */
154 void
155 count_set_bits(char *path, int bmd)
156 {
157 	u_longlong_t cnt;
158 
159 	if (!ndmpd_mark_count_flag)
160 		return;
161 
162 	cnt = 0;
163 	(void) dbm_apply_ifset(bmd, count_bits_cb, &cnt);
164 	NDMP_LOG(LOG_DEBUG, "%s %llu inodes marked", path, cnt);
165 }
166 
167 
168 /*
169  * traverse
170  *
171  * Starts the post-traverse the backup hierarchy.  Checks
172  * for exceptional cases, like aborting operation and if
173  * asked, report detailed information after traversing.
174  *
175  * Parameters:
176  *   session (input) - pointer to the session
177  *   nlp (input) - pointer to the nlp structure
178  *   ftp (input) - pointer to the traverse parameters
179  *
180  * Returns:
181  *   0: on success
182  *   != 0: otherwise
183  */
184 int
185 traverse(ndmpd_session_t *session, ndmp_lbr_params_t *nlp,
186     fs_traverse_t *ftp)
187 {
188 	int rv;
189 	time_t s, e;
190 
191 	if (!session || !nlp || !ftp) {
192 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
193 		return (-1);
194 	}
195 	NDMP_LOG(LOG_DEBUG, "Processing directories of \"%s\"",
196 	    nlp->nlp_backup_path);
197 
198 	(void) time(&s);
199 	if (traverse_post(ftp) != 0) {
200 		rv = -1;
201 		if (!session->ns_data.dd_abort && !NLP_ISSET(nlp,
202 		    NLPF_ABORTED)) {
203 			NDMP_LOG(LOG_DEBUG,
204 			    "Traversing backup path hierarchy \"%s\"",
205 			    nlp->nlp_backup_path);
206 		}
207 	} else {
208 		(void) dbm_setone(nlp->nlp_bkmap, (u_longlong_t)ROOT_INODE);
209 		rv = 0;
210 		(void) time(&e);
211 		NDMP_LOG(LOG_DEBUG,
212 		    "\"%s\" traversed in %u sec", nlp->nlp_backup_path,
213 		    (uint_t)(e-s));
214 
215 		count_set_bits(nlp->nlp_backup_path, nlp->nlp_bkmap);
216 	}
217 
218 	return (rv);
219 }
220 
221 
222 /*
223  * mark_cb
224  *
225  * The callback function, called by traverse_post to mark bits
226  * in the bitmap.
227  *
228  * Set the bit of the entry if it's been modified (obviously
229  * should be backed up) plus its parent directory.
230  *
231  * If the entry is a directory and is not modified itself,
232  * but it's marked, then there is something below it that
233  * is being backed up.  It shows the the path, leads to
234  * an object that will be backed up. So the path should
235  * be marked too.
236  *
237  * The backup path itself is always marked.
238  *
239  * Parameters:
240  *   arg (input) - pointer to the mark parameter
241  *   pnp (input) - pointer to the path node
242  *   enp (input) - pointer to the entry node
243  *
244  * Returns:
245  *   0: as long as traversing should continue
246  *   != 0: if traversing should stop
247  */
248 int
249 mark_cb(void *arg, fst_node_t *pnp, fst_node_t *enp)
250 {
251 	int bmd;
252 	int rv;
253 	u_longlong_t bl;
254 	time_t ddate;
255 	fs_fhandle_t *pfhp, *efhp;
256 	struct stat64 *pstp, *estp;
257 	mark_param_t *mpp;
258 	ndmp_lbr_params_t *nlp;
259 	tlm_acls_t *tacl;
260 
261 	rv = 0;
262 	mpp = (mark_param_t *)arg;
263 	tacl = mpp->mp_tacl;
264 	nlp = ndmp_get_nlp(mpp->mp_session);
265 	if (!mpp) {
266 		NDMP_LOG(LOG_DEBUG, "NULL argument passed");
267 		rv = -1;
268 	} else if (mpp->mp_session->ns_eof) {
269 		NDMP_LOG(LOG_INFO, "Connection to the client is closed");
270 		rv = -1;
271 	} else if (mpp->mp_session->ns_data.dd_abort ||
272 	    (nlp && NLP_ISSET(nlp, NLPF_ABORTED))) {
273 		NDMP_LOG(LOG_INFO, "Processing directories aborted.");
274 		rv = -1;
275 	}
276 
277 	if (rv != 0)
278 		return (rv);
279 
280 	ddate = mpp->mp_ddate;
281 	bmd = mpp->mp_bmd;
282 	bl = dbm_getlen(bmd);
283 
284 	pfhp = pnp->tn_fh;
285 	pstp = pnp->tn_st;
286 
287 	/* sanity check on fh and stat of the path passed */
288 	if (pstp->st_ino > bl) {
289 		NDMP_LOG(LOG_DEBUG, "Invalid path inode #%u",
290 		    (uint_t)pstp->st_ino);
291 		return (-1);
292 	}
293 	if (pstp->st_ino != pfhp->fh_fid) {
294 		NDMP_LOG(LOG_DEBUG, "Path ino mismatch %u %u",
295 		    (uint_t)pstp->st_ino, (uint_t)pfhp->fh_fid);
296 		return (-1);
297 	}
298 
299 	/*
300 	 * Always mark the backup path inode number.
301 	 */
302 	if (!enp->tn_path) {
303 		(void) dbm_setone(bmd, pstp->st_ino);
304 		return (0);
305 	}
306 
307 	efhp = enp->tn_fh;
308 	estp = enp->tn_st;
309 
310 	/* sanity check on fh and stat of the entry passed */
311 	if (estp->st_ino > bl) {
312 		NDMP_LOG(LOG_DEBUG, "Invalid entry inode #%u",
313 		    (uint_t)estp->st_ino);
314 		return (-1);
315 	}
316 	if (estp->st_ino != efhp->fh_fid) {
317 		NDMP_LOG(LOG_DEBUG, "Entry ino mismatch %u %u", estp->st_ino,
318 		    (uint_t)pfhp->fh_fid);
319 		return (-1);
320 	}
321 
322 	/* check the dates and mark the bitmap inode */
323 	if (ddate == 0) {
324 		/* base backup */
325 		(void) dbm_setone(bmd, (u_longlong_t)estp->st_ino);
326 		(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
327 		if (ndmpd_verbose_traverse) {
328 			NDMP_LOG(LOG_DEBUG, "Base Backup");
329 			NDMP_LOG(LOG_DEBUG, "\"%s/%s\"",
330 			    pnp->tn_path, enp->tn_path);
331 		}
332 
333 	} else if (estp->st_mtime > ddate) {
334 		(void) dbm_setone(bmd, (u_longlong_t)estp->st_ino);
335 		(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
336 		if (ndmpd_verbose_traverse) {
337 			NDMP_LOG(LOG_DEBUG,
338 			    "m(%u,%u,%u,%u)", (uint_t)pstp->st_ino,
339 			    (uint_t)estp->st_ino, (uint_t)estp->st_mtime,
340 			    (uint_t)ddate);
341 			NDMP_LOG(LOG_DEBUG, "\"%s/%s\"",
342 			    pnp->tn_path, enp->tn_path);
343 		}
344 	} else if (iscreated(nlp, NULL, tacl, ddate)) {
345 		(void) dbm_setone(bmd, (u_longlong_t)estp->st_ino);
346 		(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
347 		if (ndmpd_verbose_traverse) {
348 			NDMP_LOG(LOG_DEBUG,
349 			    "cr(%u,%u,%u,%u)", (uint_t)pstp->st_ino,
350 			    (uint_t)estp->st_ino, (uint_t)estp->st_mtime,
351 			    (uint_t)ddate);
352 			NDMP_LOG(LOG_DEBUG, "\"%s/%s\"",
353 			    pnp->tn_path, enp->tn_path);
354 		}
355 	} else if (estp->st_ctime > ddate) {
356 		if (!NLP_IGNCTIME(nlp)) {
357 			(void) dbm_setone(bmd, (u_longlong_t)estp->st_ino);
358 			(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
359 		}
360 		if (ndmpd_verbose_traverse) {
361 			if (NLP_IGNCTIME(nlp)) {
362 				NDMP_LOG(LOG_DEBUG,
363 				    "ign c(%u,%u,%u,%u)", (uint_t)pstp->st_ino,
364 				    (uint_t)estp->st_ino,
365 				    (uint_t)estp->st_ctime, (uint_t)ddate);
366 			} else {
367 				NDMP_LOG(LOG_DEBUG,
368 				    "c(%u,%u,%u,%u)", (uint_t)pstp->st_ino,
369 				    (uint_t)estp->st_ino,
370 				    (uint_t)estp->st_ctime, (uint_t)ddate);
371 			}
372 			NDMP_LOG(LOG_DEBUG, "\"%s/%s\"",
373 			    pnp->tn_path, enp->tn_path);
374 		}
375 	} else if (S_ISDIR(estp->st_mode) &&
376 	    dbm_getone(bmd, (u_longlong_t)estp->st_ino)) {
377 		(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
378 		if (ndmpd_verbose_traverse) {
379 			NDMP_LOG(LOG_DEBUG, "d(%u,%u)",
380 			    (uint_t)pstp->st_ino, (uint_t)estp->st_ino);
381 			NDMP_LOG(LOG_DEBUG, "\"%s, %s\"",
382 			    pnp->tn_path, enp->tn_path);
383 		}
384 	}
385 
386 	return (0);
387 }
388 
389 
390 /*
391  * mark_inodes_v2
392  *
393  * Traverse the file system in post-order and mark
394  * all the modified objects and also directories leading
395  * to them.
396  *
397  * Parameters:
398  *   session (input) - pointer to the session
399  *   nlp (input) - pointer to the nlp structure
400  *   path (input) - the physical path to traverse
401  *
402  * Returns:
403  *   0: on success.
404  *   != 0: on error.
405  */
406 int
407 mark_inodes_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp, char *path)
408 {
409 	fs_traverse_t ft;
410 	mark_param_t mp;
411 
412 	if (!session || !nlp || !path || !*path) {
413 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
414 		return (-1);
415 	}
416 
417 	NDMP_LOG(LOG_DEBUG, "path \"%s\"", path);
418 
419 	mp.mp_bmd = nlp->nlp_bkmap;
420 	mp.mp_ddate = nlp->nlp_ldate;
421 	mp.mp_session = session;
422 	mp.mp_nlp = nlp;
423 
424 	ft.ft_path = path;
425 	ft.ft_lpath = nlp->nlp_backup_path;
426 	ft.ft_callbk = mark_cb;
427 	ft.ft_arg = &mp;
428 	ft.ft_logfp = (ft_log_t)ndmp_log;
429 	ft.ft_flags = ndmpd_mark_flags;
430 
431 	return (traverse(session, nlp, &ft));
432 }
433 
434 
435 /*
436  * create_bitmap
437  *
438  * Create a dbitmap and return its descriptor.
439  *
440  * Parameters:
441  *   path (input) - path for which the bitmap should be created
442  *   value (input) - the initial value for the bitmap
443  *
444  * Returns:
445  *   the dbitmap descriptor
446  */
447 static int
448 create_bitmap(char *path, int value)
449 {
450 	char bm_fname[PATH_MAX];
451 	char buf[TLM_MAX_PATH_NAME];
452 	char *livepath;
453 	ulong_t ninode;
454 
455 	NDMP_LOG(LOG_DEBUG, "path \"%s\"", path);
456 
457 	if (fs_is_chkpntvol(path))
458 		livepath = (char *)tlm_remove_checkpoint(path, buf);
459 	else
460 		livepath = path;
461 	ninode = 1024 * 1024 * 1024;
462 	if (ninode == 0)
463 		return (-1);
464 	(void) ndmpd_mk_temp(bm_fname);
465 
466 	NDMP_LOG(LOG_DEBUG, "path \"%s\"ninode %u bm_fname \"%s\"",
467 	    livepath, ninode, bm_fname);
468 
469 	return (dbm_alloc(bm_fname, (u_longlong_t)ninode, value));
470 }
471 
472 
473 /*
474  * create_allset_bitmap
475  *
476  * A helper function to create a bitmap with all the
477  * values set to 1.
478  *
479  * Parameters:
480  *   nlp (input) - pointer to the nlp structure
481  *
482  * Returns:
483  *   the dbitmap descriptor
484  */
485 static int
486 create_allset_bitmap(ndmp_lbr_params_t *nlp)
487 {
488 	int rv;
489 
490 	nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 1);
491 	NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);
492 
493 	if (nlp->nlp_bkmap < 0) {
494 		NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
495 		rv = -1;
496 	} else
497 		rv = 0;
498 
499 	return (rv);
500 }
501 
502 
503 /*
504  * mark_common_v2
505  *
506  * Create the inode bitmap.  If last date of the the
507  * backup is epoch, then all the objects should be backed
508  * up; there is no need to traverse the backup hierarchy
509  * and mark the inodes.  All the bits should be marked.
510  *
511  * Otherwise, the backup hierarchy should be traversed and
512  * the objects should be marked.
513  *
514  * Parameters:
515  *   session (input) - pointer to the session
516  *   nlp (input) - pointer to the nlp structure
517  *
518  * Returns:
519  *   0: on success.
520  *   != 0: on error.
521  */
522 static int
523 mark_common_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
524 {
525 	char buf[TLM_MAX_PATH_NAME], *chkpath;
526 	int rv;
527 
528 	/*
529 	 * Everything is needed for full backup.
530 	 */
531 	if (nlp->nlp_ldate == (time_t)0)
532 		return (create_allset_bitmap(nlp));
533 
534 	rv = 0;
535 	nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0);
536 	NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);
537 
538 	if (nlp->nlp_bkmap < 0) {
539 		NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
540 		rv = -1;
541 	} else {
542 		if (fs_is_chkpntvol(nlp->nlp_backup_path))
543 			chkpath = nlp->nlp_backup_path;
544 		else
545 			chkpath = tlm_build_snapshot_name(
546 			    nlp->nlp_backup_path, buf,
547 			    nlp->nlp_jstat->js_job_name);
548 		rv = mark_inodes_v2(session, nlp, chkpath);
549 		(void) dbm_setone(nlp->nlp_bkmap, (u_longlong_t)ROOT_INODE);
550 	}
551 
552 	return (rv);
553 }
554 
555 
556 /*
557  * mark_tar_inodes_v2
558  *
559  * Create the bitmap for tar backup format.
560  *
561  * Parameters:
562  *   session (input) - pointer to the session
563  *   nlp (input) - pointer to the nlp structure
564  *
565  * Returns:
566  *   0: on success.
567  *   != 0: on error.
568  */
569 static int
570 mark_tar_inodes_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
571 {
572 	int rv;
573 
574 	if (ndmp_tar_force_traverse)
575 		rv = mark_common_v2(session, nlp);
576 	else
577 		rv = create_allset_bitmap(nlp);
578 
579 	return (rv);
580 }
581 
582 
583 /*
584  * mark_dump_inodes_v2
585  *
586  * Create the bitmap for dump backup format.
587  *
588  * Parameters:
589  *   session (input) - pointer to the session
590  *   nlp (input) - pointer to the nlp structure
591  *
592  * Returns:
593  *   0: on success.
594  *   != 0: on error.
595  */
596 static int
597 mark_dump_inodes_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
598 {
599 	return (mark_common_v2(session, nlp));
600 }
601 
602 
603 /*
604  * ndmpd_mark_inodes_v2
605  *
606  * Mark the inodes of the backup hierarchy if necessary.
607  *
608  * Parameters:
609  *   session (input) - pointer to the session
610  *   nlp (input) - pointer to the nlp structure
611  *
612  * Returns:
613  *   0: on success.
614  *   != 0: on error.
615  */
616 int
617 ndmpd_mark_inodes_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
618 {
619 	int rv;
620 
621 	if (ndmp_skip_traverse) {
622 		NDMP_LOG(LOG_INFO, "Skip processing directories \"%s\"",
623 		    nlp->nlp_backup_path);
624 		rv = create_allset_bitmap(nlp);
625 	} else {
626 		if (NLP_ISTAR(nlp))
627 			rv = mark_tar_inodes_v2(session, nlp);
628 		else if (NLP_ISDUMP(nlp))
629 			rv = mark_dump_inodes_v2(session, nlp);
630 		else {
631 			NDMP_LOG(LOG_DEBUG, "Unknown backup type for \"%s\"",
632 			    nlp->nlp_backup_path);
633 			rv = -1;
634 		}
635 	}
636 
637 	return (rv);
638 }
639 
640 
641 /*
642  * ndmpd_abort_making_v2
643  *
644  * Abort the process of marking inodes.
645  *
646  * Parameters:
647  *   session (input) - pointer to the session
648  *
649  * Returns:
650  *   void
651  */
652 void
653 ndmpd_abort_marking_v2(ndmpd_session_t *session)
654 {
655 	ndmp_lbr_params_t *nlp;
656 
657 	nlp = ndmp_get_nlp(session);
658 	if (nlp)
659 		NLP_SET(nlp, NLPF_ABORTED);
660 }
661 
662 
663 /*
664  * mark_tokv3
665  *
666  * Traverse the backup hierarchy and mark the bits for the
667  * modified objects of directories leading to a modified
668  * object for the token-based backup.
669  *
670  * Parameters:
671  *   session (input) - pointer to the session
672  *   nlp (input) - pointer to the nlp structure
673  *   path (input) - the physical path to traverse
674  *
675  * Returns:
676  *   0: on success
677  *   != 0: otherwise
678  */
679 int
680 mark_tokv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp, char *path)
681 {
682 	fs_traverse_t ft;
683 	mark_param_t mp;
684 
685 	if (!session || !nlp || !path || !*path) {
686 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
687 		return (-1);
688 	}
689 	if (nlp->nlp_tokdate == (time_t)0)
690 		return (create_allset_bitmap(nlp));
691 
692 	nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0);
693 	if (nlp->nlp_bkmap < 0) {
694 		NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
695 		return (-1);
696 	}
697 	NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);
698 
699 	mp.mp_bmd = nlp->nlp_bkmap;
700 	mp.mp_ddate = nlp->nlp_tokdate;
701 	mp.mp_session = session;
702 	mp.mp_nlp = nlp;
703 
704 	ft.ft_path = path;
705 	ft.ft_lpath = nlp->nlp_backup_path;
706 	ft.ft_callbk = mark_cb;
707 	ft.ft_arg = &mp;
708 	ft.ft_logfp = (ft_log_t)ndmp_log;
709 	ft.ft_flags = ndmpd_mark_flags;
710 
711 	return (traverse(session, nlp, &ft));
712 }
713 
714 
715 /*
716  * marklbrv3_cb
717  *
718  * The callback function, called by traverse_post to mark
719  * bits in the bitmap.
720  *
721  * It's so much like mark_cb for time-based (token-based
722  * and level-type) backup types, except that it looks at
723  * the archive bit of the objects instead of their timestamp.
724  *
725  * Parameters:
726  *   arg (input) - pointer to the mark parameter
727  *   pnp (input) - pointer to the path node
728  *   enp (input) - pointer to the entry node
729  *
730  * Returns:
731  *   0: as long as traversing should continue
732  *   != 0: if traversing should stop
733  */
734 int
735 marklbrv3_cb(void *arg, fst_node_t *pnp, fst_node_t *enp)
736 {
737 	int bmd;
738 	u_longlong_t bl;
739 	fs_fhandle_t *pfhp, *efhp;
740 	struct stat64 *pstp, *estp;
741 	mark_param_t *mpp;
742 	ndmp_lbr_params_t *nlp;
743 
744 	mpp = (mark_param_t *)arg;
745 	if (!mpp) {
746 		NDMP_LOG(LOG_DEBUG, "NULL argument passed");
747 		return (-1);
748 	}
749 	nlp = ndmp_get_nlp(mpp->mp_session);
750 	if (mpp->mp_session->ns_data.dd_abort ||
751 	    (nlp && NLP_ISSET(nlp, NLPF_ABORTED))) {
752 		NDMP_LOG(LOG_INFO, "Processing directories aborted.");
753 		return (-1);
754 	}
755 
756 	bmd = mpp->mp_bmd;
757 	bl = dbm_getlen(bmd);
758 
759 	pfhp = pnp->tn_fh;
760 	pstp = pnp->tn_st;
761 
762 	/* sanity check on fh and stat of the path passed */
763 	if (pstp->st_ino > bl) {
764 		NDMP_LOG(LOG_DEBUG, "Invalid path inode #%u",
765 		    (uint_t)pstp->st_ino);
766 		return (-1);
767 	}
768 	if (pstp->st_ino != pfhp->fh_fid) {
769 		NDMP_LOG(LOG_DEBUG, "Path ino mismatch %u %u",
770 		    (uint_t)pstp->st_ino, (uint_t)pfhp->fh_fid);
771 		return (-1);
772 	}
773 
774 	/*
775 	 * Always mark the backup path inode number.
776 	 */
777 	if (!enp->tn_path) {
778 		(void) dbm_setone(bmd, pstp->st_ino);
779 		if (ndmpd_verbose_traverse) {
780 			NDMP_LOG(LOG_DEBUG, "d(%u)", (uint_t)pstp->st_ino);
781 			NDMP_LOG(LOG_DEBUG, "\"%s\"", pnp->tn_path);
782 		}
783 		return (0);
784 	}
785 
786 	efhp = enp->tn_fh;
787 	estp = enp->tn_st;
788 
789 	/* sanity check on fh and stat of the entry passed */
790 	if (estp->st_ino > bl) {
791 		NDMP_LOG(LOG_DEBUG, "Invalid entry inode #%u",
792 		    (uint_t)estp->st_ino);
793 		return (-1);
794 	}
795 	if (estp->st_ino != efhp->fh_fid) {
796 		NDMP_LOG(LOG_DEBUG, "Entry ino mismatch %u %u", estp->st_ino,
797 		    (uint_t)pfhp->fh_fid);
798 		return (-1);
799 	}
800 
801 	if (S_ISDIR(estp->st_mode) &&
802 	    dbm_getone(bmd, (u_longlong_t)estp->st_ino)) {
803 		(void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
804 		if (ndmpd_verbose_traverse) {
805 			NDMP_LOG(LOG_DEBUG, "d(%u,%u)",
806 			    (uint_t)pstp->st_ino, (uint_t)estp->st_ino);
807 			NDMP_LOG(LOG_DEBUG, "\"%s, %s\"",
808 			    pnp->tn_path, enp->tn_path);
809 		}
810 	}
811 
812 	return (0);
813 }
814 
815 
816 /*
817  * mark_lbrv3
818  *
819  * Traverse the backup hierarchy and mark the bits for the
820  * modified objects of directories leading to a modified
821  * object for the LBR-type backup.
822  *
823  * Parameters:
824  *   session (input) - pointer to the session
825  *   nlp (input) - pointer to the nlp structure
826  *   path (input) - the physical path to traverse
827  *
828  * Returns:
829  *   0: on success
830  *   != 0: otherwise
831  */
832 int
833 mark_lbrv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp, char *path)
834 {
835 	char c;
836 	fs_traverse_t ft;
837 	mark_param_t mp;
838 
839 	if (!session || !nlp || !path || !*path) {
840 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
841 		return (-1);
842 	}
843 	/* full and archive backups backup everything */
844 	c = toupper(nlp->nlp_clevel);
845 	if (c == 'F' || c == 'A')
846 		return (create_allset_bitmap(nlp));
847 
848 	nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0);
849 	if (nlp->nlp_bkmap < 0) {
850 		NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
851 		return (-1);
852 	}
853 	NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);
854 
855 	mp.mp_bmd = nlp->nlp_bkmap;
856 	mp.mp_ddate = 0;
857 	mp.mp_session = session;
858 	mp.mp_nlp = nlp;
859 
860 	ft.ft_path = path;
861 	ft.ft_lpath = nlp->nlp_backup_path;
862 	ft.ft_callbk = marklbrv3_cb;
863 	ft.ft_arg = &mp;
864 	ft.ft_logfp = (ft_log_t)ndmp_log;
865 	ft.ft_flags = ndmpd_mark_flags;
866 
867 	return (traverse(session, nlp, &ft));
868 }
869 
870 
871 /*
872  * mark_levelv3
873  *
874  * Traverse the backup hierarchy and mark the bits for the
875  * modified objects of directories leading to a modified
876  * object for the level-type backup.
877  *
878  * Parameters:
879  *   session (input) - pointer to the session
880  *   nlp (input) - pointer to the nlp structure
881  *   path (input) - the physical path to traverse
882  *
883  * Returns:
884  *   0: on success
885  *   != 0: otherwise
886  */
887 int
888 mark_levelv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp, char *path)
889 {
890 	fs_traverse_t ft;
891 	mark_param_t mp;
892 	tlm_acls_t traverse_acl;
893 
894 	if (!session || !nlp || !path || !*path) {
895 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
896 		return (-1);
897 	}
898 	if (nlp->nlp_ldate == (time_t)0)
899 		return (create_allset_bitmap(nlp));
900 
901 	nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0);
902 	if (nlp->nlp_bkmap < 0) {
903 		NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
904 		return (-1);
905 	}
906 	NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);
907 
908 	/*
909 	 * We do not want to allocate memory for acl every time we
910 	 * process a file.
911 	 */
912 	(void) memset(&traverse_acl, 0, sizeof (traverse_acl));
913 	mp.mp_tacl = &traverse_acl;
914 
915 	mp.mp_bmd = nlp->nlp_bkmap;
916 	mp.mp_ddate = nlp->nlp_ldate;
917 	mp.mp_session = session;
918 	mp.mp_nlp = nlp;
919 
920 	ft.ft_path = path;
921 	ft.ft_lpath = nlp->nlp_backup_path;
922 	ft.ft_callbk = mark_cb;
923 	ft.ft_arg = &mp;
924 	ft.ft_logfp = (ft_log_t)ndmp_log;
925 	ft.ft_flags = ndmpd_mark_flags;
926 
927 	return (traverse(session, nlp, &ft));
928 }
929 
930 
931 /*
932  * mark_commonv3
933  *
934  * Create the inode bitmap.  If last date of the the
935  * backup is epoch, then all the objects should be backed
936  * up; there is no need to traverse the backup hierarchy
937  * and mark the inodes.  All the bits should be marked.
938  *
939  * Otherwise, the backup hierarchy should be traversed and
940  * the objects should be marked.
941  *
942  * Parameters:
943  *   session (input) - pointer to the session
944  *   nlp (input) - pointer to the nlp structure
945  *
946  * Returns:
947  *   0: on success.
948  *   != 0: on error.
949  */
950 int
951 mark_commonv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
952 {
953 	char buf[TLM_MAX_PATH_NAME], *chkpath;
954 	int rv;
955 
956 	if (NLP_ISCHKPNTED(nlp))
957 		chkpath = nlp->nlp_backup_path;
958 	else
959 		chkpath = tlm_build_snapshot_name(nlp->nlp_backup_path, buf,
960 		    nlp->nlp_jstat->js_job_name);
961 
962 	if (NLP_ISSET(nlp, NLPF_TOKENBK))
963 		rv = mark_tokv3(session, nlp, chkpath);
964 	else if (NLP_ISSET(nlp, NLPF_LBRBK))
965 		rv = mark_lbrv3(session, nlp, chkpath);
966 	else if (NLP_ISSET(nlp, NLPF_LEVELBK)) {
967 		rv = mark_levelv3(session, nlp, chkpath);
968 	} else {
969 		rv = -1;
970 		NDMP_LOG(LOG_DEBUG, "Unknown backup type for \"%s\"",
971 		    nlp->nlp_backup_path);
972 	}
973 
974 	return (rv);
975 }
976 
977 
978 /*
979  * mark_tar_inodesv3
980  *
981  * Mark bits for tar backup format of V3.  Normally, the
982  * backup hierarchy is not traversed for tar format
983  * unless it's forced by setting the ndmp_tar_force_traverse
984  * to a non-zero value.
985  *
986  * Parameters:
987  *   session (input) - pointer to the session
988  *   nlp (input) - pointer to the nlp structure
989  *
990  * Returns:
991  *   0: on success
992  *   != 0: otherwise
993  */
994 int
995 mark_tar_inodesv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
996 {
997 	int rv;
998 
999 	if (ndmp_tar_force_traverse)
1000 		rv = mark_commonv3(session, nlp);
1001 	else
1002 		rv = create_allset_bitmap(nlp);
1003 
1004 	return (rv);
1005 }
1006 
1007 
1008 /*
1009  * ndmpd_mark_inodes_v3
1010  *
1011  * Mark the inodes of the backup hierarchy if necessary.
1012  *
1013  * Parameters:
1014  *   session (input) - pointer to the session
1015  *   nlp (input) - pointer to the nlp structure
1016  *
1017  * Returns:
1018  *   0: on success.
1019  *   != 0: on error.
1020  */
1021 int
1022 ndmpd_mark_inodes_v3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
1023 {
1024 	int rv;
1025 
1026 	if (ndmp_skip_traverse) {
1027 		NDMP_LOG(LOG_INFO, "Skip processing directories \"%s\"",
1028 		    nlp->nlp_backup_path);
1029 		rv = create_allset_bitmap(nlp);
1030 	} else {
1031 		if (NLP_ISTAR(nlp))
1032 			rv = mark_tar_inodesv3(session, nlp);
1033 		else if (NLP_ISDUMP(nlp)) {
1034 			rv = mark_commonv3(session, nlp);
1035 		} else {
1036 			NDMP_LOG(LOG_DEBUG, "Unknown backup type for \"%s\"",
1037 			    nlp->nlp_backup_path);
1038 			rv = -1;
1039 		}
1040 	}
1041 
1042 	return (rv);
1043 }
1044