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

Richard Sharpe realrichardsharpe at gmail.com
Wed Feb 5 21:48:24 MST 2014


On Wed, Feb 5, 2014 at 9:50 AM, Richard Sharpe
<realrichardsharpe at gmail.com> wrote:
> +++ /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");

We have some extensions to allow you to create tests that work with N
connections:

> torture_suite_add_nsmb2_test(suite, "multiple_change_notify", 51, test_multiple_change_notify);

However, it is a bit clunky at the moment because you have to specify
the number of connections when you define the test.

It would be more useful if you could specify the number of connections
either with a parameter like --num-conn 51 or by specifying 51 UNCs on
the command line.

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


More information about the samba-technical mailing list