* [PATCH v3 1/4] fsstress: show the real file id and parid in rename_f()
2019-10-31 6:41 [PATCH v3 0/4] xfstests: add deadlock between the AGI and AGF with RENAME_WHITEOUT test kaixuxia
@ 2019-10-31 6:41 ` kaixuxia
2019-10-31 6:41 ` [PATCH v3 2/4] fsstress: add NOREPLACE and WHITEOUT renameat2 support kaixuxia
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: kaixuxia @ 2019-10-31 6:41 UTC (permalink / raw)
To: fstests; +Cc: linux-xfs, guaneryu, bfoster, newtongao, jasperwang
The source file id and parentid are overwritten by del_from_flist()
call, and should show the actually values.
Signed-off-by: kaixuxia <kaixuxia@tencent.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
ltp/fsstress.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/ltp/fsstress.c b/ltp/fsstress.c
index 51976f5..95285f1 100644
--- a/ltp/fsstress.c
+++ b/ltp/fsstress.c
@@ -4227,6 +4227,7 @@ rename_f(int opno, long r)
pathname_t newf;
int oldid;
int parid;
+ int oldparid;
int v;
int v1;
@@ -4265,10 +4266,12 @@ rename_f(int opno, long r)
if (e == 0) {
int xattr_counter = fep->xattr_counter;
- if (flp - flist == FT_DIR) {
- oldid = fep->id;
+ oldid = fep->id;
+ oldparid = fep->parent;
+
+ if (flp - flist == FT_DIR)
fix_parent(oldid, id);
- }
+
del_from_flist(flp - flist, fep - flp->fents);
add_to_flist(flp - flist, id, parid, xattr_counter);
}
@@ -4277,7 +4280,7 @@ rename_f(int opno, long r)
newf.path, e);
if (e == 0) {
printf("%d/%d: rename del entry: id=%d,parent=%d\n",
- procid, opno, fep->id, fep->parent);
+ procid, opno, oldid, oldparid);
printf("%d/%d: rename add entry: id=%d,parent=%d\n",
procid, opno, id, parid);
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v3 2/4] fsstress: add NOREPLACE and WHITEOUT renameat2 support
2019-10-31 6:41 [PATCH v3 0/4] xfstests: add deadlock between the AGI and AGF with RENAME_WHITEOUT test kaixuxia
2019-10-31 6:41 ` [PATCH v3 1/4] fsstress: show the real file id and parid in rename_f() kaixuxia
@ 2019-10-31 6:41 ` kaixuxia
2019-10-31 6:41 ` [PATCH v3 3/4] fsstress: add EXCHANGE " kaixuxia
2019-10-31 6:41 ` [PATCH v3 4/4] xfs: test the deadlock between the AGI and AGF with RENAME_WHITEOUT kaixuxia
3 siblings, 0 replies; 6+ messages in thread
From: kaixuxia @ 2019-10-31 6:41 UTC (permalink / raw)
To: fstests; +Cc: linux-xfs, guaneryu, bfoster, newtongao, jasperwang
Support the renameat2(NOREPLACE and WHITEOUT) syscall in fsstress.
The fent id correlates with filename and the filename correlates
to type in flist, and the RWHITEOUT operation would leave a dev
node around with whatever the name of the source file was, so in
order to maintain filelist/filename integrity, we should restrict
RWHITEOUT source file to device nodes.
Signed-off-by: kaixuxia <kaixuxia@tencent.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
ltp/fsstress.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 90 insertions(+), 15 deletions(-)
diff --git a/ltp/fsstress.c b/ltp/fsstress.c
index 95285f1..ecc1adc 100644
--- a/ltp/fsstress.c
+++ b/ltp/fsstress.c
@@ -44,6 +44,35 @@ io_context_t io_ctx;
#define IOV_MAX 1024
#endif
+#ifndef HAVE_RENAMEAT2
+#if !defined(SYS_renameat2) && defined(__x86_64__)
+#define SYS_renameat2 316
+#endif
+
+#if !defined(SYS_renameat2) && defined(__i386__)
+#define SYS_renameat2 353
+#endif
+
+static int renameat2(int dfd1, const char *path1,
+ int dfd2, const char *path2,
+ unsigned int flags)
+{
+#ifdef SYS_renameat2
+ return syscall(SYS_renameat2, dfd1, path1, dfd2, path2, flags);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+#endif
+
+#ifndef RENAME_NOREPLACE
+#define RENAME_NOREPLACE (1 << 0) /* Don't overwrite target */
+#endif
+#ifndef RENAME_WHITEOUT
+#define RENAME_WHITEOUT (1 << 2) /* Whiteout source */
+#endif
+
#define FILELEN_MAX (32*4096)
typedef enum {
@@ -85,6 +114,8 @@ typedef enum {
OP_READV,
OP_REMOVEFATTR,
OP_RENAME,
+ OP_RNOREPLACE,
+ OP_RWHITEOUT,
OP_RESVSP,
OP_RMDIR,
OP_SETATTR,
@@ -203,6 +234,8 @@ void readlink_f(int, long);
void readv_f(int, long);
void removefattr_f(int, long);
void rename_f(int, long);
+void rnoreplace_f(int, long);
+void rwhiteout_f(int, long);
void resvsp_f(int, long);
void rmdir_f(int, long);
void setattr_f(int, long);
@@ -262,6 +295,8 @@ opdesc_t ops[] = {
/* remove (delete) extended attribute */
{ OP_REMOVEFATTR, "removefattr", removefattr_f, 1, 1 },
{ OP_RENAME, "rename", rename_f, 2, 1 },
+ { OP_RNOREPLACE, "rnoreplace", rnoreplace_f, 2, 1 },
+ { OP_RWHITEOUT, "rwhiteout", rwhiteout_f, 2, 1 },
{ OP_RESVSP, "resvsp", resvsp_f, 1, 1 },
{ OP_RMDIR, "rmdir", rmdir_f, 1, 1 },
/* set attribute flag (FS_IOC_SETFLAGS ioctl) */
@@ -354,7 +389,7 @@ int open_path(pathname_t *, int);
DIR *opendir_path(pathname_t *);
void process_freq(char *);
int readlink_path(pathname_t *, char *, size_t);
-int rename_path(pathname_t *, pathname_t *);
+int rename_path(pathname_t *, pathname_t *, int);
int rmdir_path(pathname_t *);
void separate_pathname(pathname_t *, char *, pathname_t *);
void show_ops(int, char *);
@@ -1519,7 +1554,7 @@ readlink_path(pathname_t *name, char *lbuf, size_t lbufsiz)
}
int
-rename_path(pathname_t *name1, pathname_t *name2)
+rename_path(pathname_t *name1, pathname_t *name2, int mode)
{
char buf1[NAME_MAX + 1];
char buf2[NAME_MAX + 1];
@@ -1528,14 +1563,18 @@ rename_path(pathname_t *name1, pathname_t *name2)
pathname_t newname2;
int rval;
- rval = rename(name1->path, name2->path);
+ if (mode == 0)
+ rval = rename(name1->path, name2->path);
+ else
+ rval = renameat2(AT_FDCWD, name1->path,
+ AT_FDCWD, name2->path, mode);
if (rval >= 0 || errno != ENAMETOOLONG)
return rval;
separate_pathname(name1, buf1, &newname1);
separate_pathname(name2, buf2, &newname2);
if (strcmp(buf1, buf2) == 0) {
if (chdir(buf1) == 0) {
- rval = rename_path(&newname1, &newname2);
+ rval = rename_path(&newname1, &newname2, mode);
assert(chdir("..") == 0);
}
} else {
@@ -1555,7 +1594,7 @@ rename_path(pathname_t *name1, pathname_t *name2)
append_pathname(&newname2, "../");
append_pathname(&newname2, name2->path);
if (chdir(buf1) == 0) {
- rval = rename_path(&newname1, &newname2);
+ rval = rename_path(&newname1, &newname2, mode);
assert(chdir("..") == 0);
}
} else {
@@ -1563,7 +1602,7 @@ rename_path(pathname_t *name1, pathname_t *name2)
append_pathname(&newname1, "../");
append_pathname(&newname1, name1->path);
if (chdir(buf2) == 0) {
- rval = rename_path(&newname1, &newname2);
+ rval = rename_path(&newname1, &newname2, mode);
assert(chdir("..") == 0);
}
}
@@ -4215,8 +4254,17 @@ out:
free_pathname(&f);
}
+struct print_flags renameat2_flags [] = {
+ { RENAME_NOREPLACE, "NOREPLACE"},
+ { RENAME_WHITEOUT, "WHITEOUT"},
+ { -1, NULL}
+};
+
+#define translate_renameat2_flags(mode) \
+ ({translate_flags(mode, "|", renameat2_flags);})
+
void
-rename_f(int opno, long r)
+do_renameat2(int opno, long r, int mode)
{
fent_t *dfep;
int e;
@@ -4228,14 +4276,17 @@ rename_f(int opno, long r)
int oldid;
int parid;
int oldparid;
+ int which;
int v;
int v1;
/* get an existing path for the source of the rename */
init_pathname(&f);
- if (!get_fname(FT_ANYm, r, &f, &flp, &fep, &v1)) {
+ which = (mode == RENAME_WHITEOUT) ? FT_DEVm : FT_ANYm;
+ if (!get_fname(which, r, &f, &flp, &fep, &v1)) {
if (v1)
- printf("%d/%d: rename - no filename\n", procid, opno);
+ printf("%d/%d: rename - no source filename\n",
+ procid, opno);
free_pathname(&f);
return;
}
@@ -4261,7 +4312,7 @@ rename_f(int opno, long r)
free_pathname(&f);
return;
}
- e = rename_path(&f, &newf) < 0 ? errno : 0;
+ e = rename_path(&f, &newf, mode) < 0 ? errno : 0;
check_cwd();
if (e == 0) {
int xattr_counter = fep->xattr_counter;
@@ -4272,16 +4323,22 @@ rename_f(int opno, long r)
if (flp - flist == FT_DIR)
fix_parent(oldid, id);
- del_from_flist(flp - flist, fep - flp->fents);
- add_to_flist(flp - flist, id, parid, xattr_counter);
+ if (mode == RENAME_WHITEOUT) {
+ fep->xattr_counter = 0;
+ add_to_flist(flp - flist, id, parid, xattr_counter);
+ } else {
+ del_from_flist(flp - flist, fep - flp->fents);
+ add_to_flist(flp - flist, id, parid, xattr_counter);
+ }
}
if (v) {
- printf("%d/%d: rename %s to %s %d\n", procid, opno, f.path,
+ printf("%d/%d: rename(%s) %s to %s %d\n", procid,
+ opno, translate_renameat2_flags(mode), f.path,
newf.path, e);
if (e == 0) {
- printf("%d/%d: rename del entry: id=%d,parent=%d\n",
+ printf("%d/%d: rename source entry: id=%d,parent=%d\n",
procid, opno, oldid, oldparid);
- printf("%d/%d: rename add entry: id=%d,parent=%d\n",
+ printf("%d/%d: rename target entry: id=%d,parent=%d\n",
procid, opno, id, parid);
}
}
@@ -4290,6 +4347,24 @@ rename_f(int opno, long r)
}
void
+rename_f(int opno, long r)
+{
+ do_renameat2(opno, r, 0);
+}
+
+void
+rnoreplace_f(int opno, long r)
+{
+ do_renameat2(opno, r, RENAME_NOREPLACE);
+}
+
+void
+rwhiteout_f(int opno, long r)
+{
+ do_renameat2(opno, r, RENAME_WHITEOUT);
+}
+
+void
resvsp_f(int opno, long r)
{
int e;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v3 3/4] fsstress: add EXCHANGE renameat2 support
2019-10-31 6:41 [PATCH v3 0/4] xfstests: add deadlock between the AGI and AGF with RENAME_WHITEOUT test kaixuxia
2019-10-31 6:41 ` [PATCH v3 1/4] fsstress: show the real file id and parid in rename_f() kaixuxia
2019-10-31 6:41 ` [PATCH v3 2/4] fsstress: add NOREPLACE and WHITEOUT renameat2 support kaixuxia
@ 2019-10-31 6:41 ` kaixuxia
2019-11-01 17:24 ` Brian Foster
2019-10-31 6:41 ` [PATCH v3 4/4] xfs: test the deadlock between the AGI and AGF with RENAME_WHITEOUT kaixuxia
3 siblings, 1 reply; 6+ messages in thread
From: kaixuxia @ 2019-10-31 6:41 UTC (permalink / raw)
To: fstests; +Cc: linux-xfs, guaneryu, bfoster, newtongao, jasperwang
Support the EXCHANGE renameat2 syscall in fsstress.
In order to maintain filelist/filename integrity, we restrict
rexchange to files of the same type.
Signed-off-by: kaixuxia <kaixuxia@tencent.com>
---
ltp/fsstress.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 96 insertions(+), 21 deletions(-)
diff --git a/ltp/fsstress.c b/ltp/fsstress.c
index ecc1adc..0125571 100644
--- a/ltp/fsstress.c
+++ b/ltp/fsstress.c
@@ -69,6 +69,9 @@ static int renameat2(int dfd1, const char *path1,
#ifndef RENAME_NOREPLACE
#define RENAME_NOREPLACE (1 << 0) /* Don't overwrite target */
#endif
+#ifndef RENAME_EXCHANGE
+#define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */
+#endif
#ifndef RENAME_WHITEOUT
#define RENAME_WHITEOUT (1 << 2) /* Whiteout source */
#endif
@@ -115,6 +118,7 @@ typedef enum {
OP_REMOVEFATTR,
OP_RENAME,
OP_RNOREPLACE,
+ OP_REXCHANGE,
OP_RWHITEOUT,
OP_RESVSP,
OP_RMDIR,
@@ -235,6 +239,7 @@ void readv_f(int, long);
void removefattr_f(int, long);
void rename_f(int, long);
void rnoreplace_f(int, long);
+void rexchange_f(int, long);
void rwhiteout_f(int, long);
void resvsp_f(int, long);
void rmdir_f(int, long);
@@ -296,6 +301,7 @@ opdesc_t ops[] = {
{ OP_REMOVEFATTR, "removefattr", removefattr_f, 1, 1 },
{ OP_RENAME, "rename", rename_f, 2, 1 },
{ OP_RNOREPLACE, "rnoreplace", rnoreplace_f, 2, 1 },
+ { OP_REXCHANGE, "rexchange", rexchange_f, 2, 1 },
{ OP_RWHITEOUT, "rwhiteout", rwhiteout_f, 2, 1 },
{ OP_RESVSP, "resvsp", resvsp_f, 1, 1 },
{ OP_RMDIR, "rmdir", rmdir_f, 1, 1 },
@@ -371,7 +377,8 @@ void del_from_flist(int, int);
int dirid_to_name(char *, int);
void doproc(void);
int fent_to_name(pathname_t *, flist_t *, fent_t *);
-void fix_parent(int, int);
+bool fents_ancestor_check(fent_t *, fent_t *);
+void fix_parent(int, int, bool);
void free_pathname(pathname_t *);
int generate_fname(fent_t *, int, pathname_t *, int *, int *);
int generate_xattr_name(int, char *, int);
@@ -1117,8 +1124,22 @@ fent_to_name(pathname_t *name, flist_t *flp, fent_t *fep)
return 1;
}
+bool
+fents_ancestor_check(fent_t *fep, fent_t *dfep)
+{
+ fent_t *tmpfep;
+
+ for (tmpfep = fep; tmpfep->parent != -1;
+ tmpfep = dirid_to_fent(tmpfep->parent)) {
+ if (tmpfep->parent == dfep->id)
+ return true;
+ }
+
+ return false;
+}
+
void
-fix_parent(int oldid, int newid)
+fix_parent(int oldid, int newid, bool swap)
{
fent_t *fep;
flist_t *flp;
@@ -1129,6 +1150,8 @@ fix_parent(int oldid, int newid)
for (j = 0, fep = flp->fents; j < flp->nfiles; j++, fep++) {
if (fep->parent == oldid)
fep->parent = newid;
+ else if (swap && fep->parent == newid)
+ fep->parent = oldid;
}
}
}
@@ -4256,6 +4279,7 @@ out:
struct print_flags renameat2_flags [] = {
{ RENAME_NOREPLACE, "NOREPLACE"},
+ { RENAME_EXCHANGE, "EXCHANGE"},
{ RENAME_WHITEOUT, "WHITEOUT"},
{ -1, NULL}
};
@@ -4291,41 +4315,86 @@ do_renameat2(int opno, long r, int mode)
return;
}
- /* get an existing directory for the destination parent directory name */
- if (!get_fname(FT_DIRm, random(), NULL, NULL, &dfep, &v))
- parid = -1;
- else
- parid = dfep->id;
- v |= v1;
+ /*
+ * Both pathnames must exist for the RENAME_EXCHANGE, and in
+ * order to maintain filelist/filename integrity, we should
+ * restrict exchange operation to files of the same type.
+ */
+ if (mode == RENAME_EXCHANGE) {
+ which = 1 << (flp - flist);
+ init_pathname(&newf);
+ if (!get_fname(which, random(), &newf, NULL, &dfep, &v)) {
+ if (v)
+ printf("%d/%d: rename - no target filename\n",
+ procid, opno);
+ free_pathname(&newf);
+ free_pathname(&f);
+ return;
+ }
+ if (which == FT_DIRm && (fents_ancestor_check(fep, dfep) ||
+ fents_ancestor_check(dfep, fep))) {
+ if (v)
+ printf("%d/%d: rename(REXCHANGE) %s and %s "
+ "have ancestor-descendant relationship\n",
+ procid, opno, f.path, newf.path);
+ free_pathname(&newf);
+ free_pathname(&f);
+ return;
+ }
+ v |= v1;
+ id = dfep->id;
+ parid = dfep->parent;
+ } else {
+ /*
+ * Get an existing directory for the destination parent
+ * directory name.
+ */
+ if (!get_fname(FT_DIRm, random(), NULL, NULL, &dfep, &v))
+ parid = -1;
+ else
+ parid = dfep->id;
+ v |= v1;
- /* generate a new path using an existing parent directory in name */
- init_pathname(&newf);
- e = generate_fname(dfep, flp - flist, &newf, &id, &v1);
- v |= v1;
- if (!e) {
- if (v) {
- (void)fent_to_name(&f, &flist[FT_DIR], dfep);
- printf("%d/%d: rename - no filename from %s\n",
- procid, opno, f.path);
+ /*
+ * Generate a new path using an existing parent directory
+ * in name.
+ */
+ init_pathname(&newf);
+ e = generate_fname(dfep, flp - flist, &newf, &id, &v1);
+ v |= v1;
+ if (!e) {
+ if (v) {
+ (void)fent_to_name(&f, &flist[FT_DIR], dfep);
+ printf("%d/%d: rename - no filename from %s\n",
+ procid, opno, f.path);
+ }
+ free_pathname(&newf);
+ free_pathname(&f);
+ return;
}
- free_pathname(&newf);
- free_pathname(&f);
- return;
}
e = rename_path(&f, &newf, mode) < 0 ? errno : 0;
check_cwd();
if (e == 0) {
int xattr_counter = fep->xattr_counter;
+ bool swap = (mode == RENAME_EXCHANGE) ? true : false;
oldid = fep->id;
oldparid = fep->parent;
+ /*
+ * Swap the parent ids for RENAME_EXCHANGE, and replace the
+ * old parent id for the others.
+ */
if (flp - flist == FT_DIR)
- fix_parent(oldid, id);
+ fix_parent(oldid, id, swap);
if (mode == RENAME_WHITEOUT) {
fep->xattr_counter = 0;
add_to_flist(flp - flist, id, parid, xattr_counter);
+ } else if (mode == RENAME_EXCHANGE) {
+ fep->xattr_counter = dfep->xattr_counter;
+ dfep->xattr_counter = xattr_counter;
} else {
del_from_flist(flp - flist, fep - flp->fents);
add_to_flist(flp - flist, id, parid, xattr_counter);
@@ -4359,6 +4428,12 @@ rnoreplace_f(int opno, long r)
}
void
+rexchange_f(int opno, long r)
+{
+ do_renameat2(opno, r, RENAME_EXCHANGE);
+}
+
+void
rwhiteout_f(int opno, long r)
{
do_renameat2(opno, r, RENAME_WHITEOUT);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v3 3/4] fsstress: add EXCHANGE renameat2 support
2019-10-31 6:41 ` [PATCH v3 3/4] fsstress: add EXCHANGE " kaixuxia
@ 2019-11-01 17:24 ` Brian Foster
0 siblings, 0 replies; 6+ messages in thread
From: Brian Foster @ 2019-11-01 17:24 UTC (permalink / raw)
To: kaixuxia; +Cc: fstests, linux-xfs, guaneryu, newtongao, jasperwang
On Thu, Oct 31, 2019 at 02:41:48PM +0800, kaixuxia wrote:
> Support the EXCHANGE renameat2 syscall in fsstress.
>
> In order to maintain filelist/filename integrity, we restrict
> rexchange to files of the same type.
>
> Signed-off-by: kaixuxia <kaixuxia@tencent.com>
> ---
Looks good to me and no errors on a quick test:
Reviewed-by: Brian Foster <bfoster@redhat.com>
> ltp/fsstress.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++-----------
> 1 file changed, 96 insertions(+), 21 deletions(-)
>
> diff --git a/ltp/fsstress.c b/ltp/fsstress.c
> index ecc1adc..0125571 100644
> --- a/ltp/fsstress.c
> +++ b/ltp/fsstress.c
> @@ -69,6 +69,9 @@ static int renameat2(int dfd1, const char *path1,
> #ifndef RENAME_NOREPLACE
> #define RENAME_NOREPLACE (1 << 0) /* Don't overwrite target */
> #endif
> +#ifndef RENAME_EXCHANGE
> +#define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */
> +#endif
> #ifndef RENAME_WHITEOUT
> #define RENAME_WHITEOUT (1 << 2) /* Whiteout source */
> #endif
> @@ -115,6 +118,7 @@ typedef enum {
> OP_REMOVEFATTR,
> OP_RENAME,
> OP_RNOREPLACE,
> + OP_REXCHANGE,
> OP_RWHITEOUT,
> OP_RESVSP,
> OP_RMDIR,
> @@ -235,6 +239,7 @@ void readv_f(int, long);
> void removefattr_f(int, long);
> void rename_f(int, long);
> void rnoreplace_f(int, long);
> +void rexchange_f(int, long);
> void rwhiteout_f(int, long);
> void resvsp_f(int, long);
> void rmdir_f(int, long);
> @@ -296,6 +301,7 @@ opdesc_t ops[] = {
> { OP_REMOVEFATTR, "removefattr", removefattr_f, 1, 1 },
> { OP_RENAME, "rename", rename_f, 2, 1 },
> { OP_RNOREPLACE, "rnoreplace", rnoreplace_f, 2, 1 },
> + { OP_REXCHANGE, "rexchange", rexchange_f, 2, 1 },
> { OP_RWHITEOUT, "rwhiteout", rwhiteout_f, 2, 1 },
> { OP_RESVSP, "resvsp", resvsp_f, 1, 1 },
> { OP_RMDIR, "rmdir", rmdir_f, 1, 1 },
> @@ -371,7 +377,8 @@ void del_from_flist(int, int);
> int dirid_to_name(char *, int);
> void doproc(void);
> int fent_to_name(pathname_t *, flist_t *, fent_t *);
> -void fix_parent(int, int);
> +bool fents_ancestor_check(fent_t *, fent_t *);
> +void fix_parent(int, int, bool);
> void free_pathname(pathname_t *);
> int generate_fname(fent_t *, int, pathname_t *, int *, int *);
> int generate_xattr_name(int, char *, int);
> @@ -1117,8 +1124,22 @@ fent_to_name(pathname_t *name, flist_t *flp, fent_t *fep)
> return 1;
> }
>
> +bool
> +fents_ancestor_check(fent_t *fep, fent_t *dfep)
> +{
> + fent_t *tmpfep;
> +
> + for (tmpfep = fep; tmpfep->parent != -1;
> + tmpfep = dirid_to_fent(tmpfep->parent)) {
> + if (tmpfep->parent == dfep->id)
> + return true;
> + }
> +
> + return false;
> +}
> +
> void
> -fix_parent(int oldid, int newid)
> +fix_parent(int oldid, int newid, bool swap)
> {
> fent_t *fep;
> flist_t *flp;
> @@ -1129,6 +1150,8 @@ fix_parent(int oldid, int newid)
> for (j = 0, fep = flp->fents; j < flp->nfiles; j++, fep++) {
> if (fep->parent == oldid)
> fep->parent = newid;
> + else if (swap && fep->parent == newid)
> + fep->parent = oldid;
> }
> }
> }
> @@ -4256,6 +4279,7 @@ out:
>
> struct print_flags renameat2_flags [] = {
> { RENAME_NOREPLACE, "NOREPLACE"},
> + { RENAME_EXCHANGE, "EXCHANGE"},
> { RENAME_WHITEOUT, "WHITEOUT"},
> { -1, NULL}
> };
> @@ -4291,41 +4315,86 @@ do_renameat2(int opno, long r, int mode)
> return;
> }
>
> - /* get an existing directory for the destination parent directory name */
> - if (!get_fname(FT_DIRm, random(), NULL, NULL, &dfep, &v))
> - parid = -1;
> - else
> - parid = dfep->id;
> - v |= v1;
> + /*
> + * Both pathnames must exist for the RENAME_EXCHANGE, and in
> + * order to maintain filelist/filename integrity, we should
> + * restrict exchange operation to files of the same type.
> + */
> + if (mode == RENAME_EXCHANGE) {
> + which = 1 << (flp - flist);
> + init_pathname(&newf);
> + if (!get_fname(which, random(), &newf, NULL, &dfep, &v)) {
> + if (v)
> + printf("%d/%d: rename - no target filename\n",
> + procid, opno);
> + free_pathname(&newf);
> + free_pathname(&f);
> + return;
> + }
> + if (which == FT_DIRm && (fents_ancestor_check(fep, dfep) ||
> + fents_ancestor_check(dfep, fep))) {
> + if (v)
> + printf("%d/%d: rename(REXCHANGE) %s and %s "
> + "have ancestor-descendant relationship\n",
> + procid, opno, f.path, newf.path);
> + free_pathname(&newf);
> + free_pathname(&f);
> + return;
> + }
> + v |= v1;
> + id = dfep->id;
> + parid = dfep->parent;
> + } else {
> + /*
> + * Get an existing directory for the destination parent
> + * directory name.
> + */
> + if (!get_fname(FT_DIRm, random(), NULL, NULL, &dfep, &v))
> + parid = -1;
> + else
> + parid = dfep->id;
> + v |= v1;
>
> - /* generate a new path using an existing parent directory in name */
> - init_pathname(&newf);
> - e = generate_fname(dfep, flp - flist, &newf, &id, &v1);
> - v |= v1;
> - if (!e) {
> - if (v) {
> - (void)fent_to_name(&f, &flist[FT_DIR], dfep);
> - printf("%d/%d: rename - no filename from %s\n",
> - procid, opno, f.path);
> + /*
> + * Generate a new path using an existing parent directory
> + * in name.
> + */
> + init_pathname(&newf);
> + e = generate_fname(dfep, flp - flist, &newf, &id, &v1);
> + v |= v1;
> + if (!e) {
> + if (v) {
> + (void)fent_to_name(&f, &flist[FT_DIR], dfep);
> + printf("%d/%d: rename - no filename from %s\n",
> + procid, opno, f.path);
> + }
> + free_pathname(&newf);
> + free_pathname(&f);
> + return;
> }
> - free_pathname(&newf);
> - free_pathname(&f);
> - return;
> }
> e = rename_path(&f, &newf, mode) < 0 ? errno : 0;
> check_cwd();
> if (e == 0) {
> int xattr_counter = fep->xattr_counter;
> + bool swap = (mode == RENAME_EXCHANGE) ? true : false;
>
> oldid = fep->id;
> oldparid = fep->parent;
>
> + /*
> + * Swap the parent ids for RENAME_EXCHANGE, and replace the
> + * old parent id for the others.
> + */
> if (flp - flist == FT_DIR)
> - fix_parent(oldid, id);
> + fix_parent(oldid, id, swap);
>
> if (mode == RENAME_WHITEOUT) {
> fep->xattr_counter = 0;
> add_to_flist(flp - flist, id, parid, xattr_counter);
> + } else if (mode == RENAME_EXCHANGE) {
> + fep->xattr_counter = dfep->xattr_counter;
> + dfep->xattr_counter = xattr_counter;
> } else {
> del_from_flist(flp - flist, fep - flp->fents);
> add_to_flist(flp - flist, id, parid, xattr_counter);
> @@ -4359,6 +4428,12 @@ rnoreplace_f(int opno, long r)
> }
>
> void
> +rexchange_f(int opno, long r)
> +{
> + do_renameat2(opno, r, RENAME_EXCHANGE);
> +}
> +
> +void
> rwhiteout_f(int opno, long r)
> {
> do_renameat2(opno, r, RENAME_WHITEOUT);
> --
> 1.8.3.1
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 4/4] xfs: test the deadlock between the AGI and AGF with RENAME_WHITEOUT
2019-10-31 6:41 [PATCH v3 0/4] xfstests: add deadlock between the AGI and AGF with RENAME_WHITEOUT test kaixuxia
` (2 preceding siblings ...)
2019-10-31 6:41 ` [PATCH v3 3/4] fsstress: add EXCHANGE " kaixuxia
@ 2019-10-31 6:41 ` kaixuxia
3 siblings, 0 replies; 6+ messages in thread
From: kaixuxia @ 2019-10-31 6:41 UTC (permalink / raw)
To: fstests; +Cc: linux-xfs, guaneryu, bfoster, newtongao, jasperwang
There is ABBA deadlock bug between the AGI and AGF when performing
rename() with RENAME_WHITEOUT flag, and add this testcase to make
sure the rename() call works well.
Signed-off-by: kaixuxia <kaixuxia@tencent.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
tests/generic/585 | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++
tests/generic/585.out | 2 ++
tests/generic/group | 1 +
3 files changed, 59 insertions(+)
create mode 100755 tests/generic/585
create mode 100644 tests/generic/585.out
diff --git a/tests/generic/585 b/tests/generic/585
new file mode 100755
index 0000000..f815da5
--- /dev/null
+++ b/tests/generic/585
@@ -0,0 +1,56 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2019 Tencent. All Rights Reserved.
+#
+# FS QA Test No. 585
+#
+# Regression test for:
+# bc56ad8c74b8: ("xfs: Fix deadlock between AGI and AGF with RENAME_WHITEOUT")
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+ cd /
+ rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/renameat2
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+_supported_os Linux
+_supported_fs generic
+_require_scratch
+_require_renameat2 whiteout
+
+_scratch_mkfs > $seqres.full 2>&1 || _fail "mkfs failed"
+_scratch_mount >> $seqres.full 2>&1
+
+# start a create and rename(rename_whiteout) workload. These processes
+# occur simultaneously may cause the deadlock between AGI and AGF with
+# RENAME_WHITEOUT.
+$FSSTRESS_PROG -z -n 150 -p 100 \
+ -f mknod=5 \
+ -f rwhiteout=5 \
+ -d $SCRATCH_MNT/fsstress >> $seqres.full 2>&1
+
+echo Silence is golden
+
+# Failure comes in the form of a deadlock.
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/585.out b/tests/generic/585.out
new file mode 100644
index 0000000..e4dd43b
--- /dev/null
+++ b/tests/generic/585.out
@@ -0,0 +1,2 @@
+QA output created by 585
+Silence is golden
diff --git a/tests/generic/group b/tests/generic/group
index 42ca2b9..e5d0c1d 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -587,3 +587,4 @@
582 auto quick encrypt
583 auto quick encrypt
584 auto quick encrypt
+585 auto rename
--
1.8.3.1
^ permalink raw reply related [flat|nested] 6+ messages in thread