The prior effort to identify the actual root inode in a filesystem failed in the (rare) case where inodes were allocated with a lower number than the root. As a result, the wrong root inode number went into the dump, and restore would fail with: xfsrestore: tree.c:757: tree_begindir: Assertion `ino != persp->p_rootino || hardh == persp->p_rooth' failed. Fix this by iterating over a chunk's worth of inodes until we find a directory inode with generation 0, which should only be true for the real root inode. Fixes: 25195ebf107 ("xfsdump: handle bind mount targets") Signed-off-by: Eric Sandeen <sandeen@xxxxxxxxxx> --- diff --git a/dump/content.c b/dump/content.c index 30232d4..9f9c03b 100644 --- a/dump/content.c +++ b/dump/content.c @@ -1384,7 +1384,7 @@ baseuuidbypass: /* 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, - * find the actual lowest inode number in the filesystem. + * actually find the root inode number in the filesystem. */ { stat64_t rootstat; @@ -1404,20 +1404,36 @@ 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")); + /* + * Find the root inode in this fs. It is (rarely) possible to + * have a non-root inode come before the root inode, so iterate + * over a chunk's worth looking for the first dir inode with + * bs_gen == 0, which should only be true for the root inode. + */ + for (i = 0; i < 64; i++) { + 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")); + return BOOL_FALSE; + } + /* found it? */ + if ((sc_rootxfsstatp->bs_mode & S_IFMT) == S_IFDIR && + sc_rootxfsstatp->bs_gen == 0) + break; + } + + if (i == 64) { + mlog(MLOG_ERROR, _("failed to find 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"), +_("root ino %lld differs from mount dir ino %lld, bind mount?\n"), sc_rootxfsstatp->bs_ino, rootstat.st_ino); }