From: Darrick J. Wong <darrick.wong@xxxxxxxxxx> Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx> --- ltp/fsx.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/ltp/fsx.c b/ltp/fsx.c index 6f2b3364..3161ba12 100644 --- a/ltp/fsx.c +++ b/ltp/fsx.c @@ -34,6 +34,7 @@ #ifdef AIO #include <libaio.h> #endif +#include <sys/syscall.h> #ifndef MAP_FILE # define MAP_FILE 0 @@ -105,6 +106,7 @@ enum { OP_INSERT_RANGE, OP_CLONE_RANGE, OP_DEDUPE_RANGE, + OP_COPY_RANGE, OP_MAX_FULL, /* integrity operations */ @@ -261,6 +263,7 @@ static const char *op_names[] = { [OP_INSERT_RANGE] = "insert_range", [OP_CLONE_RANGE] = "clone_range", [OP_DEDUPE_RANGE] = "dedupe_range", + [OP_COPY_RANGE] = "copy_range", [OP_FSYNC] = "fsync", }; @@ -457,6 +460,13 @@ logdump(void) if (overlap) prt("\t******IIII"); break; + case OP_COPY_RANGE: + prt("COPY 0x%x thru 0x%x\t(0x%x bytes) to 0x%x", + lp->args[0], lp->args[0] + lp->args[1] - 1, + lp->args[1], lp->args[2]); + if (overlap) + prt("\t******IIII"); + break; case OP_FSYNC: prt("FSYNC"); break; @@ -1400,6 +1410,73 @@ do_dedupe_range(unsigned offset, unsigned length, unsigned dest) } #endif +#ifdef HAVE_COPY_FILE_RANGE +void +do_copy_range(unsigned offset, unsigned length, unsigned dest) +{ + loff_t o1, o2; + ssize_t nr; + + if (length == 0) { + if (!quiet && testcalls > simulatedopcount) + prt("skipping zero length copy range\n"); + log5(OP_COPY_RANGE, offset, length, dest, FL_SKIPPED); + return; + } + + if ((loff_t)offset >= file_size) { + if (!quiet && testcalls > simulatedopcount) + prt("skipping copy range behind EOF\n"); + log5(OP_COPY_RANGE, offset, length, dest, FL_SKIPPED); + return; + } + + log5(OP_COPY_RANGE, offset, length, dest, FL_NONE); + + if (testcalls <= simulatedopcount) + return; + + if ((progressinterval && testcalls % progressinterval == 0) || + (debug && (monitorstart == -1 || monitorend == -1 || + dest <= monitorstart || dest + length <= monitorend))) { + prt("%lu copy\tfrom 0x%x to 0x%x, (0x%x bytes) at 0x%x\n", + testcalls, offset, offset+length, length, dest); + } + + o1 = offset; + o2 = dest; + + nr = copy_file_range(fd, &o1, fd, &o2, length, 0); + if (nr == -1) { + if (errno == EOPNOTSUPP || errno == ENOTTY) { + if (!quiet && testcalls > simulatedopcount) + prt("skipping unsupported copy range\n"); + logptr--; + log5(OP_COPY_RANGE, offset, length, dest, FL_SKIPPED); + return; + } + + prt("copy range: 0x%x to 0x%x at 0x%x\n", offset, + offset + length, dest); + prterr("do_copy_range:"); + report_failure(161); + } + + memcpy(good_buf + dest, good_buf + offset, nr); + if (dest > file_size) + memset(good_buf + file_size, '\0', dest - file_size); + if (dest + nr > file_size) + file_size = dest + nr; +} + +#else +void +do_copy_range(unsigned offset, unsigned length, unsigned dest) +{ + return; +} +#endif + #ifdef HAVE_LINUX_FALLOC_H /* fallocate is basically a no-op unless extending, then a lot like a truncate */ void @@ -1719,6 +1796,14 @@ test(void) offset2 + size > file_size); break; } + case OP_COPY_RANGE: + TRIM_OFF_LEN(offset, size, file_size); + do { + offset2 = random(); + TRIM_OFF(offset2, maxfilelen); + } while (llabs(offset2 - offset) < size || + offset2 + size > maxfilelen); + break; } have_op: @@ -1764,6 +1849,7 @@ test(void) break; case OP_CLONE_RANGE: case OP_DEDUPE_RANGE: + case OP_COPY_RANGE: if (!remap_calls) { log5(op, offset, size, offset2, FL_SKIPPED); goto out; @@ -1859,6 +1945,18 @@ test(void) do_dedupe_range(offset, size, offset2); break; + case OP_COPY_RANGE: + if (size == 0) { + log5(OP_COPY_RANGE, offset, size, offset2, FL_SKIPPED); + goto out; + } + if (offset2 + size > maxfilelen) { + log5(OP_COPY_RANGE, offset, size, offset2, FL_SKIPPED); + goto out; + } + + do_copy_range(offset, size, offset2); + break; case OP_FSYNC: dofsync(); break;