[Ocfs2-test-devel] [PATCH 1/1] Ocfs2-test: Add testcase to ocfs2-test to verify refcount after punching holes.
Tao Ma
tao.ma at oracle.com
Mon Feb 1 01:26:37 PST 2010
sob.
Tristan Ye wrote:
> 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;
> +
> +}
More information about the Ocfs2-test-devel
mailing list