Sometimes you need an smbtorture test that handles multiple connections to Samba

Richard Sharpe realrichardsharpe at gmail.com
Wed Feb 5 10:50:48 MST 2014


+++ /source4/torture/smb2/notify.c
@@ -2054,6 +2054,170 @@
        return ret;
 }

+#define WAIT_FOR_ASYNC_RESPONSE(req) \
+        while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \
+                if (tevent_loop_once(torture->ev) != 0) { \
+                        break; \
+                } \
+        }
+
+static bool test_multiple_change_notify(struct torture_context *torture,
+                                        int max_conns,
+                                        struct smb2_tree **tree)
+{
+
+       bool ret = true;
+       NTSTATUS status;
+       struct smb2_handle *dh = NULL;
+       struct smb2_handle *dirh = NULL;
+       struct smb2_notify *notify = NULL;
+       struct smb2_request **req = NULL;
+       struct smb2_find *find = NULL;
+       struct smb2_request **find_req = NULL;
+       struct smb2_create io;
+
+       int i, complete = 0, find_complete = 0;
+
+       notify   = talloc_array(torture, struct smb2_notify, max_conns);
+       dh       = talloc_array(torture, struct smb2_handle, max_conns);
+       dirh     = talloc_array(torture, struct smb2_handle, max_conns);
+       req      = talloc_array(torture, struct smb2_request*, max_conns);
+       find     = talloc_array(torture, struct smb2_find, max_conns);
+       find_req = talloc_array(torture, struct smb2_request*, max_conns);
+
+       if (!notify || !dh || !dirh || !req || !find || !find_req) {
+               torture_comment(torture, "Memory allocation failure\n");
+               return false;
+       }
+
+       /*
+         * Create the target directory and some files ...
+        */
+       smb2_util_mkdir(tree[0], BASEDIR);
+       smb2_util_unlink(tree[0],BASEDIR "\\some-file.txt");
+       /*
+         * Send a NOTIFY request on all but the last connection ...
+        */
+       for (i = 0; i < max_conns - 1; i++) {
+               struct smb2_create create;
+
+               status = smb2_util_roothandle(tree[i], &dh[i]);
+               CHECK_STATUS(status, NT_STATUS_OK);
+
+               notify[i].in.recursive         = 0x0001;
+               notify[i].in.buffer_size       = 0x1000;
+               notify[i].in.file.handle       = dh[i];
+               notify[i].in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
+               notify[i].in.unknown           = 0x0;
+
+               req[i] = smb2_notify_send(tree[i], &notify[i]);
+
+               /* Now, wait for the pending ... */
+               WAIT_FOR_ASYNC_RESPONSE(req[i]);
+
+               /* Now, get a handle for the dir on this tree as well. */
+               ZERO_STRUCT(create);
+               create.in.desired_access = SEC_RIGHTS_DIR_ALL;
+               create.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
+               create.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
+               create.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+                                       NTCREATEX_SHARE_ACCESS_WRITE |
+                                       NTCREATEX_SHARE_ACCESS_DELETE;
+               create.in.create_disposition = NTCREATEX_DISP_OPEN;
+               create.in.fname = BASEDIR;
+
+               status = smb2_create(tree[i], torture, &create);
+               CHECK_STATUS(status, NT_STATUS_OK);
+               dirh[i] = create.out.file.handle;
+       }
+
+
+       torture_comment(torture, "Sent all the change_notify requests
..., now creating a file\n");
+
+       ZERO_STRUCT(io);
+       io.in.oplock_level = 0;
+       io.in.desired_access     = SEC_RIGHTS_FILE_ALL;
+       io.in.file_attributes    = FILE_ATTRIBUTE_NORMAL;
+       io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
+       io.in.share_access       = NTCREATEX_SHARE_ACCESS_DELETE |
+                                  NTCREATEX_SHARE_ACCESS_READ |
+                                  NTCREATEX_SHARE_ACCESS_WRITE;
+       io.in.create_options = 0;
+       io.in.fname = BASEDIR "\\some-file.txt";
+
+       req[max_conns - 1] = smb2_create_send(tree[max_conns - 1], &io);
+
+       torture_comment(torture, "Sent the create now ...\n");
+
+       /*
+        * Now, loop through those requests figuring out which one has
completed.
+        */
+       while (complete != (max_conns - 1)) {
+               if (tevent_loop_once(torture->ev) != 0) {
+                       return false;
+               }
+               for (i = 0; i < max_conns; i++) {
+                       if (req[i]->cancel.can_cancel ||
+                            req[i]->state > SMB2_REQUEST_RECV) {
+
+                               if (i < (max_conns - 1)) {
+                                       /* We should be able to get
that notify */
+                                       status =
smb2_notify_recv(req[i], torture, &notify[i]);
+                                       CHECK_STATUS(status, NT_STATUS_OK);
+
+                                       torture_comment(torture,
"Notify %d received\n", i);
+                                       complete++;
+
+                                       /* Now, send a FIND * request */
+
+                                       ZERO_STRUCT(find[i]);
+                                       find[i].in.file.handle = dirh[i];
+                                       find[i].in.pattern = "*";
+                                       find[i].in.continue_flags = 0;
+                                       find[i].in.max_response_size = 65536;
+                                       find[i].in.level =
SMB2_FIND_BOTH_DIRECTORY_INFO;
+
+                                       /* Send the find ... */
+                                       find_req[i] =
smb2_find_send(tree[i], &find[i]);
+                               }
+                               else {
+                                       status =
smb2_create_recv(req[i], torture, &io);
+                                       CHECK_STATUS(status, NT_STATUS_OK);
+                                       torture_comment(torture,
"Create received\n");
+                               }
+                               req[i]->state = SMB2_REQUEST_INIT; /* DONE */
+                       }
+               }
+
+       }
+
+       /*
+        * We should wait for the find responses now ... but ...
+        */
+       while (find_complete != (max_conns - 1)) {
+               if (tevent_loop_once(torture->ev) != 0) {
+                       return false;
+               }
+               for (i = 0; i < max_conns - 1; i++) {
+                       if (find_req[i]->cancel.can_cancel ||
+                            find_req[i]->state > SMB2_REQUEST_RECV) {
+                               status = smb2_find_recv(find_req[i],
torture, &find[i]);
+                               CHECK_STATUS(status, NT_STATUS_OK);
+
+                               find_complete++;
+                               torture_comment(torture, "Find %d
received\n", i);
+
+                               find_req[i]->state = SMB2_REQUEST_INIT;
+                       }
+               }
+       }
+
+done:
+       torture_comment(torture, "Sleeping for a while ...\n");
+       sleep(10);
+       return ret;
+}
+
 #define        ITERATIONS      1000
 #define        DATA_SIZE       4096 /*Size of data per write and per
read in each iteration*/

@@ -2295,6 +2459,7 @@
        torture_suite_add_1smb2_test(suite, "overflow",
torture_smb2_notify_overflow);
        torture_suite_add_1smb2_test(suite, "large-buffer",
torture_smb2_notify_large_buffer);
        torture_suite_add_nsmb2_test(suite,
"distributed_change_notify", 3, test_distributed_change_notify);
+       torture_suite_add_nsmb2_test(suite, "multiple_change_notify",
51, test_multiple_change_notify);

        suite->description = talloc_strdup(suite, "SMB2-NOTIFY tests");


-- 
Regards,
Richard Sharpe
(何以解憂?唯有杜康。--曹操)


More information about the samba-technical mailing list