[Ocfs2-test-devel] [PATCH 1/1] Ocfs2-test: Add testcase to ocfs2-test to verify refcount after punching holes.
Tristan Ye
tristan.ye at oracle.com
Thu Jan 28 20:57:18 PST 2010
The newly added testcase was originally aimed to expose a reflink bug on punching holes:
http://oss.oracle.com/bugzilla/show_bug.cgi?id=1216
The new testcase did following things:
1. Prepare a oringal file with clusters.
2. Reflink the original file to N reflinks.
3. Punching hole randomly on original file.
4. Verify the consistency on reflinks(expect reflinks stay unchanged)
Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
---
programs/reflink_tests/reflink_test.c | 127 ++++++++++++++++++++++++++-
programs/reflink_tests/reflink_test.h | 7 ++
programs/reflink_tests/reflink_test_run.sh | 18 ++++
programs/reflink_tests/reflink_test_utils.c | 103 ++++++++++++++++++++++
4 files changed, 252 insertions(+), 3 deletions(-)
diff --git a/programs/reflink_tests/reflink_test.c b/programs/reflink_tests/reflink_test.c
index 9c95a24..49c5990 100755
--- a/programs/reflink_tests/reflink_test.c
+++ b/programs/reflink_tests/reflink_test.c
@@ -118,6 +118,7 @@ static void usage(void)
"-O enable O_DIRECT test.\n"
"-D enable destructive test.\n"
"-v enable verification for destructive test.\n"
+ "-H enable CoW verification test for punching holse.\n"
"-I enable inline-data test.\n"
"-x enable combination test with xattr.\n"
"-h enable holes punching and filling tests.\n"
@@ -141,8 +142,8 @@ static int parse_opts(int argc, char **argv)
while (1) {
c = getopt(argc, argv,
- "i:d:w:IOfFbBsSrRmMW:n:N:"
- "l:L:c:C:p:x:X:h:H:o:v:a:P:D:");
+ "i:d:w:IOfFbBsSrRHmMW:n:N:"
+ "l:L:c:C:p:x:X:h:o:v:a:P:D:");
if (c == -1)
break;
@@ -220,11 +221,12 @@ static int parse_opts(int argc, char **argv)
xattr_nums = atol(optarg);
break;
case 'h':
- case 'H':
test_flags |= HOLE_TEST;
hole_nums = atol(optarg);
case 'P':
port = atol(optarg);
+ case 'H':
+ test_flags |= PUNH_TEST;
default:
break;
}
@@ -2244,6 +2246,122 @@ static int inline_test(void)
return 0;
}
+static int verify_punch_hole_cow_test(void)
+{
+ int ret = 0, fd;
+ int sub_testno = 1;
+ char *write_pattern = NULL;
+ char *read_pattern = NULL;
+
+ unsigned long i;
+ unsigned long long offset, len, read_size;
+ char dest[PATH_MAX];
+
+ printf("Test %d: Verify cow for punching holes.\n", testno++);
+
+ snprintf(orig_path, PATH_MAX, "%s/original_verify_cow_punch_hole_"
+ "refile", workplace);
+
+ write_pattern = malloc(clustersize);
+ read_pattern = malloc(clustersize);
+
+ get_rand_buf(write_pattern, clustersize);
+ memset(read_pattern, 0, clustersize);
+
+ printf(" *SubTest %d: Prepare file.\n", sub_testno++);
+ ret = prep_orig_file_with_pattern(orig_path, file_size, clustersize,
+ write_pattern, 0);
+ if (ret < 0)
+ goto bail;
+ printf(" *SubTest %d: Do %ld reflinks.\n", sub_testno++, ref_counts);
+ ret = do_reflinks(orig_path, orig_path, ref_counts, 0);
+ if (ret < 0)
+ goto bail;
+
+ printf(" *SubTest %d: Punching hole to original file.\n",
+ sub_testno++);
+
+ fd = open_file(orig_path, O_RDWR);
+ if (fd < 0)
+ goto bail;
+
+ offset = 0;
+
+ while (offset < file_size) {
+
+ offset += get_rand(0, clustersize);
+ len = get_rand(clustersize, 2 * clustersize);
+ if ((offset + len) > file_size)
+ len = file_size - offset;
+
+ ret = punch_hole(fd, offset, len);
+ if (ret < 0) {
+ fprintf(stderr, "failed to punch hole from %llu to "
+ "%llu on %s\n", offset,
+ offset + len, orig_path);
+ close(fd);
+ goto bail;
+ }
+
+ offset += len;
+ }
+
+ close(fd);
+
+ printf(" *SubTest %d: Verify reflinks after punching holes.\n",
+ sub_testno++);
+
+ for (i = 0; i < ref_counts; i++) {
+ snprintf(dest, PATH_MAX, "%sr%ld", orig_path, i);
+ fd = open_file(dest, O_RDONLY);
+ if (fd < 0)
+ goto bail;
+
+ offset = 0;
+ while (offset < file_size) {
+ if ((offset + clustersize) > file_size)
+ read_size = file_size - offset;
+ else
+ read_size = clustersize;
+ ret = read_at(fd, read_pattern, read_size, offset);
+ if (ret < 0) {
+ close(fd);
+ goto bail;
+ }
+ if (memcmp(read_pattern, write_pattern, read_size)) {
+ fprintf(stderr, "Corrupted chunk found on "
+ "reflink %s: from %llu to %llu\n",
+ dest, offset, offset + read_size);
+ ret = -1;
+ close(fd);
+ goto bail;
+ }
+ offset += read_size;
+ }
+
+ close(fd);
+
+ }
+
+ printf(" *SubTest %d: Unlinking reflinks and original file.\n",
+ sub_testno++);
+
+ ret = do_unlinks(orig_path, ref_counts);
+ if (ret < 0)
+ goto bail;
+
+ ret = do_unlink(orig_path);
+
+bail:
+ if (write_pattern)
+ free(write_pattern);
+
+ if (read_pattern)
+ free(read_pattern);
+
+ return ret;
+}
+
static void run_test(void)
{
int i;
@@ -2288,6 +2406,9 @@ static void run_test(void)
if (test_flags & VERI_TEST)
verification_dest();
+ if (test_flags & PUNH_TEST)
+ verify_punch_hole_cow_test();
+
}
}
diff --git a/programs/reflink_tests/reflink_test.h b/programs/reflink_tests/reflink_test.h
index 3db48f1..2117cda 100755
--- a/programs/reflink_tests/reflink_test.h
+++ b/programs/reflink_tests/reflink_test.h
@@ -77,6 +77,7 @@
#define INLN_TEST 0x00000800
#define DSCV_TEST 0x00001000
#define VERI_TEST 0x00002000
+#define PUNH_TEST 0x00004000
#define MPI_RET_SUCCESS 0
#define MPI_RET_FAILED 1
@@ -131,6 +132,9 @@ int fill_pattern(unsigned long size);
int prep_orig_file(char *file_name, unsigned long size, int once);
int prep_orig_file_dio(char *file_name, unsigned long size);
int prep_orig_file_in_chunks(char *file_name, unsigned long chunks);
+int prep_orig_file_with_pattern(char *file_name, unsigned long size,
+ unsigned long chunk_size, char *pattern_buf,
+ int once);
int verify_pattern(char *buf, unsigned long offset, unsigned long size);
int verify_orig_file(char *orig);
@@ -180,4 +184,7 @@ int semaphore_close(int sem_id);
int semaphore_p(int sem_id);
int semaphore_v(int sem_id);
+int open_file(const char *filename, int flags);
+int punch_hole(int fd, uint64_t start, uint64_t len);
+
#endif
diff --git a/programs/reflink_tests/reflink_test_run.sh b/programs/reflink_tests/reflink_test_run.sh
index 097a97a..840f7a2 100755
--- a/programs/reflink_tests/reflink_test_run.sh
+++ b/programs/reflink_tests/reflink_test_run.sh
@@ -533,6 +533,24 @@ ${WORK_PLACE} -D >>${LOG_FILE} 2>&1
f_exit_or_not ${RET}
((TEST_NO++))
+ f_LogRunMsg ${RUN_LOG_FILE} "[${TEST_NO}] Verificationl CoW Test On \
+Punching Holes:"
+ f_LogMsg ${LOG_FILE} "[${TEST_NO}] Verification CoW Test On Punching \
+Holes, CMD:${SUDO} ${REFLINK_TEST_BIN} -i 1 -n 100 -l 3276800 -d ${DEVICE} \
+-w ${WORK_PLACE} -H "
+ ${SUDO} ${REFLINK_TEST_BIN} -i 1 -n 100 -l 3276800 -d ${DEVICE} -w \
+${WORK_PLACE} -H >>${LOG_FILE} 2>&1
+ RET=$?
+ f_echo_status ${RET} | tee -a ${RUN_LOG_FILE}
+ f_exit_or_not ${RET}
+ ((TEST_PASS++))
+ f_LogMsg ${LOG_FILE} "Cleanup working place"
+ ${SUDO} ${CHMOD_BIN} -R 777 ${MOUNT_POINT} >>${LOG_FILE} 2>&1
+ ${RM_BIN} -rf ${WORK_PLACE}/* >>${LOG_FILE} 2>&1
+ RET=$?
+ f_exit_or_not ${RET}
+
+ ((TEST_NO++))
f_LogRunMsg ${RUN_LOG_FILE} "[${TEST_NO}] Bash & Tools Utility Test:"
f_reflink_bash_utils_test 100 104857600 >>${LOG_FILE} 2>&1
RET=$?
diff --git a/programs/reflink_tests/reflink_test_utils.c b/programs/reflink_tests/reflink_test_utils.c
index 925cb41..96cb1da 100755
--- a/programs/reflink_tests/reflink_test_utils.c
+++ b/programs/reflink_tests/reflink_test_utils.c
@@ -461,6 +461,70 @@ int prep_orig_file(char *file_name, unsigned long size, int once)
return 0;
}
+int prep_orig_file_with_pattern(char *file_name, unsigned long size,
+ unsigned long chunk_size, char *pattern_buf,
+ int once)
+{
+ int fd, fdt, ret, o_ret;
+ unsigned long offset = 0, write_size = 0;
+ char tmp_path[PATH_MAX];
+
+ fd = open64(file_name, open_rw_flags, FILE_MODE);
+ if (fd < 0) {
+ o_ret = fd;
+ fd = errno;
+ fprintf(stderr, "create file %s failed:%d:%s\n", file_name, fd,
+ strerror(fd));
+ fd = o_ret;
+ return fd;
+ }
+
+ if (once) {
+
+ while (offset < size) {
+ if ((offset + chunk_size) > size)
+ write_size = size - offset;
+ else
+ write_size = chunk_size;
+
+ ret = write_at(fd, pattern_buf, write_size, offset);
+ if (ret < 0)
+ return ret;
+
+ offset += write_size;
+ }
+ } else {
+ snprintf(tmp_path, PATH_MAX, "%s-tmp-file", file_name);
+ fdt = open64(tmp_path, open_rw_flags, FILE_MODE);
+
+ unlink(tmp_path);
+
+ while (offset < size) {
+
+ if ((offset + chunk_size) > size)
+ write_size = size - offset;
+ else
+ write_size = chunk_size;
+
+ ret = write_at(fd, pattern_buf, write_size, offset);
+ if (ret < 0)
+ return ret;
+
+ ret = write_at(fdt, pattern_buf, write_size, offset);
+ if (ret < 0)
+ return ret;
+
+ offset += write_size;
+ }
+
+ close(fdt);
+
+ }
+
+ close(fd);
+ return 0;
+}
+
int prep_orig_file_dio(char *file_name, unsigned long size)
{
int fd, ret, o_ret, flags;
@@ -1825,3 +1889,42 @@ int semaphore_v(int sem_id)
return 0;
}
+
+int open_file(const char *filename, int flags)
+{
+ int fd, ret, o_ret;
+
+ fd = open64(filename, open_rw_flags, FILE_MODE);
+ if (fd < 0) {
+ o_ret = fd;
+ fd = errno;
+ fprintf(stderr, "open file %s failed:%d:%s\n", filename, fd,
+ strerror(fd));
+ fd = o_ret;
+ return -1;
+ }
+
+ return fd;
+}
+
+
+int punch_hole(int fd, uint64_t start, uint64_t len)
+{
+ int ret;
+ struct ocfs2_space_resv sr;
+
+ memset(&sr, 0, sizeof(sr));
+ sr.l_whence = 0;
+ sr.l_start = start;
+ sr.l_len = len;
+
+ ret = ioctl(fd, OCFS2_IOC_UNRESVSP64, &sr);
+ if (ret == -1) {
+ fprintf(stderr, "ioctl error %d: \"%s\"\n",
+ errno, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+
+}
--
1.5.5
More information about the Ocfs2-test-devel
mailing list