[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