s4 torture: Add a new RAW-OPLOCK test: BATCH26
authorTim Prouty <tprouty@samba.org>
Thu, 3 Dec 2009 21:46:11 +0000 (13:46 -0800)
committerTim Prouty <tprouty@samba.org>
Fri, 4 Dec 2009 02:54:52 +0000 (18:54 -0800)
Try a rename with a wide-open share mode on an already open file
and the there is still share mode contention.  For the reason why
see:

http://social.msdn.microsoft.com/Forums/en-US/os_fileservices/thread/3ca14dc9-da1f-4786-a8f7-a86e9903db0c

Msft's anser:

   After further review, The reason for server to fail with sharing
   violation is that the windows server that executes a path-based
   rename request opens the file for DELETE access, but only with
   FILE_SHARED_READ as ShareAccess .  Therefore, the existing
   open(frame 76), which has shared read/write/delete , is compatible
   with the Windows servers access mode (DELETE), but Windows servers
   open is not compatible with access mode in existing open.

   Note that it is correct to state that the logic in Windows server
   could have been written to allow shared read/write/delete in which
   case it would succeed as you mention. The behavior here is
   historical based on the existing implementation.

source4/torture/raw/oplock.c

index d35445c7eb94c95021f3c8bea8d7fa9de89177bd..78987e312170437f042f8c858cd53e4a5e2c9268 100644 (file)
@@ -2969,6 +2969,113 @@ done:
        return ret;
 }
 
+/**
+ * Similar to batch17/18, but test with open share mode rather than
+ * share_none.
+ */
+static bool test_raw_oplock_batch26(struct torture_context *tctx,
+    struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+       const char *fname1 = BASEDIR "\\test_batch26_1.dat";
+       const char *fname2 = BASEDIR "\\test_batch26_2.dat";
+       NTSTATUS status;
+       bool ret = true;
+       union smb_open io;
+       union smb_rename rn;
+       uint16_t fnum=0;
+
+       if (!torture_setup_dir(cli1, BASEDIR)) {
+               return false;
+       }
+
+       /* cleanup */
+       smbcli_unlink(cli1->tree, fname1);
+       smbcli_unlink(cli1->tree, fname2);
+
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given,
+           cli1->tree);
+
+       /*
+         base ntcreatex parms
+       */
+       io.generic.level = RAW_OPEN_NTCREATEX;
+       io.ntcreatex.in.root_fid.fnum = 0;
+       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+       io.ntcreatex.in.alloc_size = 0;
+       io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+           NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       io.ntcreatex.in.create_options = 0;
+       io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       io.ntcreatex.in.security_flags = 0;
+       io.ntcreatex.in.fname = fname1;
+
+       torture_comment(tctx, "BATCH26: open a file with an batch oplock "
+           "(share mode: none)\n");
+
+       ZERO_STRUCT(break_info);
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+               NTCREATEX_FLAGS_REQUEST_OPLOCK |
+               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+
+
+       status = smb_raw_open(cli1->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+       torture_comment(tctx, "rename should trigger a break\n");
+       ZERO_STRUCT(rn);
+       rn.generic.level = RAW_RENAME_RENAME;
+       rn.rename.in.pattern1 = fname1;
+       rn.rename.in.pattern2 = fname2;
+       rn.rename.in.attrib = 0;
+
+       torture_comment(tctx, "trying rename while first file open\n");
+       status = smb_raw_rename(cli2->tree, &rn);
+       CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+
+       torture_wait_for_oplock_break(tctx);
+       CHECK_VAL(break_info.count, 1);
+       CHECK_VAL(break_info.failures, 0);
+       CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+
+       /* Close and reopen with batch again. */
+       smbcli_close(cli1->tree, fnum);
+       ZERO_STRUCT(break_info);
+
+       status = smb_raw_open(cli1->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+       /* Now try ntrename. */
+       torture_comment(tctx, "ntrename should trigger a break\n");
+       ZERO_STRUCT(rn);
+       rn.generic.level = RAW_RENAME_NTRENAME;
+       rn.ntrename.in.attrib   = 0;
+       rn.ntrename.in.flags    = RENAME_FLAG_RENAME;
+       rn.ntrename.in.old_name = fname1;
+       rn.ntrename.in.new_name = fname2;
+       torture_comment(tctx, "trying rename while first file open\n");
+       status = smb_raw_rename(cli2->tree, &rn);
+       CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+
+       torture_wait_for_oplock_break(tctx);
+       CHECK_VAL(break_info.count, 1);
+       CHECK_VAL(break_info.failures, 0);
+       CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+
+       smbcli_close(cli1->tree, fnum);
+
+done:
+       smb_raw_exit(cli1->session);
+       smb_raw_exit(cli2->session);
+       smbcli_deltree(cli1->tree, BASEDIR);
+       return ret;
+}
+
 /* Test how oplocks work on streams. */
 static bool test_raw_oplock_stream1(struct torture_context *tctx,
                                    struct smbcli_state *cli1,
@@ -3557,6 +3664,7 @@ struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx)
        torture_suite_add_2smb_test(suite, "BATCH23", test_raw_oplock_batch23);
        torture_suite_add_2smb_test(suite, "BATCH24", test_raw_oplock_batch24);
        torture_suite_add_2smb_test(suite, "BATCH25", test_raw_oplock_batch25);
+       torture_suite_add_2smb_test(suite, "BATCH26", test_raw_oplock_batch26);
        torture_suite_add_2smb_test(suite, "STREAM1", test_raw_oplock_stream1);
        torture_suite_add_1smb_test(suite, "DOC1", test_raw_oplock_doc);
        torture_suite_add_2smb_test(suite, "BRL1", test_raw_oplock_brl1);