[RFC PATCH] xfsdump: fix handling bind mount targets

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Sometimes, it's not true that the root directory is always
the first result from calling bulkstat with lastino == 0
assumed by xfsdump.

Recently XFS_BULK_IREQ_SPECIAL_ROOT was introduced last year,
yet that doesn't exist in old kernels.

Alternatively, we can also use bulkstat to walk through
all dirs and find the exact dir whose ino # of ".." is
itself by getdents, and that should be considered as the
root dir.

Fixes: 25195ebf107d ("xfsdump: handle bind mount targets")
Cc: Eric Sandeen <sandeen@xxxxxxxxxx>
Signed-off-by: Gao Xiang <hsiangkao@xxxxxxxxxx>
---
preliminary test with the original testcase is done...

 dump/content.c | 168 ++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 140 insertions(+), 28 deletions(-)

diff --git a/dump/content.c b/dump/content.c
index 30232d4..653d4eb 100644
--- a/dump/content.c
+++ b/dump/content.c
@@ -511,6 +511,132 @@ static bool_t create_inv_session(
 		ix_t subtreecnt,
 		size_t strmix);
 
+struct fixrootino_context {
+	xfs_ino_t	rootino;
+	struct dirent	*gdp;
+	size_t		gdsz;
+};
+
+static bool_t
+scan_rootinode(int fd,
+	       xfs_ino_t ino,
+	       struct dirent *gdp,
+	       size_t gdsz)
+{
+	while (1) {
+		struct dirent *p;
+		int nread;
+
+		nread = getdents_wrap(fd, (char *)gdp, gdsz);
+		/*
+		 * negative count indicates something very bad happened;
+		 * try to gracefully end this dir.
+		 */
+		if (nread < 0) {
+			mlog(MLOG_NORMAL | MLOG_WARNING,
+_("unable to read dirents for directory ino %llu: %s\n"),
+			      ino, strerror(errno));
+			/* !!! curtis looked at this, and pointed out that
+			 * we could take some recovery action here. if the
+			 * errno is appropriate, lseek64 to the value of
+			 * doff field of the last dirent successfully
+			 * obtained, and contiue the loop.
+			 */
+			nread = 0; /* pretend we are done */
+		}
+
+		/* no more directory entries: break; */
+		if (!nread)
+			break;
+
+		for (p = gdp; nread > 0;
+		     nread -= (int)p->d_reclen,
+		     assert(nread >= 0),
+		     p = (struct dirent *)((char *)p + p->d_reclen)) {
+			if (!strcmp(p->d_name, "..") && p->d_ino == ino) {
+				mlog(MLOG_NITTY, "FOUND: name %s d_ino %llu\n",
+				     p->d_name, ino);
+				return BOOL_TRUE;
+			}
+		}
+	}
+	return BOOL_FALSE;
+}
+
+/* ARGSUSED */
+static int
+cb_find_root_inode(void *arg1,
+	jdm_fshandle_t *fshandlep,
+	int fsfd,
+	struct xfs_bstat *statp)
+{
+	int fd;
+	struct fixrootino_context *ctx = arg1;
+
+	/* open the directory named by statp*/
+	fd = jdm_open(fshandlep, statp, O_RDONLY);
+	if (fd < 0) {
+		mlog(MLOG_NORMAL | MLOG_WARNING, _(
+		      "unable to open directory: ino %llu: %s\n"),
+		      statp->bs_ino, strerror(errno));
+		return RV_OK; /* continue anyway */
+	}
+
+	if (scan_rootinode(fd, statp->bs_ino, ctx->gdp, ctx->gdsz)) {
+		ctx->rootino = statp->bs_ino;
+		return RV_NOMORE;
+	}
+	return RV_OK;
+}
+
+static bool_t
+fix_root_inode(
+	stat64_t *rootstat,
+	struct xfs_bstat *sc_rootxfsstatp)
+{
+	struct xfs_bstat *bstatbufp;
+	int rval;
+	struct fixrootino_context ctx;
+	rv_t rv = RV_OK;
+
+	ctx.gdsz = sizeof(struct dirent) + NAME_MAX + 1;
+	if (ctx.gdsz < GETDENTSBUF_SZ_MIN)
+		ctx.gdsz = GETDENTSBUF_SZ_MIN;
+
+	ctx.gdp = (struct dirent *)calloc(1, ctx.gdsz);
+	assert(ctx.gdp);
+
+	/* already a root dir */
+	if (scan_rootinode(sc_fsfd, rootstat->st_ino, ctx.gdp, ctx.gdsz))
+		goto out;
+
+	/* allocate a buffer for use by bigstat_iter */
+	bstatbufp = (struct xfs_bstat *)calloc(BSTATBUFLEN,
+					       sizeof(struct xfs_bstat));
+	assert(bstatbufp);
+
+	rval = bigstat_iter(sc_fshandlep, sc_fsfd, BIGSTAT_ITER_DIR,
+			    (xfs_ino_t)0, cb_find_root_inode,
+			    &ctx, NULL, NULL, (int *)&rv, preemptchk,
+			    bstatbufp, BSTATBUFLEN);
+	if (rval)
+		return BOOL_FALSE;
+
+	if (rv != RV_NOMORE && rv != RV_OK)
+		return BOOL_FALSE;
+
+	mlog(MLOG_NORMAL | MLOG_NOTE,
+	     "fix up rootino %lld, bind mount?\n", ctx.rootino);
+	rootstat->st_ino = ctx.rootino;
+out:
+	if (bigstat_one(sc_fsfd, rootstat->st_ino, sc_rootxfsstatp) < 0) {
+		mlog( MLOG_ERROR,
+		      _("failed to get bulkstat information for root inode\n"));
+		return BOOL_FALSE;
+	}
+	return BOOL_TRUE;
+}
+
 bool_t
 content_init(int argc,
 	      char *argv[],
@@ -1381,6 +1507,18 @@ baseuuidbypass:
 		return BOOL_FALSE;
 	}
 
+	/* alloc a file system handle, to be used with the jdm_open()
+	 * functions.
+	 */
+	sc_fshandlep = jdm_getfshandle(mntpnt);
+	if (!sc_fshandlep) {
+		mlog(MLOG_NORMAL, _(
+		      "unable to construct a file system handle for %s: %s\n"),
+		      mntpnt,
+		      strerror(errno));
+		return BOOL_FALSE;
+	}
+
 	/* figure out the ino for the root directory of the fs
 	 * and get its struct xfs_bstat for inomap_build().  This could
 	 * be a bind mount; don't ask for the mount point inode,
@@ -1388,9 +1526,6 @@ baseuuidbypass:
 	 */
 	{
 		stat64_t rootstat;
-		xfs_ino_t lastino = 0;
-		int ocount = 0;
-		struct xfs_fsop_bulkreq bulkreq;
 
 		/* Get the inode of the mount point */
 		rval = fstat64(sc_fsfd, &rootstat);
@@ -1404,33 +1539,10 @@ baseuuidbypass:
 			(struct xfs_bstat *)calloc(1, sizeof(struct xfs_bstat));
 		assert(sc_rootxfsstatp);
 
-		/* Get the first valid (i.e. root) inode in this fs */
-		bulkreq.lastip = (__u64 *)&lastino;
-		bulkreq.icount = 1;
-		bulkreq.ubuffer = sc_rootxfsstatp;
-		bulkreq.ocount = &ocount;
-		if (ioctl(sc_fsfd, XFS_IOC_FSBULKSTAT, &bulkreq) < 0) {
-			mlog(MLOG_ERROR,
-			      _("failed to get bulkstat information for root inode\n"));
+		if (!fix_root_inode(&rootstat, sc_rootxfsstatp)) {
+			mlog(MLOG_ERROR, _("failed to fix root inode\n"));
 			return BOOL_FALSE;
 		}
-
-		if (sc_rootxfsstatp->bs_ino != rootstat.st_ino)
-			mlog (MLOG_NORMAL | MLOG_NOTE,
-			       _("root ino %lld differs from mount dir ino %lld, bind mount?\n"),
-			         sc_rootxfsstatp->bs_ino, rootstat.st_ino);
-	}
-
-	/* alloc a file system handle, to be used with the jdm_open()
-	 * functions.
-	 */
-	sc_fshandlep = jdm_getfshandle(mntpnt);
-	if (!sc_fshandlep) {
-		mlog(MLOG_NORMAL, _(
-		      "unable to construct a file system handle for %s: %s\n"),
-		      mntpnt,
-		      strerror(errno));
-		return BOOL_FALSE;
 	}
 
 	if (preemptchk(PREEMPT_FULL)) {
-- 
2.18.1




[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux