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], ¬ify[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, ¬ify[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