From: Hironori Shiina <shiina.hironori@gmail.com>
To: Gao Xiang <hsiangkao@redhat.com>, linux-xfs@vger.kernel.org
Cc: Eric Sandeen <sandeen@sandeen.net>, Donald Douwsma <ddouwsma@redhat.com>
Subject: Re: [RFC PATCH v2] xfsrestore: fix rootdir due to xfsdump bulkstat misuse
Date: Thu, 30 Jun 2022 15:19:07 -0400 [thread overview]
Message-ID: <e61ae295-a331-d36a-cae1-646022dc2a6e@gmail.com> (raw)
In-Reply-To: <aed54ce4-e1bf-39f7-cf91-a67e29f59d52@gmail.com>
On 6/10/22 19:05, Hironori Shiina wrote:
>
>
> On 11/16/20 03:07, Gao Xiang wrote:
>> If rootino is wrong and misspecified to a subdir inode #,
>> the following assertion could be triggered:
>> assert(ino != persp->p_rootino || hardh == persp->p_rooth);
>>
>> This patch adds a '-x' option (another awkward thing is that
>> the codebase doesn't support long options) to address
>> problamatic images by searching for the real dir, the reason
>> that I don't enable it by default is that I'm not very confident
>> with the xfsrestore codebase and xfsdump bulkstat issue will
>> also be fixed immediately as well, so this function might be
>> optional and only useful for pre-exist corrupted dumps.
>
> I agree that this function is optional for another reason. This fix
> cannot be the default behavior because of a workaround for a case where
> a fake root's gen is zero. This workaround prevents a correct dump
> without a fake root from being restored.
>
>>
>> In details, my understanding of the original logic is
>> 1) xfsrestore will create a rootdir node_t (p_rooth);
>> 2) it will build the tree hierarchy from inomap and adopt
>> the parent if needed (so inodes whose parent ino hasn't
>> detected will be in the orphan dir, p_orphh);
>> 3) during this period, if ino == rootino and
>> hardh != persp->p_rooth (IOWs, another node_t with
>> the same ino # is created), that'd be definitely wrong.
>>
>> So the proposal fix is that
>> - considering the xfsdump root ino # is a subdir inode, it'll
>> trigger ino == rootino && hardh != persp->p_rooth condition;
>> - so we log this node_t as persp->p_rooth rather than the
>> initial rootdir node_t created in 1);
>> - we also know that this node is actually a subdir, and after
>> the whole inomap is scanned (IOWs, the tree is built),
>> the real root dir will have the orphan dir parent p_orphh;
>> - therefore, we walk up by the parent until some node_t has
>> the p_orphh, so that's it.
>>
>> Cc: Donald Douwsma <ddouwsma@redhat.com>
>> Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
>> ---
>> changes since RFC v1:
>> - fix non-dir fake rootino cases since tree_begindir()
>> won't be triggered for these non-dir, and we could do
>> that in tree_addent() instead (fault injection verified);
>>
>> - fix fake rootino case with gen = 0 as well, for more
>> details, see the inlined comment in link_hardh()
>> (fault injection verified as well).
>>
>> Anyway, all of this behaves like a workaround and I have
>> no idea how to deal it more gracefully.
>>
>> restore/content.c | 7 +++++
>> restore/getopt.h | 4 +--
>> restore/tree.c | 70 ++++++++++++++++++++++++++++++++++++++++++++---
>> restore/tree.h | 2 ++
>> 4 files changed, 77 insertions(+), 6 deletions(-)
>>
>> diff --git a/restore/content.c b/restore/content.c
>> index 6b22965..e807a83 100644
>> --- a/restore/content.c
>> +++ b/restore/content.c
>> @@ -865,6 +865,7 @@ static int quotafilecheck(char *type, char *dstdir, char *quotafile);
>>
>> bool_t content_media_change_needed;
>> bool_t restore_rootdir_permissions;
>> +bool_t need_fixrootdir;
>> char *media_change_alert_program = NULL;
>> size_t perssz;
>>
>> @@ -964,6 +965,7 @@ content_init(int argc, char *argv[], size64_t vmsz)
>> stsz = 0;
>> interpr = BOOL_FALSE;
>> restore_rootdir_permissions = BOOL_FALSE;
>> + need_fixrootdir = BOOL_FALSE;
>> optind = 1;
>> opterr = 0;
>> while ((c = getopt(argc, argv, GETOPT_CMDSTRING)) != EOF) {
>> @@ -1189,6 +1191,9 @@ content_init(int argc, char *argv[], size64_t vmsz)
>> case GETOPT_FMT2COMPAT:
>> tranp->t_truncategenpr = BOOL_TRUE;
>> break;
>> + case GETOPT_FIXROOTDIR:
>> + need_fixrootdir = BOOL_TRUE;
>> + break;
>> }
>> }
>>
>> @@ -3140,6 +3145,8 @@ applydirdump(drive_t *drivep,
>> return rv;
>> }
>>
>> + if (need_fixrootdir)
>> + tree_fixroot();
>> persp->s.dirdonepr = BOOL_TRUE;
>> }
>>
>> diff --git a/restore/getopt.h b/restore/getopt.h
>> index b5bc004..b0c0c7d 100644
>> --- a/restore/getopt.h
>> +++ b/restore/getopt.h
>> @@ -26,7 +26,7 @@
>> * purpose is to contain that command string.
>> */
>>
>> -#define GETOPT_CMDSTRING "a:b:c:def:himn:op:qrs:tv:wABCDEFG:H:I:JKL:M:NO:PQRS:TUVWX:Y:"
>> +#define GETOPT_CMDSTRING "a:b:c:def:himn:op:qrs:tv:wxABCDEFG:H:I:JKL:M:NO:PQRS:TUVWX:Y:"
>>
>> #define GETOPT_WORKSPACE 'a' /* workspace dir (content.c) */
>> #define GETOPT_BLOCKSIZE 'b' /* blocksize for rmt */
>> @@ -51,7 +51,7 @@
>> /* 'u' */
>> #define GETOPT_VERBOSITY 'v' /* verbosity level (0 to 4) */
>> #define GETOPT_SMALLWINDOW 'w' /* use a small window for dir entries */
>> -/* 'x' */
>> +#define GETOPT_FIXROOTDIR 'x' /* try to fix rootdir due to bulkstat misuse */
>> /* 'y' */
>> /* 'z' */
>> #define GETOPT_NOEXTATTR 'A' /* do not restore ext. file attr. */
>> diff --git a/restore/tree.c b/restore/tree.c
>> index 0670318..918fa01 100644
>> --- a/restore/tree.c
>> +++ b/restore/tree.c
>> @@ -15,7 +15,6 @@
>> * along with this program; if not, write the Free Software Foundation,
>> * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
>> */
>> -
>> #include <stdio.h>
>> #include <unistd.h>
>> #include <stdlib.h>
>> @@ -265,6 +264,7 @@ extern void usage(void);
>> extern size_t pgsz;
>> extern size_t pgmask;
>> extern bool_t restore_rootdir_permissions;
>> +extern bool_t need_fixrootdir;
>>
>> /* forward declarations of locally defined static functions ******************/
>>
>> @@ -331,10 +331,45 @@ static tran_t *tranp = 0;
>> static char *persname = PERS_NAME;
>> static char *orphname = ORPH_NAME;
>> static xfs_ino_t orphino = ORPH_INO;
>> +static nh_t orig_rooth = NH_NULL;
>>
>>
>> /* definition of locally defined global functions ****************************/
>>
>> +void
>> +tree_fixroot(void)
>> +{
>> + nh_t rooth = persp->p_rooth;
>> + xfs_ino_t rootino;
>> +
>> + while (1) {
>> + nh_t parh;
>> + node_t *rootp = Node_map(rooth);
>> +
>> + rootino = rootp->n_ino;
>> + parh = rootp->n_parh;
>> + Node_unmap(rooth, &rootp);
>> +
>> + if (parh == rooth ||
>> + /*
>> + * since all new node (including non-parent)
>> + * would be adopted into orphh
>> + */
>> + parh == persp->p_orphh ||
>> + parh == NH_NULL)
>> + break;
>> + rooth = parh;
>> + }
>> +
>> + if (rooth != persp->p_rooth) {
>> + persp->p_rooth = rooth;
>> + persp->p_rootino = rootino;
>> +
>
> As far as I see intialization for a root in tree_init(), isn't it
> necessary to adopt the orphanage node(persp->p_orphh) to the new root?
>
These two steps are necessary here:
+ disown(rooth);
+ adopt(persp->p_rooth, persp->p_orphh, NH_NULL);
Otherwise, we hit an assertion error when restroing a renamed file in
the cumulative mode. We need to re-adopt the orphanage dir to the fixed
root for creating a correct path of a node put to orphanage here:
https://git.kernel.org/pub/scm/fs/xfs/xfsdump-dev.git/tree/restore/tree.c#n1498
>> + mlog(MLOG_NORMAL, _("fix root # to %llu (bind mount?)\n"),
>> + rootino);
>> + }
>> +}
>> +
>> /* ARGSUSED */
>> bool_t
>> tree_init(char *hkdir,
>> @@ -754,7 +789,8 @@ tree_begindir(filehdr_t *fhdrp, dah_t *dahp)
>> /* lookup head of hardlink list
>> */
>> hardh = link_hardh(ino, gen);
>> - assert(ino != persp->p_rootino || hardh == persp->p_rooth);
>> + if (need_fixrootdir == BOOL_FALSE)
>> + assert(ino != persp->p_rootino || hardh == persp->p_rooth);
>>
>> /* already present
>> */
>> @@ -823,7 +859,6 @@ tree_begindir(filehdr_t *fhdrp, dah_t *dahp)
>> adopt(persp->p_orphh, hardh, NRH_NULL);
>> *dahp = dah;
>> }
>> -
>> return hardh;
>> }
>>
>> @@ -968,6 +1003,7 @@ tree_addent(nh_t parh, xfs_ino_t ino, gen_t gen, char *name, size_t namelen)
>> }
>> } else {
>> assert(hardp->n_nrh != NRH_NULL);
>> +
>> namebuflen
>> =
>> namreg_get(hardp->n_nrh,
>> @@ -1118,6 +1154,13 @@ tree_addent(nh_t parh, xfs_ino_t ino, gen_t gen, char *name, size_t namelen)
>> ino,
>> gen);
>> }
>> + /* found the fake rootino from subdir, need fix p_rooth. */
>> + if (need_fixrootdir == BOOL_TRUE &&
>> + persp->p_rootino == ino && hardh != persp->p_rooth) {
>> + mlog(MLOG_NORMAL,
>> + _("found fake rootino #%llu, will fix.\n"), ino);
>> + persp->p_rooth = hardh;
>> + }
>> return RV_OK;
>> }
>>
>> @@ -3841,7 +3884,26 @@ selsubtree_recurse_down(nh_t nh, bool_t sensepr)
>> static nh_t
>> link_hardh(xfs_ino_t ino, gen_t gen)
>> {
>> - return hash_find(ino, gen);
>> + nh_t tmp = hash_find(ino, gen);
>> +
>> + /*
>> + * XXX (another workaround): the simply way is that don't reuse node_t
>> + * with gen = 0 created in tree_init(). Otherwise, it could cause
>> + * xfsrestore: tree.c:1003: tree_addent: Assertion
>> + * `hardp->n_nrh != NRH_NULL' failed.
>> + * and that node_t is a dir node but the fake rootino could be a non-dir
>> + * plus reusing it could cause potential loop in tree hierarchy.
>> + */
>> + if (need_fixrootdir == BOOL_TRUE &&
>> + ino == persp->p_rootino && gen == 0 &&
>> + orig_rooth == NH_NULL) {
>
> As I mentioned above, this workaround makes this correction optional.
> This workaround assumes the initially created root is fake. If a dump is
> created correctly without a fake root, this function returns NH_NULL for
> the correct root.
>
>
Due to this part, '-x' flag does not work for the correct dump. We need
to provide procudure for a user who may have a wrong dump with man or
the help message like this:
---------
A user who has a dump created by xfsdump with this bug should see a
table of contents of the dump file before restoring:
xfsrestore -t -f <dumpfile>
If a similar message to the following one is displayed, '-x' is required
to restore the dump:
NOTE: ino 128 salvaging file, placing in orphanage/1024.0/FILE_056
Otherwise, '-x' is not required.
---------
I tried the cumulative mode locally with this fix by combining xfs/064,
xfs/065 and xfs/545 in xfstests. Then, the issue regarding a renamed
file, which is mentioned above, was found. Based on the results of the
tests, the following information also should be provied to users:
---------
In the cumulative mode, a user needs to check with '-t' and use '-x'
flag only for the level 0 dump. Once the root is fixed in restoring the
level 0 dump, '-x' flag is no longer required for level 1+ dumps.
---------
Thanks,
Hironori
> Thanks,
> Hironori
>
>> + mlog(MLOG_NORMAL,
>> +_("link out fake rootino %llu with gen=0 created in tree_init()\n"), ino);
>> + link_out(tmp);
>> + orig_rooth = tmp;
>> + return NH_NULL;
>> + }
>> + return tmp;
>> }
>>
>> /* returns following node in hard link list
>> diff --git a/restore/tree.h b/restore/tree.h
>> index 4f9ffe8..5d0c346 100644
>> --- a/restore/tree.h
>> +++ b/restore/tree.h
>> @@ -18,6 +18,8 @@
>> #ifndef TREE_H
>> #define TREE_H
>>
>> +void tree_fixroot(void);
>> +
>> /* tree_init - creates a new tree abstraction.
>> */
>> extern bool_t tree_init(char *hkdir,
next prev parent reply other threads:[~2022-06-30 19:19 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-11-13 12:51 [RFC PATCH] xfsrestore: fix rootdir due to xfsdump bulkstat misuse Gao Xiang
2020-11-13 14:10 ` Eric Sandeen
2020-11-13 14:15 ` Gao Xiang
2020-11-16 8:23 ` Gao Xiang
2020-11-16 8:07 ` [RFC PATCH v2] " Gao Xiang
2020-11-16 8:13 ` Gao Xiang
2021-09-27 15:00 ` Bill O'Donnell
2021-12-20 15:14 ` Masayoshi Mizuma
2022-06-10 23:05 ` Hironori Shiina
2022-06-30 19:19 ` Hironori Shiina [this message]
2022-09-28 19:10 ` [RFC PATCH V3] " Hironori Shiina
2022-09-29 18:17 ` Darrick J. Wong
2023-04-19 14:16 ` Eric Sandeen
2023-04-19 15:40 ` Darrick J. Wong
2023-04-21 9:10 ` Carlos Maiolino
2023-04-21 16:14 ` Darrick J. Wong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=e61ae295-a331-d36a-cae1-646022dc2a6e@gmail.com \
--to=shiina.hironori@gmail.com \
--cc=ddouwsma@redhat.com \
--cc=hsiangkao@redhat.com \
--cc=linux-xfs@vger.kernel.org \
--cc=sandeen@sandeen.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).