[SCM] Samba Shared Repository - branch master updated
Jeremy Allison
jra at samba.org
Wed Feb 11 19:20:05 MST 2015
The branch, master has been updated
via 177692c torture/ioctl: add test_ioctl_sparse_copy_chunk test
via 048068e torture/ioctl: add sparse_compressed test
via 200bab0 torture/ioctl: extend sparse_hole_dealloc test
via c7f1284 torture/ioctl: add sparse_hole_dealloc test
via af9a99c torture/ioctl: fix check_[zero/pattern]() for len=0
from 618af83 vfs_prealloc: Remove call to gpfs_prealloc
https://git.samba.org/?p=samba.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit 177692c0042558fc5b8812645a7c67769ebade6b
Author: David Disseldorp <ddiss at samba.org>
Date: Mon Feb 9 12:09:35 2015 +0100
torture/ioctl: add test_ioctl_sparse_copy_chunk test
This test copies unallocated and allocated ranges from a sparse file
into a sparse and non-sparse destination file using FSCTL_SRV_COPYCHUNK.
Signed-off-by: David Disseldorp <ddiss at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
Autobuild-User(master): Jeremy Allison <jra at samba.org>
Autobuild-Date(master): Thu Feb 12 03:19:32 CET 2015 on sn-devel-104
commit 048068e83632fa217939afa70c5c3b4213c91bb0
Author: David Disseldorp <ddiss at samba.org>
Date: Mon Feb 9 12:09:34 2015 +0100
torture/ioctl: add sparse_compressed test
This test checks whether a file marked with sparse and compression
attributes is deallocated following FSCTL_SET_ZERO_DATA.
Signed-off-by: David Disseldorp <ddiss at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit 200bab04202210ac1019e1c64857c589d3f89890
Author: David Disseldorp <ddiss at samba.org>
Date: Mon Feb 9 12:09:33 2015 +0100
torture/ioctl: extend sparse_hole_dealloc test
Check whether unwritten extents in a sparse file are allocated.
Signed-off-by: David Disseldorp <ddiss at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit c7f1284f03f5b473d2159e20723c9461964081b2
Author: David Disseldorp <ddiss at samba.org>
Date: Mon Feb 9 12:09:32 2015 +0100
torture/ioctl: add sparse_hole_dealloc test
This test finds the minimum length at which a zeroed range in a sparse
file is deallocated by the underlying filesystem.
It also checks whether zeroed neighbours are merged for deallocation.
Signed-off-by: David Disseldorp <ddiss at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
commit af9a99c35c46f0f82d4cf07b79442257731b966c
Author: David Disseldorp <ddiss at samba.org>
Date: Mon Feb 9 12:09:31 2015 +0100
torture/ioctl: fix check_[zero/pattern]() for len=0
Subtraction currently triggers an underflow.
Signed-off-by: David Disseldorp <ddiss at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
-----------------------------------------------------------------------
Summary of changes:
source4/torture/smb2/ioctl.c | 568 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 567 insertions(+), 1 deletion(-)
Changeset truncated at 500 lines:
diff --git a/source4/torture/smb2/ioctl.c b/source4/torture/smb2/ioctl.c
index 344ff0e..931a013 100644
--- a/source4/torture/smb2/ioctl.c
+++ b/source4/torture/smb2/ioctl.c
@@ -3,7 +3,7 @@
test suite for SMB2 ioctl operations
- Copyright (C) David Disseldorp 2011-2013
+ Copyright (C) David Disseldorp 2011-2015
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -164,6 +164,10 @@ static bool check_pattern(struct torture_context *torture,
struct smb2_read r;
NTSTATUS status;
+ if (len == 0) {
+ return true;
+ }
+
ZERO_STRUCT(r);
r.in.file.handle = h;
r.in.length = len;
@@ -194,6 +198,10 @@ static bool check_zero(struct torture_context *torture,
struct smb2_read r;
NTSTATUS status;
+ if (len == 0) {
+ return true;
+ }
+
ZERO_STRUCT(r);
r.in.file.handle = h;
r.in.length = len;
@@ -3287,6 +3295,558 @@ static bool test_ioctl_sparse_punch(struct torture_context *torture,
}
/*
+ * Find the point at which a zeroed range in a sparse file is deallocated by the
+ * underlying filesystem. NTFS on Windows Server 2012 deallocates chunks in 64k
+ * increments. Also check whether zeroed neighbours are merged for deallocation.
+ */
+static bool test_ioctl_sparse_hole_dealloc(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ uint64_t file_size;
+ uint64_t hlen;
+ uint64_t dealloc_chunk_len = 0;
+ struct file_alloced_range_buf *far_rsp = NULL;
+ uint64_t far_count = 0;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file 1");
+
+ /* check for FS sparse file */
+ status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &fh,
+ &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ /* set sparse */
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ file_size = 1024 * 1024;
+
+ ok = write_pattern(torture, tree, tmp_ctx, fh,
+ 0, /* off */
+ file_size, /* len */
+ 0); /* pattern offset */
+ torture_assert(torture, ok, "write pattern");
+
+ /* check allocated ranges, should be fully allocated */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ file_size, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected far off");
+ torture_assert_u64_equal(torture, far_rsp[0].len, file_size,
+ "unexpected far len");
+
+ /* punch holes in sizes of 1k increments */
+ for (hlen = 0; hlen <= file_size; hlen += 4096) {
+
+ /* punch a hole from zero to the current increment */
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ hlen); /* beyond_final_zero */
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+
+ /* ensure hole is zeroed, and pattern is consistent */
+ ok = check_zero(torture, tree, tmp_ctx, fh, 0, hlen);
+ torture_assert(torture, ok, "sparse zeroed range");
+
+ ok = check_pattern(torture, tree, tmp_ctx, fh, hlen,
+ file_size - hlen, hlen);
+ torture_assert(torture, ok, "allocated pattern range");
+
+ /* Check allocated ranges, hole might have been deallocated */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ file_size, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES");
+ if ((hlen == file_size) && (far_count == 0)) {
+ /* hole covered entire file, deallocation occurred */
+ dealloc_chunk_len = file_size;
+ break;
+ }
+
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ if (far_rsp[0].file_off != 0) {
+ /*
+ * We now know the hole punch length needed to trigger a
+ * deallocation on this FS...
+ */
+ dealloc_chunk_len = hlen;
+ torture_comment(torture, "hole punch %lu at 0 resulted in "
+ "deallocation of %lu at 0\n", hlen,
+ far_rsp[0].file_off);
+ torture_assert_u64_equal(torture,
+ file_size - far_rsp[0].len,
+ far_rsp[0].file_off,
+ "invalid alloced range");
+ break;
+ }
+ }
+
+ if (dealloc_chunk_len == 0) {
+ torture_comment(torture, "strange, this FS never deallocates"
+ "zeroed ranges in sparse files\n");
+ return true; /* FS specific, not a failure */
+ }
+
+ /*
+ * Check whether deallocation occurs when the (now known)
+ * deallocation chunk size is punched via two ZERO_DATA requests.
+ * I.e. Does the FS merge the two ranges and deallocate the chunk?
+ * NTFS on Windows Server 2012 does not.
+ */
+ ok = write_pattern(torture, tree, tmp_ctx, fh,
+ 0, /* off */
+ file_size, /* len */
+ 0); /* pattern offset */
+ torture_assert(torture, ok, "write pattern");
+
+ /* divide dealloc chunk size by two, to use as punch length */
+ hlen = dealloc_chunk_len >> 1;
+
+ /*
+ * /half of dealloc chunk size 1M\
+ * | |
+ * /offset 0 | /dealloc chunk size |
+ * |------------------ |-------------------|-------------------|
+ * | zeroed, 1st punch | zeroed, 2nd punch | existing pattern |
+ */
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ hlen); /* beyond final zero */
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ hlen, /* off */
+ dealloc_chunk_len); /* beyond final */
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+
+ /* ensure holes are zeroed, and pattern is consistent */
+ ok = check_zero(torture, tree, tmp_ctx, fh, 0, dealloc_chunk_len);
+ torture_assert(torture, ok, "sparse zeroed range");
+
+ ok = check_pattern(torture, tree, tmp_ctx, fh, dealloc_chunk_len,
+ file_size - dealloc_chunk_len, dealloc_chunk_len);
+ torture_assert(torture, ok, "allocated pattern range");
+
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ file_size, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+
+ if ((far_count == 0) && (dealloc_chunk_len == file_size)) {
+ torture_comment(torture, "holes merged for deallocation of "
+ "full file\n");
+ return true;
+ }
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ if (far_rsp[0].file_off == dealloc_chunk_len) {
+ torture_comment(torture, "holes merged for deallocation of "
+ "%lu chunk\n", dealloc_chunk_len);
+ torture_assert_u64_equal(torture,
+ file_size - far_rsp[0].len,
+ far_rsp[0].file_off,
+ "invalid alloced range");
+ } else {
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected deallocation");
+ torture_comment(torture, "holes not merged for deallocation\n");
+ }
+
+ smb2_util_close(tree, fh);
+
+ /*
+ * Check whether an unwritten range is allocated when a sparse file is
+ * written to at an offset past the dealloc chunk size:
+ *
+ * /dealloc chunk size
+ * /offset 0 |
+ * |------------------ |-------------------|
+ * | unwritten | pattern |
+ */
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file 1");
+
+ /* set sparse */
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ ok = write_pattern(torture, tree, tmp_ctx, fh,
+ dealloc_chunk_len, /* off */
+ 1024, /* len */
+ dealloc_chunk_len); /* pattern offset */
+ torture_assert(torture, ok, "write pattern");
+
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ dealloc_chunk_len + 1024, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ if (far_rsp[0].file_off == 0) {
+ torture_assert_u64_equal(torture, far_rsp[0].len,
+ dealloc_chunk_len + 1024,
+ "unexpected far len");
+ torture_comment(torture, "unwritten range fully allocated\n");
+ } else {
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, dealloc_chunk_len,
+ "unexpected deallocation");
+ torture_assert_u64_equal(torture, far_rsp[0].len, 1024,
+ "unexpected far len");
+ torture_comment(torture, "unwritten range not allocated\n");
+ }
+
+ ok = check_zero(torture, tree, tmp_ctx, fh, 0, dealloc_chunk_len);
+ torture_assert(torture, ok, "sparse zeroed range");
+
+ ok = check_pattern(torture, tree, tmp_ctx, fh, dealloc_chunk_len,
+ 1024, dealloc_chunk_len);
+ torture_assert(torture, ok, "allocated pattern range");
+
+ /* unsparse, should now be fully allocated */
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, false);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ dealloc_chunk_len + 1024, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected deallocation");
+ torture_assert_u64_equal(torture, far_rsp[0].len,
+ dealloc_chunk_len + 1024,
+ "unexpected far len");
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/* check whether a file with compression and sparse attrs can be deallocated */
+static bool test_ioctl_sparse_compressed(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle fh;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ uint64_t file_size = 1024 * 1024;
+ struct file_alloced_range_buf *far_rsp = NULL;
+ uint64_t far_count = 0;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &fh, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file 1");
+
+ /* check for FS sparse file and compression support */
+ status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &fh,
+ &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ status = test_ioctl_compress_fs_supported(torture, tree, tmp_ctx, &fh,
+ &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ if (!ok) {
+ smb2_util_close(tree, fh);
+ torture_skip(torture, "FS compression not supported\n");
+ }
+
+ /* set compression and write some data */
+ status = test_ioctl_compress_set(torture, tmp_ctx, tree, fh,
+ COMPRESSION_FORMAT_DEFAULT);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_COMPRESSION");
+
+ ok = write_pattern(torture, tree, tmp_ctx, fh,
+ 0, /* off */
+ file_size, /* len */
+ 0); /* pattern offset */
+ torture_assert(torture, ok, "write pattern");
+
+ /* set sparse - now sparse and compressed */
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, fh, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ /* check allocated ranges, should be fully alloced */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ file_size, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected far off");
+ torture_assert_u64_equal(torture, far_rsp[0].len, file_size,
+ "unexpected far len");
+
+ /* zero (hole-punch) all data, with sparse and compressed attrs */
+ status = test_ioctl_zdata_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ file_size); /* beyond_final_zero */
+ torture_assert_ntstatus_ok(torture, status, "zero_data");
+
+ /*
+ * Windows Server 2012 still deallocates a zeroed range when a sparse
+ * file carries the compression attribute.
+ */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, fh,
+ 0, /* off */
+ file_size, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ if (far_count == 0) {
+ torture_comment(torture, "sparse & compressed file "
+ "deallocated after hole-punch\n");
+ } else {
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, 0,
+ "unexpected far off");
+ torture_assert_u64_equal(torture, far_rsp[0].len, file_size,
+ "unexpected far len");
+ torture_comment(torture, "sparse & compressed file fully "
+ "allocated after hole-punch\n");
+ }
+
+ smb2_util_close(tree, fh);
+ talloc_free(tmp_ctx);
+ return true;
+}
+
+/*
+ * Create a sparse file, then attempt to copy unallocated and allocated ranges
+ * into a target file using FSCTL_SRV_COPYCHUNK.
+ */
+static bool test_ioctl_sparse_copy_chunk(struct torture_context *torture,
+ struct smb2_tree *tree)
+{
+ struct smb2_handle src_h;
+ struct smb2_handle dest_h;
+ NTSTATUS status;
+ TALLOC_CTX *tmp_ctx = talloc_new(tree);
+ bool ok;
+ uint64_t dealloc_chunk_len = 64 * 1024; /* Windows 2012 */
+ struct file_alloced_range_buf *far_rsp = NULL;
+ uint64_t far_count = 0;
+ union smb_ioctl ioctl;
+ struct srv_copychunk_copy cc_copy;
+ struct srv_copychunk_rsp cc_rsp;
+ enum ndr_err_code ndr_ret;
+
+ ok = test_setup_create_fill(torture, tree, tmp_ctx,
+ FNAME, &src_h, 0, SEC_RIGHTS_FILE_ALL,
+ FILE_ATTRIBUTE_NORMAL);
+ torture_assert(torture, ok, "setup file");
+
+ /* check for FS sparse file support */
+ status = test_ioctl_sparse_fs_supported(torture, tree, tmp_ctx, &src_h,
+ &ok);
+ torture_assert_ntstatus_ok(torture, status, "SMB2_GETINFO_FS");
+ smb2_util_close(tree, src_h);
+ if (!ok) {
+ torture_skip(torture, "Sparse files not supported\n");
+ }
+
+ ok = test_setup_copy_chunk(torture, tree, tmp_ctx,
+ 1, /* chunks */
+ &src_h, 0, /* src file */
+ SEC_RIGHTS_FILE_ALL,
+ &dest_h, 0, /* dest file */
+ SEC_RIGHTS_FILE_ALL,
+ &cc_copy,
+ &ioctl);
+ torture_assert(torture, ok, "setup copy chunk error");
+
+ /* set sparse */
+ status = test_ioctl_sparse_req(torture, tmp_ctx, tree, src_h, true);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SET_SPARSE");
+
+ /* start after dealloc_chunk_len, to create an unwritten sparse range */
+ ok = write_pattern(torture, tree, tmp_ctx, src_h,
+ dealloc_chunk_len, /* off */
+ 1024, /* len */
+ dealloc_chunk_len); /* pattern offset */
+ torture_assert(torture, ok, "write pattern");
+
+ /* Skip test if 64k chunk is allocated - FS specific */
+ status = test_ioctl_qar_req(torture, tmp_ctx, tree, src_h,
+ 0, /* off */
+ dealloc_chunk_len + 1024, /* len */
+ &far_rsp,
+ &far_count);
+ torture_assert_ntstatus_ok(torture, status,
+ "FSCTL_QUERY_ALLOCATED_RANGES req failed");
+ torture_assert_u64_equal(torture, far_count, 1,
+ "unexpected response len");
+ if (far_rsp[0].file_off == 0) {
+ torture_skip(torture, "unwritten range fully allocated\n");
+ }
+
+ torture_assert_u64_equal(torture, far_rsp[0].file_off, dealloc_chunk_len,
+ "unexpected allocation");
+ torture_assert_u64_equal(torture, far_rsp[0].len, 1024,
+ "unexpected far len");
+
+ /* copy-chunk unallocated + written ranges into non-sparse dest */
+
+ cc_copy.chunks[0].source_off = 0;
+ cc_copy.chunks[0].target_off = 0;
+ cc_copy.chunks[0].length = dealloc_chunk_len + 1024;
+
+ ndr_ret = ndr_push_struct_blob(&ioctl.smb2.in.out, tmp_ctx,
+ &cc_copy,
+ (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_push_srv_copychunk_copy");
+
+ status = smb2_ioctl(tree, tmp_ctx, &ioctl.smb2);
+ torture_assert_ntstatus_ok(torture, status, "FSCTL_SRV_COPYCHUNK");
+
+ ndr_ret = ndr_pull_struct_blob(&ioctl.smb2.out.out, tmp_ctx,
+ &cc_rsp,
+ (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
+ torture_assert_ndr_success(torture, ndr_ret,
+ "ndr_pull_srv_copychunk_rsp");
+
+ ok = check_copy_chunk_rsp(torture, &cc_rsp,
+ 1, /* chunks written */
+ 0, /* chunk bytes unsuccessfully written */
+ dealloc_chunk_len + 1024); /* bytes written */
+ torture_assert(torture, ok, "bad copy chunk response data");
--
Samba Shared Repository
More information about the samba-cvs
mailing list