The branch, master has been updated via 47f5aac... s4/torture: add test for zero byte read contention with byte range locks via 995b480... s4/libcli: add define for exclusive lock mode via b4c72e4... s4/torture: fix >80 column spacing issues via 0c42d65... s4/torture: add delete-on-close test for directories from a246310... parent_sd can never be null in this function, so don't check for it.
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 47f5aac39d4a81f37ae0d8656ac75d985b24053b Author: Steven Danneman <steven.danne...@isilon.com> Date: Thu Dec 3 18:50:33 2009 -0800 s4/torture: add test for zero byte read contention with byte range locks commit 995b4800f820a9d4415026e677aaad8de7668b92 Author: Steven Danneman <steven.danne...@isilon.com> Date: Thu Dec 3 18:32:56 2009 -0800 s4/libcli: add define for exclusive lock mode commit b4c72e44a83157768ae991e72d824f56a381eab6 Author: Steven Danneman <steven.danne...@isilon.com> Date: Thu Dec 3 19:32:53 2009 -0800 s4/torture: fix >80 column spacing issues commit 0c42d65d7cbc24b96f0e9ec700d32da860060174 Author: Aravind Srinivasan <aravind.sriniva...@isilon.com> Date: Tue Nov 17 12:28:34 2009 -0800 s4/torture: add delete-on-close test for directories This test opens a directory with delete on close, opens it again, and checks to make sure that the second open returned with NT_STATUS_DELETE_PENDING. ----------------------------------------------------------------------- Summary of changes: source4/libcli/raw/smb.h | 1 + source4/selftest/knownfail | 2 + source4/torture/basic/delete.c | 63 ++++++++++++++++ source4/torture/raw/lock.c | 162 +++++++++++++++++++++++++++++++++++++++- source4/torture/smb2/lock.c | 132 +++++++++++++++++++++++++++++++-- 5 files changed, 350 insertions(+), 10 deletions(-) Changeset truncated at 500 lines: diff --git a/source4/libcli/raw/smb.h b/source4/libcli/raw/smb.h index 4fbf76f..349705d 100644 --- a/source4/libcli/raw/smb.h +++ b/source4/libcli/raw/smb.h @@ -559,6 +559,7 @@ #define UID_FIELD_INVALID 0 /* Lock types. */ +#define LOCKING_ANDX_EXCLUSIVE_LOCK 0x00 #define LOCKING_ANDX_SHARED_LOCK 0x01 #define LOCKING_ANDX_OPLOCK_RELEASE 0x02 #define LOCKING_ANDX_CHANGE_LOCKTYPE 0x04 diff --git a/source4/selftest/knownfail b/source4/selftest/knownfail index b9d40f2..ef3c10c 100644 --- a/source4/selftest/knownfail +++ b/source4/selftest/knownfail @@ -67,3 +67,5 @@ samba4.raw.lock.*.async # bug 6960 samba4.smb2.lock.*.MULTIPLE-UNLOCK # bug 6959 samba4.raw.sfileinfo.*.END-OF-FILE # bug 6962 samba4.raw.oplock.*.BATCH22 # bug 6963 +samba4.raw.lock.*.zerobyteread # bug 6974 +samba4.smb2.lock.*.ZEROBYTEREAD # bug 6974 diff --git a/source4/torture/basic/delete.c b/source4/torture/basic/delete.c index 0f7c939..22d9219 100644 --- a/source4/torture/basic/delete.c +++ b/source4/torture/basic/delete.c @@ -1515,9 +1515,71 @@ static bool deltest22(struct torture_context *tctx) CHECK_STATUS(cli1, NT_STATUS_DELETE_PENDING); + smbcli_close(cli1->tree, dnum2); + CHECK_STATUS(cli1, NT_STATUS_OK); + return correct; } +/* Test 23 - Second directory open fails when delete is pending. */ +static bool deltest23(struct torture_context *tctx, + struct smbcli_state *cli1, + struct smbcli_state *cli2) +{ + int dnum1 = -1; + int dnum2 = -1; + bool correct = true; + NTSTATUS status; + + del_clean_area(cli1, cli2); + + /* Test 23 -- Basic delete on close for directories. */ + + /* Open a directory */ + dnum1 = smbcli_nt_create_full(cli1->tree, dname, 0, + SEC_FILE_READ_DATA| + SEC_FILE_WRITE_DATA| + SEC_STD_DELETE, + FILE_ATTRIBUTE_DIRECTORY, + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE| + NTCREATEX_SHARE_ACCESS_DELETE, + NTCREATEX_DISP_CREATE, + NTCREATEX_OPTIONS_DIRECTORY, 0); + + torture_assert(tctx, dnum1 != -1, talloc_asprintf(tctx, + "open of %s failed: %s!", + dname, smbcli_errstr(cli1->tree))); + + correct &= check_delete_on_close(tctx, cli1, dnum1, dname, false, + __location__); + + /* Set delete on close */ + status = smbcli_nt_delete_on_close(cli1->tree, dnum1, true); + + /* Attempt opening the directory again. It should fail. */ + dnum2 = smbcli_nt_create_full(cli1->tree, dname, 0, + SEC_FILE_READ_DATA| + SEC_FILE_WRITE_DATA| + SEC_STD_DELETE, + FILE_ATTRIBUTE_DIRECTORY, + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE| + NTCREATEX_SHARE_ACCESS_DELETE, + NTCREATEX_DISP_OPEN, + NTCREATEX_OPTIONS_DIRECTORY, 0); + + torture_assert(tctx, dnum2 == -1, talloc_asprintf(tctx, + "open of %s succeeded: %s. It should have failed " + "with NT_STATUS_DELETE_PENDING", + dname, smbcli_errstr(cli1->tree))); + + torture_assert_ntstatus_equal(tctx, smbcli_nt_error(cli1->tree), + NT_STATUS_DELETE_PENDING, "smbcli_open failed"); + + return true; +} + /* Test delete on close semantics. */ @@ -1551,6 +1613,7 @@ struct torture_suite *torture_test_delete(void) torture_suite_add_2smb_test(suite, "deltest20b", deltest20b); torture_suite_add_simple_test(suite, "deltest21", deltest21); torture_suite_add_simple_test(suite, "deltest22", deltest22); + torture_suite_add_2smb_test(suite, "deltest23", deltest23); return suite; } diff --git a/source4/torture/raw/lock.c b/source4/torture/raw/lock.c index 6871ed3..34b05b7 100644 --- a/source4/torture/raw/lock.c +++ b/source4/torture/raw/lock.c @@ -71,9 +71,10 @@ #define TARGET_IS_W2K8(_tctx) (torture_setting_bool(_tctx, "w2k8", false)) #define TARGET_IS_WIN7(_tctx) (torture_setting_bool(_tctx, "win7", false)) -#define TARGET_IS_WINDOWS(_tctx) ((torture_setting_bool(_tctx, "w2k8", false)) || \ - (torture_setting_bool(_tctx, "win7", false)) || \ - (torture_setting_bool(_tctx, "w2k3", false))) +#define TARGET_IS_WINDOWS(_tctx) \ + ((torture_setting_bool(_tctx, "w2k3", false)) || \ + (torture_setting_bool(_tctx, "w2k8", false)) || \ + (torture_setting_bool(_tctx, "win7", false))) #define TARGET_IS_SAMBA3(_tctx) (torture_setting_bool(_tctx, "samba3", false)) #define TARGET_IS_SAMBA4(_tctx) (torture_setting_bool(_tctx, "samba4", false)) @@ -1996,7 +1997,158 @@ done: return ret; } -/* +/** + * Test how 0-byte read requests contend with byte range locks + */ +static bool test_zerobyteread(struct torture_context *tctx, + struct smbcli_state *cli) +{ + union smb_lock io; + union smb_read rd; + NTSTATUS status; + bool ret = true; + int fnum1, fnum2; + const char *fname = BASEDIR "\\zerobyteread.txt"; + struct smb_lock_entry lock1; + uint8_t c = 1; + + if (!torture_setup_dir(cli, BASEDIR)) { + return false; + } + + io.generic.level = RAW_LOCK_LOCKX; + + fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + torture_assert(tctx,(fnum1 != -1), talloc_asprintf(tctx, + "Failed to create %s - %s\n", + fname, smbcli_errstr(cli->tree))); + + fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + torture_assert(tctx,(fnum2 != -1), talloc_asprintf(tctx, + "Failed to create %s - %s\n", + fname, smbcli_errstr(cli->tree))); + + /* Setup initial parameters */ + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.timeout = 0; + + lock1.pid = cli->session->pid; + lock1.offset = 0; + lock1.count = 10; + + ZERO_STRUCT(rd); + rd.readx.level = RAW_READ_READX; + + torture_comment(tctx, "Testing zero byte read on lock range:\n"); + + /* Take an exclusive lock */ + torture_comment(tctx, " taking exclusive lock.\n"); + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK; + io.lockx.in.file.fnum = fnum1; + io.lockx.in.locks = &lock1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Try a zero byte read */ + torture_comment(tctx, " reading 0 bytes.\n"); + rd.readx.in.file.fnum = fnum2; + rd.readx.in.offset = 5; + rd.readx.in.mincnt = 0; + rd.readx.in.maxcnt = 0; + rd.readx.in.remaining = 0; + rd.readx.in.read_for_execute = false; + rd.readx.out.data = &c; + status = smb_raw_read(cli->tree, &rd); + torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done, + "zero byte read did not return 0 bytes"); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Unlock lock */ + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK; + io.lockx.in.file.fnum = fnum1; + io.lockx.in.locks = &lock1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + torture_comment(tctx, "Testing zero byte read on zero byte lock " + "range:\n"); + + /* Take an exclusive lock */ + torture_comment(tctx, " taking exclusive 0-byte lock.\n"); + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK; + io.lockx.in.file.fnum = fnum1; + io.lockx.in.locks = &lock1; + lock1.offset = 5; + lock1.count = 0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Try a zero byte read before the lock */ + torture_comment(tctx, " reading 0 bytes before the lock.\n"); + rd.readx.in.file.fnum = fnum2; + rd.readx.in.offset = 4; + rd.readx.in.mincnt = 0; + rd.readx.in.maxcnt = 0; + rd.readx.in.remaining = 0; + rd.readx.in.read_for_execute = false; + rd.readx.out.data = &c; + status = smb_raw_read(cli->tree, &rd); + torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done, + "zero byte read did not return 0 bytes"); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Try a zero byte read on the lock */ + torture_comment(tctx, " reading 0 bytes on the lock.\n"); + rd.readx.in.file.fnum = fnum2; + rd.readx.in.offset = 5; + rd.readx.in.mincnt = 0; + rd.readx.in.maxcnt = 0; + rd.readx.in.remaining = 0; + rd.readx.in.read_for_execute = false; + rd.readx.out.data = &c; + status = smb_raw_read(cli->tree, &rd); + torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done, + "zero byte read did not return 0 bytes"); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Try a zero byte read after the lock */ + torture_comment(tctx, " reading 0 bytes after the lock.\n"); + rd.readx.in.file.fnum = fnum2; + rd.readx.in.offset = 6; + rd.readx.in.mincnt = 0; + rd.readx.in.maxcnt = 0; + rd.readx.in.remaining = 0; + rd.readx.in.read_for_execute = false; + rd.readx.out.data = &c; + status = smb_raw_read(cli->tree, &rd); + torture_assert_int_equal_goto(tctx, rd.readx.out.nread, 0, ret, done, + "zero byte read did not return 0 bytes"); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Unlock lock */ + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK; + io.lockx.in.file.fnum = fnum1; + io.lockx.in.locks = &lock1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + +done: + smbcli_close(cli->tree, fnum1); + smbcli_close(cli->tree, fnum2); + smb_raw_exit(cli->session); + smbcli_deltree(cli->tree, BASEDIR); + return ret; +} + +/* basic testing of lock calls */ struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx) @@ -2016,6 +2168,8 @@ struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx) test_multiple_unlock); torture_suite_add_1smb_test(suite, "zerobytelocks", test_zerobytelocks); + torture_suite_add_1smb_test(suite, "zerobyteread", + test_zerobyteread); return suite; } diff --git a/source4/torture/smb2/lock.c b/source4/torture/smb2/lock.c index ba97a54..508358e 100644 --- a/source4/torture/smb2/lock.c +++ b/source4/torture/smb2/lock.c @@ -1453,6 +1453,124 @@ done: return ret; } +static bool test_zerobyteread(struct torture_context *torture, + struct smb2_tree *tree) +{ + NTSTATUS status; + bool ret = true; + struct smb2_handle h, h2; + uint8_t buf[200]; + struct smb2_lock lck; + struct smb2_lock_element el[1]; + struct smb2_read rd; + + const char *fname = BASEDIR "\\zerobyteread.txt"; + + status = torture_smb2_testdir(tree, BASEDIR, &h); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, h); + + status = torture_smb2_testfile(tree, fname, &h); + CHECK_STATUS(status, NT_STATUS_OK); + + ZERO_STRUCT(buf); + status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf)); + CHECK_STATUS(status, NT_STATUS_OK); + + status = torture_smb2_testfile(tree, fname, &h2); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Setup initial parameters */ + lck.in.locks = el; + lck.in.lock_count = 0x0001; + lck.in.lock_sequence = 0x00000000; + lck.in.file.handle = h; + + ZERO_STRUCT(rd); + rd.in.file.handle = h2; + + torture_comment(torture, "Testing zero byte read on lock range:\n"); + + /* Take an exclusive lock */ + torture_comment(torture, " taking exclusive lock.\n"); + el[0].offset = 0; + el[0].length = 10; + el[0].reserved = 0x00000000; + el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE | + SMB2_LOCK_FLAG_FAIL_IMMEDIATELY; + status = smb2_lock(tree, &lck); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_VALUE(lck.out.reserved, 0); + + /* Try a zero byte read */ + torture_comment(torture, " reading 0 bytes.\n"); + rd.in.offset = 5; + rd.in.length = 0; + status = smb2_read(tree, tree, &rd); + torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done, + "zero byte read did not return 0 bytes"); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Unlock lock */ + el[0].flags = SMB2_LOCK_FLAG_UNLOCK; + status = smb2_lock(tree, &lck); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_VALUE(lck.out.reserved, 0); + + torture_comment(torture, "Testing zero byte read on zero byte lock " + "range:\n"); + + /* Take an exclusive lock */ + torture_comment(torture, " taking exclusive 0-byte lock.\n"); + el[0].offset = 5; + el[0].length = 0; + el[0].reserved = 0x00000000; + el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE | + SMB2_LOCK_FLAG_FAIL_IMMEDIATELY; + status = smb2_lock(tree, &lck); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_VALUE(lck.out.reserved, 0); + + /* Try a zero byte read before the lock */ + torture_comment(torture, " reading 0 bytes before the lock.\n"); + rd.in.offset = 4; + rd.in.length = 0; + status = smb2_read(tree, tree, &rd); + torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done, + "zero byte read did not return 0 bytes"); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Try a zero byte read on the lock */ + torture_comment(torture, " reading 0 bytes on the lock.\n"); + rd.in.offset = 5; + rd.in.length = 0; + status = smb2_read(tree, tree, &rd); + torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done, + "zero byte read did not return 0 bytes"); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Try a zero byte read after the lock */ + torture_comment(torture, " reading 0 bytes after the lock.\n"); + rd.in.offset = 6; + rd.in.length = 0; + status = smb2_read(tree, tree, &rd); + torture_assert_int_equal_goto(torture, rd.out.data.length, 0, ret, done, + "zero byte read did not return 0 bytes"); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Unlock lock */ + el[0].flags = SMB2_LOCK_FLAG_UNLOCK; + status = smb2_lock(tree, &lck); + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_VALUE(lck.out.reserved, 0); + +done: + smb2_util_close(tree, h2); + smb2_util_close(tree, h); + smb2_deltree(tree, BASEDIR); + return ret; +} + static bool test_unlock(struct torture_context *torture, struct smb2_tree *tree) { @@ -2626,8 +2744,8 @@ static bool test_overlap(struct torture_context *torture, NT_STATUS_IS_OK(torture_smb2_testfile(tree, fname, &h)) && NT_STATUS_IS_OK(smb2cli_lock(tree, h, 7, 1, true)); EXPECTED(ret, true); - torture_comment(torture, "the server %s have the NT byte range lock bug\n", - !ret?"does":"doesn't"); + torture_comment(torture, "the server %s have the NT byte range lock " + "bug\n", !ret?"does":"doesn't"); done: smb2_util_close(tree2, h3); @@ -2694,8 +2812,8 @@ static bool test_truncate(struct torture_context *torture, CHECK_STATUS(status, NT_STATUS_OK); /* On second handle open the file with OVERWRITE disposition */ - torture_comment(torture, " overwrite disposition is allowed on a locked " - "file.\n"); + torture_comment(torture, " overwrite disposition is allowed on a " + "locked file.\n"); io.in.create_disposition = NTCREATEX_DISP_OVERWRITE; status = smb2_create(tree, tree, &io); @@ -2704,8 +2822,8 @@ static bool test_truncate(struct torture_context *torture, smb2_util_close(tree, h2); /* On second handle open the file with SUPERSEDE disposition */ - torture_comment(torture, " supersede disposition is allowed on a locked " - "file.\n"); + torture_comment(torture, " supersede disposition is allowed on a " + "locked file.\n"); io.in.create_disposition = NTCREATEX_DISP_SUPERSEDE; status = smb2_create(tree, tree, &io); @@ -2750,6 +2868,8 @@ struct torture_suite *torture_smb2_lock_init(void) torture_suite_add_1smb2_test(suite, "ERRORCODE", test_errorcode); torture_suite_add_1smb2_test(suite, "ZEROBYTELENGTH", test_zerobytelength); + torture_suite_add_1smb2_test(suite, "ZEROBYTEREAD", + test_zerobyteread); torture_suite_add_1smb2_test(suite, "UNLOCK", test_unlock); torture_suite_add_1smb2_test(suite, "MULTIPLE-UNLOCK", test_multiple_unlock); -- Samba Shared Repository