From 2505c6c4071f142571bde5809504e8665837d412 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Thu, 2 Nov 2017 12:36:25 +0100 Subject: [PATCH 01/15] VERSION: Bump version up to 4.7.2... and re-enable GIT_SNAPSHOTS. Signed-off-by: Karolin Seeger --- VERSION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index c8a48377ac3..04110837524 100644 --- a/VERSION +++ b/VERSION @@ -25,7 +25,7 @@ ######################################################## SAMBA_VERSION_MAJOR=4 SAMBA_VERSION_MINOR=7 -SAMBA_VERSION_RELEASE=1 +SAMBA_VERSION_RELEASE=2 ######################################################## # If a official release has a serious bug # @@ -99,7 +99,7 @@ SAMBA_VERSION_RC_RELEASE= # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_GIT_SNAPSHOT=no +SAMBA_VERSION_IS_GIT_SNAPSHOT=yes ######################################################## # This is for specifying a release nickname # From 0b0d2485ea55e324577b01a880286183e14b2dac Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 3 Nov 2017 21:47:01 +0000 Subject: [PATCH 02/15] Revert "s3/smbd: fix deferred open with streams and kernel oplocks" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit b35a296a27a0807c780f2a9e7af2f2e93feefaa8. This was the cause of BUG: https://bugzilla.samba.org/show_bug.cgi?id=13058 1. client of smbd-1 opens the file and sets the oplock. 2. client of smbd-2 tries to open the file. open() fails(EAGAIN) and open is deferred. 3. client of smbd-1 sends oplock break request to the client. 4. client of smbd-1 closes the file. 5. client of smbd-1 opens the file and sets the oplock. 6. client of smbd-2 calls defer_open_done(), sees that the file lease was not changed and does not reschedule open. and is no longer needed now vfs_streams_xattr.c no longer opens the base file internally. Signed-off-by: Jeremy Allison Reviewed-by: Ralph Böhme (cherry picked from commit 62a556d5c8ce0650e3a2095ee62bea16c8eab1d5) --- source3/smbd/open.c | 115 +++++----------------------------------------------- 1 file changed, 11 insertions(+), 104 deletions(-) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 7781a6f86a7..89a267b0634 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -1896,23 +1896,6 @@ static bool delay_for_oplock(files_struct *fsp, return delay; } -/** - * Return lease or oplock state from a share mode - **/ -static uint32_t get_lease_type_from_share_mode(const struct share_mode_data *d) -{ - uint32_t e_lease_type = 0; - uint32_t i; - - for (i=0; i < d->num_share_modes; i++) { - struct share_mode_entry *e = &d->share_modes[i]; - - e_lease_type |= get_lease_type(d, e); - } - - return e_lease_type; -} - static bool file_has_brlocks(files_struct *fsp) { struct byte_range_lock *br_lck; @@ -2325,11 +2308,6 @@ static struct deferred_open_record *deferred_open_record_create( struct defer_open_state { struct smbXsrv_connection *xconn; uint64_t mid; - struct file_id file_id; - struct timeval request_time; - struct timeval timeout; - bool kernel_oplock; - uint32_t lease_type; }; static void defer_open_done(struct tevent_req *req); @@ -2348,7 +2326,6 @@ static void defer_open(struct share_mode_lock *lck, struct timeval timeout, struct smb_request *req, bool delayed_for_oplocks, - bool kernel_oplock, struct file_id id) { struct deferred_open_record *open_rec = NULL; @@ -2360,12 +2337,11 @@ static void defer_open(struct share_mode_lock *lck, abs_timeout = timeval_sum(&request_time, &timeout); DBG_DEBUG("request time [%s] timeout [%s] mid [%" PRIu64 "] " - "delayed_for_oplocks [%s] kernel_oplock [%s] file_id [%s]\n", + "delayed_for_oplocks [%s] file_id [%s]\n", timeval_string(talloc_tos(), &request_time, false), timeval_string(talloc_tos(), &abs_timeout, false), req->mid, delayed_for_oplocks ? "yes" : "no", - kernel_oplock ? "yes" : "no", file_id_string_tos(&id)); open_rec = deferred_open_record_create(delayed_for_oplocks, @@ -2382,11 +2358,6 @@ static void defer_open(struct share_mode_lock *lck, } watch_state->xconn = req->xconn; watch_state->mid = req->mid; - watch_state->file_id = lck->data->id; - watch_state->request_time = request_time; - watch_state->timeout = timeout; - watch_state->kernel_oplock = kernel_oplock; - watch_state->lease_type = get_lease_type_from_share_mode(lck->data); DBG_DEBUG("defering mid %" PRIu64 "\n", req->mid); @@ -2416,12 +2387,8 @@ static void defer_open_done(struct tevent_req *req) { struct defer_open_state *state = tevent_req_callback_data( req, struct defer_open_state); - struct tevent_req *watch_req = NULL; - struct share_mode_lock *lck = NULL; - bool schedule_req = true; - struct timeval timeout; NTSTATUS status; - bool ok; + bool ret; status = dbwrap_watched_watch_recv(req, talloc_tos(), NULL, NULL, NULL); @@ -2433,72 +2400,13 @@ static void defer_open_done(struct tevent_req *req) * Even if it failed, retry anyway. TODO: We need a way to * tell a re-scheduled open about that error. */ - if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) && - state->kernel_oplock) - { - /* - * If we reschedule but the kernel oplock is still hold - * we would block in the second open as that will be a - * blocking open attempt. - */ - exit_server("Kernel oplock holder didn't " - "respond to break message"); - } - } - - if (state->kernel_oplock) { - lck = get_existing_share_mode_lock(talloc_tos(), state->file_id); - if (lck != NULL) { - uint32_t lease_type; - - lease_type = get_lease_type_from_share_mode(lck->data); - - if ((lease_type != 0) && - (lease_type == state->lease_type)) - { - DBG_DEBUG("Unchanged lease: %" PRIu32 "\n", - lease_type); - schedule_req = false; - } - } - } - - if (schedule_req) { - DBG_DEBUG("scheduling mid %" PRIu64 "\n", state->mid); - - ok = schedule_deferred_open_message_smb(state->xconn, - state->mid); - if (!ok) { - exit_server("schedule_deferred_open_message_smb failed"); - } - TALLOC_FREE(lck); - TALLOC_FREE(state); - return; - } - - DBG_DEBUG("Keep waiting for oplock release for [%s/%s%s] " - "mid: %" PRIu64 "\n", - lck->data->servicepath, - lck->data->base_name, - lck->data->stream_name ? lck->data->stream_name : "", - state->mid); - - watch_req = dbwrap_watched_watch_send(state, - state->xconn->ev_ctx, - lck->data->record, - (struct server_id){0}); - if (watch_req == NULL) { - exit_server("Could not watch share mode record"); } - tevent_req_set_callback(watch_req, defer_open_done, state); - timeout = timeval_sum(&state->request_time, &state->timeout); - ok = tevent_req_set_endtime(watch_req, state->xconn->ev_ctx, timeout); - if (!ok) { - exit_server("tevent_req_set_endtime failed"); - } + DEBUG(10, ("scheduling mid %llu\n", (unsigned long long)state->mid)); - TALLOC_FREE(lck); + ret = schedule_deferred_open_message_smb(state->xconn, state->mid); + SMB_ASSERT(ret); + TALLOC_FREE(state); } /** @@ -2649,8 +2557,7 @@ static NTSTATUS fcb_or_dos_open(struct smb_request *req, static void schedule_defer_open(struct share_mode_lock *lck, struct file_id id, struct timeval request_time, - struct smb_request *req, - bool kernel_oplock) + struct smb_request *req) { /* This is a relative time, added to the absolute request_time value to get the absolute timeout time. @@ -2674,7 +2581,7 @@ static void schedule_defer_open(struct share_mode_lock *lck, return; } - defer_open(lck, request_time, timeout, req, true, kernel_oplock, id); + defer_open(lck, request_time, timeout, req, true, id); } /**************************************************************************** @@ -3360,7 +3267,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, first_open_attempt); if (delay) { schedule_defer_open(lck, fsp->file_id, request_time, - req, true); + req); TALLOC_FREE(lck); DEBUG(10, ("Sent oplock break request to kernel " "oplock holder\n")); @@ -3493,7 +3400,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, first_open_attempt); if (delay) { schedule_defer_open(lck, fsp->file_id, - request_time, req, false); + request_time, req); TALLOC_FREE(lck); fd_close(fsp); return NT_STATUS_SHARING_VIOLATION; @@ -3597,7 +3504,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, if (!request_timed_out(request_time, timeout)) { defer_open(lck, request_time, timeout, req, - false, false, id); + false, id); } } From aebe7a4974e71d449950ccde840128161205df3f Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 3 Nov 2017 12:02:17 -0700 Subject: [PATCH 03/15] s4: torture: kernel_oplocks. Create a regression test case for bug #13058. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It implements the following test case: 1. client of smbd-1 opens the file and sets the oplock. 2. client of smbd-2 tries to open the file. open() fails(EAGAIN) and open is deferred. 3. client of smbd-1 sends oplock break request to the client. 4. client of smbd-1 closes the file. 5. client of smbd-1 opens the file and sets the oplock. 6. client of smbd-2 calls defer_open_done(), sees that the file lease was not changed and does not reschedule open. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13058 Signed-off-by: Jeremy Allison Reviewed-by: Ralph Böhme (cherry picked from commit 15597a95ecd2d1c2b7edce4942d489c95796951f) --- source4/torture/smb2/oplock.c | 117 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/source4/torture/smb2/oplock.c b/source4/torture/smb2/oplock.c index e0db5ecb50d..3290ed42d8c 100644 --- a/source4/torture/smb2/oplock.c +++ b/source4/torture/smb2/oplock.c @@ -4674,6 +4674,122 @@ static bool test_smb2_kernel_oplocks6(struct torture_context *tctx, return ret; } +/** + * Recreate regression test from bug: + * + * https://bugzilla.samba.org/show_bug.cgi?id=13058 + * + * 1. smbd-1 opens the file and sets the oplock + * 2. smbd-2 tries to open the file. open() fails(EAGAIN) and open is deferred. + * 3. smbd-1 sends oplock break request to the client. + * 4. smbd-1 closes the file. + * 5. smbd-1 opens the file and sets the oplock. + * 6. smbd-2 calls defer_open_done(), and should re-break the oplock. + **/ + +static bool test_smb2_kernel_oplocks7(struct torture_context *tctx, + struct smb2_tree *tree, + struct smb2_tree *tree2) +{ + const char *fname = "test_kernel_oplock7.dat"; + NTSTATUS status; + bool ret = true; + struct smb2_create create; + struct smb2_handle h1 = {{0}}, h2 = {{0}}; + struct smb2_create create_2; + struct smb2_create io; + struct smb2_request *req; + + smb2_util_unlink(tree, fname); + status = torture_smb2_testfile(tree, fname, &h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "Error creating testfile\n"); + smb2_util_close(tree, h1); + ZERO_STRUCT(h1); + + /* Close the open file on break. */ + tree->session->transport->oplock.handler = torture_oplock_handler_close; + tree->session->transport->oplock.private_data = tree; + ZERO_STRUCT(break_info); + + /* 1 - open file with oplock */ + ZERO_STRUCT(create); + create.in.desired_access = SEC_RIGHTS_FILE_ALL; + create.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create.in.share_access = NTCREATEX_SHARE_ACCESS_MASK; + create.in.create_disposition = NTCREATEX_DISP_OPEN; + create.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; + create.in.fname = fname; + create.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "Error opening the file\n"); + CHECK_VAL(create.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE); + + /* 2 - open file to break oplock */ + ZERO_STRUCT(create_2); + create_2.in.desired_access = SEC_RIGHTS_FILE_ALL; + create_2.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + create_2.in.share_access = NTCREATEX_SHARE_ACCESS_MASK; + create_2.in.create_disposition = NTCREATEX_DISP_OPEN; + create_2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; + create_2.in.fname = fname; + create_2.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE; + + /* Open on tree2 - should cause a break on tree */ + req = smb2_create_send(tree2, &create_2); + torture_assert(tctx, req != NULL, "smb2_create_send"); + + /* The oplock break handler should close the file. */ + /* Steps 3 & 4. */ + torture_wait_for_oplock_break(tctx); + + tree->session->transport->oplock.handler = torture_oplock_handler; + + /* + * 5 - re-open on tree. NB. There is a race here + * depending on which smbd goes first. We either get + * an oplock level of SMB2_OPLOCK_LEVEL_EXCLUSIVE if + * the close and re-open on tree is processed first, or + * SMB2_OPLOCK_LEVEL_NONE if the pending create on + * tree2 is processed first. + */ + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "Error opening the file\n"); + + h1 = create.out.file.handle; + if (create.out.oplock_level != SMB2_OPLOCK_LEVEL_EXCLUSIVE && + create.out.oplock_level != SMB2_OPLOCK_LEVEL_NONE) { + torture_result(tctx, + TORTURE_FAIL, + "(%s): wrong value for oplock got 0x%x\n", + __location__, + (unsigned int)create.out.oplock_level); + ret = false; + goto done; + + } + + /* 6 - retrieve the second open. */ + status = smb2_create_recv(req, tctx, &io); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "Error opening the file\n"); + h2 = io.out.file.handle; + CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE); + +done: + if (!smb2_util_handle_empty(h1)) { + smb2_util_close(tree, h1); + } + if (!smb2_util_handle_empty(h2)) { + smb2_util_close(tree2, h2); + } + smb2_util_unlink(tree, fname); + return ret; +} + struct torture_suite *torture_smb2_kernel_oplocks_init(TALLOC_CTX *ctx) { struct torture_suite *suite = @@ -4685,6 +4801,7 @@ struct torture_suite *torture_smb2_kernel_oplocks_init(TALLOC_CTX *ctx) torture_suite_add_1smb2_test(suite, "kernel_oplocks4", test_smb2_kernel_oplocks4); torture_suite_add_1smb2_test(suite, "kernel_oplocks5", test_smb2_kernel_oplocks5); torture_suite_add_2smb2_test(suite, "kernel_oplocks6", test_smb2_kernel_oplocks6); + torture_suite_add_2smb2_test(suite, "kernel_oplocks7", test_smb2_kernel_oplocks7); suite->description = talloc_strdup(suite, "SMB2-KERNEL-OPLOCK tests"); From 007e8fe6a148217c91beb43cfe6865dd620802ff Mon Sep 17 00:00:00 2001 From: Ralph Wuerthner Date: Fri, 3 Nov 2017 22:33:28 +0000 Subject: [PATCH 04/15] s3: smbd: Fix delete-on-close after smb2_find Both dptr_create() and can_delete_directory_fsp() are calling OpenDir_fsp() to get a directory handle. This causes an issue when delete-on-close is set after smb2_find because both directory handle instances share the same underlying file descriptor. In addition the SMB_ASSERT() in destructor smb_Dir_destructor() gets triggered. To avoid this use OpenDir() instead of OpenDir_fsp(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=13118 Signed-off-by: Ralph Wuerthner Reviewed-by: Jeremy Allison Reviewed-by: Volker Lendecke (cherry picked from commit c9e996d78df3ce326a5c13f8f4f1426918769ceb) --- source3/smbd/dir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index cb54be4de76..19e29640118 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -2128,9 +2128,9 @@ NTSTATUS can_delete_directory_fsp(files_struct *fsp) char *talloced = NULL; SMB_STRUCT_STAT st; struct connection_struct *conn = fsp->conn; - struct smb_Dir *dir_hnd = OpenDir_fsp(talloc_tos(), + struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, - fsp, + fsp->fsp_name, NULL, 0); From d41af5d03dd7f8375e1295001d920007c113143c Mon Sep 17 00:00:00 2001 From: Ralph Wuerthner Date: Fri, 27 Oct 2017 14:59:32 +0200 Subject: [PATCH 05/15] s4: torture: Add smb2 FIND_and_set_DOC test case. Regression tests doing an SMB2_find followed by a set delete on close and then close on a directory. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13118 Signed-off-by: Ralph Wuerthner Reviewed-by: Jeremy Allison Reviewed-by: Volker Lendecke Autobuild-User(master): Volker Lendecke Autobuild-Date(master): Sun Nov 5 12:31:12 CET 2017 on sn-devel-144 (cherry picked from commit 44c018bdcc2d81aaf667d11c0c8fae209419ddd7) --- source4/torture/smb2/delete-on-close.c | 66 ++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/source4/torture/smb2/delete-on-close.c b/source4/torture/smb2/delete-on-close.c index 44ef33ec6f8..2312df285a3 100644 --- a/source4/torture/smb2/delete-on-close.c +++ b/source4/torture/smb2/delete-on-close.c @@ -516,6 +516,71 @@ static bool test_doc_create_if_exist(struct torture_context *tctx, struct smb2_t return true; } +static bool test_doc_find_and_set_doc(struct torture_context *tctx, struct smb2_tree *tree) +{ + struct smb2_create io; + struct smb2_find find; + NTSTATUS status; + union smb_search_data *d; + union smb_setfileinfo sfinfo; + unsigned int count; + uint32_t perms = 0; + + perms = SEC_STD_SYNCHRONIZE | SEC_STD_READ_CONTROL | SEC_STD_DELETE | + SEC_DIR_WRITE_ATTRIBUTE | SEC_DIR_READ_ATTRIBUTE | + SEC_DIR_WRITE_EA | SEC_FILE_APPEND_DATA | + SEC_FILE_WRITE_DATA | SEC_DIR_LIST; + + /* File should not exist for this first test, so make sure */ + set_dir_delete_perms(tctx, tree); + + smb2_deltree(tree, DNAME); + + create_dir(tctx, tree); + + torture_comment(tctx, "FIND and delete directory\n"); + torture_comment(tctx, "We expect NT_STATUS_OK\n"); + + /* open the directory first */ + ZERO_STRUCT(io); + io.in.desired_access = perms; + io.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; + io.in.create_disposition = NTCREATEX_DISP_OPEN_IF; + io.in.share_access = NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_DELETE; + io.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; + io.in.fname = DNAME; + + status = smb2_create(tree, tctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* list directory */ + ZERO_STRUCT(find); + find.in.file.handle = io.out.file.handle; + find.in.pattern = "*"; + find.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE; + find.in.max_response_size = 0x100; + find.in.level = SMB2_FIND_BOTH_DIRECTORY_INFO; + + /* start enumeration on directory */ + status = smb2_find_level(tree, tree, &find, &count, &d); + CHECK_STATUS(status, NT_STATUS_OK); + + /* set delete-on-close */ + ZERO_STRUCT(sfinfo); + sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION; + sfinfo.disposition_info.in.delete_on_close = 1; + sfinfo.generic.in.file.handle = io.out.file.handle; + status = smb2_setinfo_file(tree, &sfinfo); + CHECK_STATUS(status, NT_STATUS_OK); + + /* close directory */ + status = smb2_util_close(tree, io.out.file.handle); + CHECK_STATUS(status, NT_STATUS_OK); + return true; +} + + /* * Extreme testing of Delete On Close and permissions */ @@ -529,6 +594,7 @@ struct torture_suite *torture_smb2_doc_init(TALLOC_CTX *ctx) torture_suite_add_1smb2_test(suite, "CREATE Existing", test_doc_create_exist); torture_suite_add_1smb2_test(suite, "CREATE_IF", test_doc_create_if); torture_suite_add_1smb2_test(suite, "CREATE_IF Existing", test_doc_create_if_exist); + torture_suite_add_1smb2_test(suite, "FIND_and_set_DOC", test_doc_find_and_set_doc); suite->description = talloc_strdup(suite, "SMB2-Delete-on-Close-Perms tests"); From 5ec68b2e44e5c0c4e6fae362c7e36ad99124faa8 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 10 Nov 2017 21:22:26 +0100 Subject: [PATCH 06/15] tevent: Fix a race condition We can't rely on tctx to exist after we unlocked the mutex. It took a while, but this does lead to data corruption. If *tctx is replaced with something where tctx->wakeup_fd points to a real, existing file descriptor, we're screwed. And by screwed, this means file corruption on disk. Again. I am not tall enough for this business. http://bholley.net/blog/2015/must-be-this-tall-to-write-multi-threaded-code.html BUG: https://bugzilla.samba.org/show_bug.cgi?id=13130 Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Sat Nov 11 03:20:09 CET 2017 on sn-devel-144 (cherry picked from commit 20cfcb7dbc5dd099384b76a76e3d35cf627100b6) Autobuild-User(v4-7-test): Karolin Seeger Autobuild-Date(v4-7-test): Mon Nov 13 13:54:56 CET 2017 on sn-devel-144 --- lib/tevent/tevent_threads.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/tevent/tevent_threads.c b/lib/tevent/tevent_threads.c index 4d1a8805181..2e83f1b66c2 100644 --- a/lib/tevent/tevent_threads.c +++ b/lib/tevent/tevent_threads.c @@ -451,7 +451,7 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx, { #ifdef HAVE_PTHREAD struct tevent_context *ev; - int ret; + int ret, wakeup_fd; ret = pthread_mutex_lock(&tctx->event_ctx_mutex); if (ret != 0) { @@ -495,6 +495,8 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx, abort(); } + wakeup_fd = tctx->wakeup_fd; + ret = pthread_mutex_unlock(&tctx->event_ctx_mutex); if (ret != 0) { abort(); @@ -510,7 +512,7 @@ void _tevent_threaded_schedule_immediate(struct tevent_threaded_context *tctx, * than a noncontended one. So I'd opt for the lower footprint * initially. Maybe we have to change that later. */ - tevent_common_wakeup_fd(tctx->wakeup_fd); + tevent_common_wakeup_fd(wakeup_fd); #else /* * tevent_threaded_context_create() returned NULL with ENOSYS... From c0000bd6024ee4208cd7c5356f4c3fb68b8476b8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 12 Sep 2017 12:08:38 -0700 Subject: [PATCH 07/15] lib: tevent: Remove select backend. select() is no longer useful on modern systems. Signed-off-by: Jeremy Allison Reviewed-by: Volker Lendecke Autobuild-User(master): Volker Lendecke Autobuild-Date(master): Sat Sep 16 08:35:39 CEST 2017 on sn-devel-144 (cherry picked from commit 2a003b1a576dcbbba0d60bae90427776a5c27867) --- lib/tevent/tevent.c | 1 - lib/tevent/tevent_internal.h | 1 - lib/tevent/tevent_select.c | 280 ------------------------------------------- lib/tevent/wscript | 2 +- source3/selftest/tests.py | 2 +- source3/torture/torture.c | 10 +- 6 files changed, 7 insertions(+), 289 deletions(-) delete mode 100644 lib/tevent/tevent_select.c diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c index 5f44b035e50..a2d2003cbf4 100644 --- a/lib/tevent/tevent.c +++ b/lib/tevent/tevent.c @@ -128,7 +128,6 @@ static void tevent_backend_init(void) done = true; - tevent_select_init(); tevent_poll_init(); tevent_poll_mt_init(); #if defined(HAVE_EPOLL) diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h index a5f1ebdefd5..47ea39b3cd1 100644 --- a/lib/tevent/tevent_internal.h +++ b/lib/tevent/tevent_internal.h @@ -377,7 +377,6 @@ int tevent_common_check_signal(struct tevent_context *ev); void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se); bool tevent_standard_init(void); -bool tevent_select_init(void); bool tevent_poll_init(void); void tevent_poll_event_add_fd_internal(struct tevent_context *ev, struct tevent_fd *fde); diff --git a/lib/tevent/tevent_select.c b/lib/tevent/tevent_select.c deleted file mode 100644 index 55dd0b66f66..00000000000 --- a/lib/tevent/tevent_select.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - Unix SMB/CIFS implementation. - main select loop and event handling - Copyright (C) Andrew Tridgell 2003-2005 - Copyright (C) Stefan Metzmacher 2005-2009 - - ** NOTE! The following LGPL license applies to the tevent - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see . -*/ - -#include "replace.h" -#include "system/filesys.h" -#include "system/select.h" -#include "tevent.h" -#include "tevent_util.h" -#include "tevent_internal.h" - -struct select_event_context { - /* a pointer back to the generic event_context */ - struct tevent_context *ev; - - /* the maximum file descriptor number in fd_events */ - int maxfd; -}; - -/* - create a select_event_context structure. -*/ -static int select_event_context_init(struct tevent_context *ev) -{ - struct select_event_context *select_ev; - - /* - * We might be called during tevent_re_initialise() - * which means we need to free our old additional_data. - */ - TALLOC_FREE(ev->additional_data); - - select_ev = talloc_zero(ev, struct select_event_context); - if (!select_ev) return -1; - select_ev->ev = ev; - - ev->additional_data = select_ev; - return 0; -} - -/* - recalculate the maxfd -*/ -static void calc_maxfd(struct select_event_context *select_ev) -{ - struct tevent_fd *fde; - - select_ev->maxfd = 0; - for (fde = select_ev->ev->fd_events; fde; fde = fde->next) { - if (fde->fd > select_ev->maxfd) { - select_ev->maxfd = fde->fd; - } - } -} - - -/* to mark the ev->maxfd invalid - * this means we need to recalculate it - */ -#define EVENT_INVALID_MAXFD (-1) - -/* - destroy an fd_event -*/ -static int select_event_fd_destructor(struct tevent_fd *fde) -{ - struct tevent_context *ev = fde->event_ctx; - struct select_event_context *select_ev = NULL; - - if (ev) { - select_ev = talloc_get_type_abort(ev->additional_data, - struct select_event_context); - - if (select_ev->maxfd == fde->fd) { - select_ev->maxfd = EVENT_INVALID_MAXFD; - } - } - - return tevent_common_fd_destructor(fde); -} - -/* - add a fd based event - return NULL on failure (memory allocation error) -*/ -static struct tevent_fd *select_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx, - int fd, uint16_t flags, - tevent_fd_handler_t handler, - void *private_data, - const char *handler_name, - const char *location) -{ - struct select_event_context *select_ev = - talloc_get_type_abort(ev->additional_data, - struct select_event_context); - struct tevent_fd *fde; - - if (fd < 0 || fd >= FD_SETSIZE) { - errno = EBADF; - return NULL; - } - - fde = tevent_common_add_fd(ev, mem_ctx, fd, flags, - handler, private_data, - handler_name, location); - if (!fde) return NULL; - - if ((select_ev->maxfd != EVENT_INVALID_MAXFD) - && (fde->fd > select_ev->maxfd)) { - select_ev->maxfd = fde->fd; - } - talloc_set_destructor(fde, select_event_fd_destructor); - - return fde; -} - -/* - event loop handling using select() -*/ -static int select_event_loop_select(struct select_event_context *select_ev, struct timeval *tvalp) -{ - fd_set r_fds, w_fds; - struct tevent_fd *fde; - int selrtn; - int select_errno; - - /* we maybe need to recalculate the maxfd */ - if (select_ev->maxfd == EVENT_INVALID_MAXFD) { - calc_maxfd(select_ev); - } - - FD_ZERO(&r_fds); - FD_ZERO(&w_fds); - - /* setup any fd events */ - for (fde = select_ev->ev->fd_events; fde; fde = fde->next) { - if (fde->fd < 0 || fde->fd >= FD_SETSIZE) { - tevent_debug(select_ev->ev, TEVENT_DEBUG_FATAL, - "ERROR: EBADF fd[%d] >= %d " - "select_event_loop_once\n", - fde->fd, FD_SETSIZE); - errno = EBADF; - return -1; - } - - if (fde->flags & TEVENT_FD_READ) { - FD_SET(fde->fd, &r_fds); - } - if (fde->flags & TEVENT_FD_WRITE) { - FD_SET(fde->fd, &w_fds); - } - } - - if (select_ev->ev->signal_events && - tevent_common_check_signal(select_ev->ev)) { - return 0; - } - - tevent_trace_point_callback(select_ev->ev, TEVENT_TRACE_BEFORE_WAIT); - selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp); - select_errno = errno; - tevent_trace_point_callback(select_ev->ev, TEVENT_TRACE_AFTER_WAIT); - - if (selrtn == -1 && select_errno == EINTR && - select_ev->ev->signal_events) { - tevent_common_check_signal(select_ev->ev); - return 0; - } - - if (selrtn == -1 && select_errno == EBADF) { - /* the socket is dead! this should never - happen as the socket should have first been - made readable and that should have removed - the event, so this must be a bug. This is a - fatal error. */ - tevent_debug(select_ev->ev, TEVENT_DEBUG_FATAL, - "ERROR: EBADF on select_event_loop_once\n"); - errno = select_errno; - return -1; - } - - if (selrtn == 0 && tvalp) { - /* we don't care about a possible delay here */ - tevent_common_loop_timer_delay(select_ev->ev); - return 0; - } - - if (selrtn > 0) { - /* at least one file descriptor is ready - check - which ones and call the handler, being careful to allow - the handler to remove itself when called */ - for (fde = select_ev->ev->fd_events; fde; fde = fde->next) { - uint16_t flags = 0; - - if (FD_ISSET(fde->fd, &r_fds) && (fde->flags & TEVENT_FD_READ)) { - flags |= TEVENT_FD_READ; - } - if (FD_ISSET(fde->fd, &w_fds) && (fde->flags & TEVENT_FD_WRITE)) { - flags |= TEVENT_FD_WRITE; - } - if (flags) { - DLIST_DEMOTE(select_ev->ev->fd_events, fde); - fde->handler(select_ev->ev, fde, flags, fde->private_data); - break; - } - } - } - - return 0; -} - -/* - do a single event loop using the events defined in ev -*/ -static int select_event_loop_once(struct tevent_context *ev, const char *location) -{ - struct select_event_context *select_ev = - talloc_get_type_abort(ev->additional_data, - struct select_event_context); - struct timeval tval; - - if (ev->signal_events && - tevent_common_check_signal(ev)) { - return 0; - } - - if (ev->threaded_contexts != NULL) { - tevent_common_threaded_activate_immediate(ev); - } - - if (ev->immediate_events && - tevent_common_loop_immediate(ev)) { - return 0; - } - - tval = tevent_common_loop_timer_delay(ev); - if (tevent_timeval_is_zero(&tval)) { - return 0; - } - - return select_event_loop_select(select_ev, &tval); -} - -static const struct tevent_ops select_event_ops = { - .context_init = select_event_context_init, - .add_fd = select_event_add_fd, - .set_fd_close_fn = tevent_common_fd_set_close_fn, - .get_fd_flags = tevent_common_fd_get_flags, - .set_fd_flags = tevent_common_fd_set_flags, - .add_timer = tevent_common_add_timer_v2, - .schedule_immediate = tevent_common_schedule_immediate, - .add_signal = tevent_common_add_signal, - .loop_once = select_event_loop_once, - .loop_wait = tevent_common_loop_wait, -}; - -_PRIVATE_ bool tevent_select_init(void) -{ - return tevent_register_backend("select", &select_event_ops); -} diff --git a/lib/tevent/wscript b/lib/tevent/wscript index bc874bb2b38..91880738f90 100644 --- a/lib/tevent/wscript +++ b/lib/tevent/wscript @@ -77,7 +77,7 @@ def build(bld): bld.RECURSE('lib/talloc') SRC = '''tevent.c tevent_debug.c tevent_fd.c tevent_immediate.c - tevent_queue.c tevent_req.c tevent_select.c + tevent_queue.c tevent_req.c tevent_poll.c tevent_threads.c tevent_signal.c tevent_standard.c tevent_timed.c tevent_util.c tevent_wakeup.c''' diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 56b94c436ce..d11f596759b 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -133,7 +133,7 @@ def plansmbtorture4testsuite(name, env, options, description=''): "LOCAL-sid_to_string", "LOCAL-binary_to_sid", "LOCAL-DBTRANS", - "LOCAL-TEVENT-SELECT", + "LOCAL-TEVENT-POLL", "LOCAL-CONVERT-STRING", "LOCAL-CONV-AUTH-INFO", "LOCAL-IDMAP-TDB-COMMON", diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 31e2bcc3497..1d89041b784 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -11114,17 +11114,17 @@ static bool run_local_dbtrans(int dummy) /* * Just a dummy test to be run under a debugger. There's no real way - * to inspect the tevent_select specific function from outside of - * tevent_select.c. + * to inspect the tevent_poll specific function from outside of + * tevent_poll.c. */ -static bool run_local_tevent_select(int dummy) +static bool run_local_tevent_poll(int dummy) { struct tevent_context *ev; struct tevent_fd *fd1, *fd2; bool result = false; - ev = tevent_context_init_byname(NULL, "select"); + ev = tevent_context_init_byname(NULL, "poll"); if (ev == NULL) { d_fprintf(stderr, "tevent_context_init_byname failed\n"); goto fail; @@ -11677,7 +11677,7 @@ static struct { { "LOCAL-sid_to_string", run_local_sid_to_string, 0}, { "LOCAL-binary_to_sid", run_local_binary_to_sid, 0}, { "LOCAL-DBTRANS", run_local_dbtrans, 0}, - { "LOCAL-TEVENT-SELECT", run_local_tevent_select, 0}, + { "LOCAL-TEVENT-POLL", run_local_tevent_poll, 0}, { "LOCAL-CONVERT-STRING", run_local_convert_string, 0}, { "LOCAL-CONV-AUTH-INFO", run_local_conv_auth_info, 0}, { "LOCAL-hex_encode_buf", run_local_hex_encode_buf, 0}, From e45ab18baeb665b5ec5a82adda288c92c731f11e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 13 Nov 2017 11:05:04 +0100 Subject: [PATCH 08/15] tevent: version 0.9.34 * Remove unused select backend * Fix a race condition in tevent_threaded_schedule_immediate() (bug #13130) Signed-off-by: Stefan Metzmacher Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Mon Nov 13 18:02:46 CET 2017 on sn-devel-144 (cherry picked from commit 2e573eead96b2e98dd8a15c9c8e470679e530392) --- lib/tevent/ABI/tevent-0.9.34.sigs | 99 +++++++++++++++++++++++++++++++++++++++ lib/tevent/wscript | 2 +- 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 lib/tevent/ABI/tevent-0.9.34.sigs diff --git a/lib/tevent/ABI/tevent-0.9.34.sigs b/lib/tevent/ABI/tevent-0.9.34.sigs new file mode 100644 index 00000000000..7a6a23689a4 --- /dev/null +++ b/lib/tevent/ABI/tevent-0.9.34.sigs @@ -0,0 +1,99 @@ +_tevent_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *) +_tevent_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *) +_tevent_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *) +_tevent_create_immediate: struct tevent_immediate *(TALLOC_CTX *, const char *) +_tevent_loop_once: int (struct tevent_context *, const char *) +_tevent_loop_until: int (struct tevent_context *, bool (*)(void *), void *, const char *) +_tevent_loop_wait: int (struct tevent_context *, const char *) +_tevent_queue_create: struct tevent_queue *(TALLOC_CTX *, const char *, const char *) +_tevent_req_callback_data: void *(struct tevent_req *) +_tevent_req_cancel: bool (struct tevent_req *, const char *) +_tevent_req_create: struct tevent_req *(TALLOC_CTX *, void *, size_t, const char *, const char *) +_tevent_req_data: void *(struct tevent_req *) +_tevent_req_done: void (struct tevent_req *, const char *) +_tevent_req_error: bool (struct tevent_req *, uint64_t, const char *) +_tevent_req_nomem: bool (const void *, struct tevent_req *, const char *) +_tevent_req_notify_callback: void (struct tevent_req *, const char *) +_tevent_req_oom: void (struct tevent_req *, const char *) +_tevent_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *) +_tevent_threaded_schedule_immediate: void (struct tevent_threaded_context *, struct tevent_immediate *, tevent_immediate_handler_t, void *, const char *, const char *) +tevent_backend_list: const char **(TALLOC_CTX *) +tevent_cleanup_pending_signal_handlers: void (struct tevent_signal *) +tevent_common_add_fd: struct tevent_fd *(struct tevent_context *, TALLOC_CTX *, int, uint16_t, tevent_fd_handler_t, void *, const char *, const char *) +tevent_common_add_signal: struct tevent_signal *(struct tevent_context *, TALLOC_CTX *, int, int, tevent_signal_handler_t, void *, const char *, const char *) +tevent_common_add_timer: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *) +tevent_common_add_timer_v2: struct tevent_timer *(struct tevent_context *, TALLOC_CTX *, struct timeval, tevent_timer_handler_t, void *, const char *, const char *) +tevent_common_check_signal: int (struct tevent_context *) +tevent_common_context_destructor: int (struct tevent_context *) +tevent_common_fd_destructor: int (struct tevent_fd *) +tevent_common_fd_get_flags: uint16_t (struct tevent_fd *) +tevent_common_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t) +tevent_common_fd_set_flags: void (struct tevent_fd *, uint16_t) +tevent_common_have_events: bool (struct tevent_context *) +tevent_common_loop_immediate: bool (struct tevent_context *) +tevent_common_loop_timer_delay: struct timeval (struct tevent_context *) +tevent_common_loop_wait: int (struct tevent_context *, const char *) +tevent_common_schedule_immediate: void (struct tevent_immediate *, struct tevent_context *, tevent_immediate_handler_t, void *, const char *, const char *) +tevent_common_threaded_activate_immediate: void (struct tevent_context *) +tevent_common_wakeup: int (struct tevent_context *) +tevent_common_wakeup_fd: int (int) +tevent_common_wakeup_init: int (struct tevent_context *) +tevent_context_init: struct tevent_context *(TALLOC_CTX *) +tevent_context_init_byname: struct tevent_context *(TALLOC_CTX *, const char *) +tevent_context_init_ops: struct tevent_context *(TALLOC_CTX *, const struct tevent_ops *, void *) +tevent_debug: void (struct tevent_context *, enum tevent_debug_level, const char *, ...) +tevent_fd_get_flags: uint16_t (struct tevent_fd *) +tevent_fd_set_auto_close: void (struct tevent_fd *) +tevent_fd_set_close_fn: void (struct tevent_fd *, tevent_fd_close_fn_t) +tevent_fd_set_flags: void (struct tevent_fd *, uint16_t) +tevent_get_trace_callback: void (struct tevent_context *, tevent_trace_callback_t *, void *) +tevent_loop_allow_nesting: void (struct tevent_context *) +tevent_loop_set_nesting_hook: void (struct tevent_context *, tevent_nesting_hook, void *) +tevent_num_signals: size_t (void) +tevent_queue_add: bool (struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *) +tevent_queue_add_entry: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *) +tevent_queue_add_optimize_empty: struct tevent_queue_entry *(struct tevent_queue *, struct tevent_context *, struct tevent_req *, tevent_queue_trigger_fn_t, void *) +tevent_queue_length: size_t (struct tevent_queue *) +tevent_queue_running: bool (struct tevent_queue *) +tevent_queue_start: void (struct tevent_queue *) +tevent_queue_stop: void (struct tevent_queue *) +tevent_queue_wait_recv: bool (struct tevent_req *) +tevent_queue_wait_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct tevent_queue *) +tevent_re_initialise: int (struct tevent_context *) +tevent_register_backend: bool (const char *, const struct tevent_ops *) +tevent_req_default_print: char *(struct tevent_req *, TALLOC_CTX *) +tevent_req_defer_callback: void (struct tevent_req *, struct tevent_context *) +tevent_req_is_error: bool (struct tevent_req *, enum tevent_req_state *, uint64_t *) +tevent_req_is_in_progress: bool (struct tevent_req *) +tevent_req_poll: bool (struct tevent_req *, struct tevent_context *) +tevent_req_post: struct tevent_req *(struct tevent_req *, struct tevent_context *) +tevent_req_print: char *(TALLOC_CTX *, struct tevent_req *) +tevent_req_received: void (struct tevent_req *) +tevent_req_reset_endtime: void (struct tevent_req *) +tevent_req_set_callback: void (struct tevent_req *, tevent_req_fn, void *) +tevent_req_set_cancel_fn: void (struct tevent_req *, tevent_req_cancel_fn) +tevent_req_set_cleanup_fn: void (struct tevent_req *, tevent_req_cleanup_fn) +tevent_req_set_endtime: bool (struct tevent_req *, struct tevent_context *, struct timeval) +tevent_req_set_print_fn: void (struct tevent_req *, tevent_req_print_fn) +tevent_sa_info_queue_count: size_t (void) +tevent_set_abort_fn: void (void (*)(const char *)) +tevent_set_debug: int (struct tevent_context *, void (*)(void *, enum tevent_debug_level, const char *, va_list), void *) +tevent_set_debug_stderr: int (struct tevent_context *) +tevent_set_default_backend: void (const char *) +tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *) +tevent_signal_support: bool (struct tevent_context *) +tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *) +tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *) +tevent_threaded_context_create: struct tevent_threaded_context *(TALLOC_CTX *, struct tevent_context *) +tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t) +tevent_timeval_compare: int (const struct timeval *, const struct timeval *) +tevent_timeval_current: struct timeval (void) +tevent_timeval_current_ofs: struct timeval (uint32_t, uint32_t) +tevent_timeval_is_zero: bool (const struct timeval *) +tevent_timeval_set: struct timeval (uint32_t, uint32_t) +tevent_timeval_until: struct timeval (const struct timeval *, const struct timeval *) +tevent_timeval_zero: struct timeval (void) +tevent_trace_point_callback: void (struct tevent_context *, enum tevent_trace_point) +tevent_update_timer: void (struct tevent_timer *, struct timeval) +tevent_wakeup_recv: bool (struct tevent_req *) +tevent_wakeup_send: struct tevent_req *(TALLOC_CTX *, struct tevent_context *, struct timeval) diff --git a/lib/tevent/wscript b/lib/tevent/wscript index 91880738f90..31f7ee7c0cc 100644 --- a/lib/tevent/wscript +++ b/lib/tevent/wscript @@ -1,7 +1,7 @@ #!/usr/bin/env python APPNAME = 'tevent' -VERSION = '0.9.33' +VERSION = '0.9.34' blddir = 'bin' From f1fe68f724022aa89d8a6c1aeb991257e0a047be Mon Sep 17 00:00:00 2001 From: Gary Lockyer Date: Wed, 16 Aug 2017 13:52:25 +1200 Subject: [PATCH 09/15] blackbox tests: method to check specific exit codes Signed-off-by: Gary Lockyer Reviewed-by: Douglas Bagnall Reviewed-by: Garming Sam (cherry picked from commit 74ebcf6dfc84b6aab6838fa99e12808eb6b913d9) BUG: https://bugzilla.samba.org/show_bug.cgi?id=13127 --- python/samba/tests/__init__.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py index 07c68c4e9f2..69c1a7ffbd3 100644 --- a/python/samba/tests/__init__.py +++ b/python/samba/tests/__init__.py @@ -311,11 +311,20 @@ def _make_cmdline(self, line): return line def check_run(self, line): + self.check_exit_code(line, 0) + + def check_exit_code(self, line, expected): line = self._make_cmdline(line) - p = subprocess.Popen(line, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + p = subprocess.Popen(line, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=True) retcode = p.wait() - if retcode: - raise BlackboxProcessError(retcode, line, p.stdout.read(), p.stderr.read()) + if retcode != expected: + raise BlackboxProcessError(retcode, + line, + p.stdout.read(), + p.stderr.read()) def check_output(self, line): line = self._make_cmdline(line) From 510b11d0b675f91cd3cad4ea422538d197bbf6f1 Mon Sep 17 00:00:00 2001 From: Joe Guo Date: Fri, 15 Sep 2017 16:13:26 +1200 Subject: [PATCH 10/15] python: use communicate to fix Popen deadlock `Popen.wait()` will deadlock when using stdout=PIPE and/or stderr=PIPE and the child process generates large output to a pipe such that it blocks waiting for the OS pipe buffer to accept more data. Use communicate() to avoid that. Signed-off-by: Joe Guo Reviewed-by: Douglas Bagnall Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Thu Oct 19 09:27:16 CEST 2017 on sn-devel-144 BUG: https://bugzilla.samba.org/show_bug.cgi?id=13127 (cherry picked from commit 5dc773a5b00834c7a53130a73a48f49048bd55e8) --- python/samba/tests/__init__.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py index 69c1a7ffbd3..0b0f567dd64 100644 --- a/python/samba/tests/__init__.py +++ b/python/samba/tests/__init__.py @@ -319,20 +319,22 @@ def check_exit_code(self, line, expected): stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) - retcode = p.wait() + stdoutdata, stderrdata = p.communicate() + retcode = p.returncode if retcode != expected: raise BlackboxProcessError(retcode, line, - p.stdout.read(), - p.stderr.read()) + stdoutdata, + stderrdata) def check_output(self, line): line = self._make_cmdline(line) p = subprocess.Popen(line, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, close_fds=True) - retcode = p.wait() + stdoutdata, stderrdata = p.communicate() + retcode = p.returncode if retcode: - raise BlackboxProcessError(retcode, line, p.stdout.read(), p.stderr.read()) - return p.stdout.read() + raise BlackboxProcessError(retcode, line, stdoutdata, stderrdata) + return stdoutdata def connect_samdb(samdb_url, lp=None, session_info=None, credentials=None, From 6e276cab469da33a4499feca62858451bac63494 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 9 Nov 2017 12:48:15 -0800 Subject: [PATCH 11/15] s3: smbd: kernel oplocks. Replace retry_open() with setup_kernel_oplock_poll_open(). If a O_NONBLOCK open fails with EWOULDBLOCK, this code changes smbd to do a retry open every second, until either the timeout or we get a successful open. If we're opening a file that has a kernel lease set by a non-smbd process, this is the best we can do. Prior to this, smbd would block on the second open on such a leased file (not using O_NONBLOCK) which freezes active clients. Regression test to follow. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13121 Signed-off-by: Jeremy Allison Reviewed-by: Ralph Boehme (cherry picked from commit 47c13fc10a2c9709e9511b2ffcf0e1004497887d) --- source3/smbd/open.c | 96 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 68 insertions(+), 28 deletions(-) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 89a267b0634..8c52f4bba56 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -2410,19 +2410,40 @@ static void defer_open_done(struct tevent_req *req) } /** - * Reschedule an open for immediate execution + * Actually attempt the kernel oplock polling open. + */ + +static void kernel_oplock_poll_open_timer(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval current_time, + void *private_data) +{ + bool ok; + struct smb_request *req = (struct smb_request *)private_data; + + ok = schedule_deferred_open_message_smb(req->xconn, req->mid); + if (!ok) { + exit_server("schedule_deferred_open_message_smb failed"); + } + DBG_DEBUG("kernel_oplock_poll_open_timer fired. Retying open !\n"); +} + +/** + * Reschedule an open for 1 second from now, if not timed out. **/ -static void retry_open(struct timeval request_time, +static void setup_kernel_oplock_poll_open(struct timeval request_time, struct smb_request *req, struct file_id id) { - struct deferred_open_record *open_rec = NULL; + bool ok; + struct deferred_open_record *open_rec = NULL; + /* Maximum wait time. */ + struct timeval timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0); - DBG_DEBUG("request time [%s] mid [%" PRIu64 "] file_id [%s]\n", - timeval_string(talloc_tos(), &request_time, false), - req->mid, - file_id_string_tos(&id)); + if (request_timed_out(request_time, timeout)) { + return; + } open_rec = deferred_open_record_create(false, false, id); if (open_rec == NULL) { @@ -2431,17 +2452,30 @@ static void retry_open(struct timeval request_time, ok = push_deferred_open_message_smb(req, request_time, - timeval_set(0, 0), + timeout, id, open_rec); if (!ok) { exit_server("push_deferred_open_message_smb failed"); } - ok = schedule_deferred_open_message_smb(req->xconn, req->mid); - if (!ok) { - exit_server("schedule_deferred_open_message_smb failed"); + /* + * As this timer event is owned by req, it will + * disappear if req it talloc_freed. + */ + open_rec->te = tevent_add_timer(req->sconn->ev_ctx, + req, + timeval_current_ofs(1, 0), + kernel_oplock_poll_open_timer, + req); + if (open_rec->te == NULL) { + exit_server("tevent_add_timer failed"); } + + DBG_DEBUG("poll request time [%s] mid [%" PRIu64 "] file_id [%s]\n", + timeval_string(talloc_tos(), &request_time, false), + req->mid, + file_id_string_tos(&id)); } /**************************************************************************** @@ -3160,20 +3194,18 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, flags2 &= ~(O_CREAT|O_TRUNC); } - if (first_open_attempt && lp_kernel_oplocks(SNUM(conn))) { + if (lp_kernel_oplocks(SNUM(conn))) { /* * With kernel oplocks the open breaking an oplock * blocks until the oplock holder has given up the - * oplock or closed the file. We prevent this by first + * oplock or closed the file. We prevent this by always * trying to open the file with O_NONBLOCK (see "man - * fcntl" on Linux). For the second try, triggered by - * an oplock break response, we do not need this - * anymore. + * fcntl" on Linux). * - * This is true under the assumption that only Samba - * requests kernel oplocks. Once someone else like - * NFSv4 starts to use that API, we will have to - * modify this by communicating with the NFSv4 server. + * If a process that doesn't use the smbd open files + * database or communication methods holds a kernel + * oplock we must periodically poll for available open + * using O_NONBLOCK. */ flags2 |= O_NONBLOCK; } @@ -3252,9 +3284,16 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id); if (lck == NULL) { - retry_open(request_time, req, fsp->file_id); - DEBUG(10, ("No share mode lock found after " - "EWOULDBLOCK, retrying sync\n")); + /* + * No oplock from Samba around. Set up a poll every 1 + * second to retry a non-blocking open until the time + * expires. + */ + setup_kernel_oplock_poll_open(request_time, + req, + fsp->file_id); + DBG_DEBUG("No Samba oplock around after EWOULDBLOCK. " + "Retrying with poll\n"); return NT_STATUS_SHARING_VIOLATION; } @@ -3275,14 +3314,15 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, } /* - * No oplock from Samba around. Immediately retry with - * a blocking open. + * No oplock from Samba around. Set up a poll every 1 + * second to retry a non-blocking open until the time + * expires. */ - retry_open(request_time, req, fsp->file_id); + setup_kernel_oplock_poll_open(request_time, req, fsp->file_id); TALLOC_FREE(lck); - DEBUG(10, ("No Samba oplock around after EWOULDBLOCK. " - "Retrying sync\n")); + DBG_DEBUG("No Samba oplock around after EWOULDBLOCK. " + "Retrying with poll\n"); return NT_STATUS_SHARING_VIOLATION; } From d7a07213e478e1c30d153c7061eb8ae72dcb75c9 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 9 Nov 2017 09:59:23 -0800 Subject: [PATCH 12/15] s4: torture: kernel oplocks. Add smb2.kernel-oplocks.kernel_oplocks8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test if the server blocks whilst waiting on a kernel lease held by a non-smbd process. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13121 Signed-off-by: Jeremy Allison Reviewed-by: Ralph Boehme Autobuild-User(master): Ralph Böhme Autobuild-Date(master): Sat Nov 11 20:12:26 CET 2017 on sn-devel-144 (cherry picked from commit ad82557e1355107920ae80fd6a0df0f16d1bdb6c) Autobuild-User(v4-7-test): Karolin Seeger Autobuild-Date(v4-7-test): Tue Nov 14 16:59:15 CET 2017 on sn-devel-144 --- source3/selftest/tests.py | 2 +- source4/torture/smb2/oplock.c | 236 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+), 1 deletion(-) diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index d11f596759b..357970db9bd 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -497,7 +497,7 @@ def plansmbtorture4testsuite(name, env, options, description=''): plansmbtorture4testsuite(t, "simpleserver", '//$SERVER/dosmode -U$USERNAME%$PASSWORD') elif t == "smb2.kernel-oplocks": if have_linux_kernel_oplocks: - plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER/kernel_oplocks -U$USERNAME%$PASSWORD') + plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER/kernel_oplocks -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/nt4_dc/share') elif t == "smb2.notify-inotify": if have_inotify: plansmbtorture4testsuite(t, "fileserver", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD') diff --git a/source4/torture/smb2/oplock.c b/source4/torture/smb2/oplock.c index 3290ed42d8c..1830a017e83 100644 --- a/source4/torture/smb2/oplock.c +++ b/source4/torture/smb2/oplock.c @@ -36,6 +36,8 @@ #include "torture/torture.h" #include "torture/smb2/proto.h" +#include "lib/util/sys_rw.h" + #define CHECK_RANGE(v, min, max) do { \ if ((v) < (min) || (v) > (max)) { \ torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \ @@ -4790,6 +4792,239 @@ static bool test_smb2_kernel_oplocks7(struct torture_context *tctx, return ret; } +#if HAVE_KERNEL_OPLOCKS_LINUX + +#ifndef F_SETLEASE +#define F_SETLEASE 1024 +#endif + +#ifndef RT_SIGNAL_LEASE +#define RT_SIGNAL_LEASE (SIGRTMIN+1) +#endif + +#ifndef F_SETSIG +#define F_SETSIG 10 +#endif + +static int got_break; + +/* + * Signal handler. + */ + +static void got_rt_break(int sig) +{ + got_break = 1; +} + +/* + * Child process function. + */ + +static int do_child_process(int pipefd, const char *name) +{ + int ret = 0; + int fd = -1; + char c = 0; + struct sigaction act; + + /* Set up a signal handler for RT_SIGNAL_LEASE. */ + ZERO_STRUCT(act); + act.sa_handler = got_rt_break; + ret = sigaction(RT_SIGNAL_LEASE, &act, NULL); + if (ret == -1) { + return 1; + } + /* Open the passed in file and get a kernel oplock. */ + fd = open(name, O_RDWR, 0666); + if (fd == -1) { + return 2; + } + + ret = fcntl(fd, F_SETSIG, RT_SIGNAL_LEASE); + if (ret == -1) { + return 3; + } + + ret = fcntl(fd, F_SETLEASE, F_WRLCK); + if (ret == -1) { + return 4; + } + + /* Tell the parent we're ready. */ + ret = sys_write(pipefd, &c, 1); + if (ret != 1) { + return 5; + } + + /* Wait for RT_SIGNAL_LEASE. */ + ret = pause(); + if (ret != -1 || errno != EINTR) { + return 6; + } + + if (got_break != 1) { + return 7; + } + + /* Force the server to wait for 3 seconds. */ + sleep(3); + + /* Remove our lease. */ + ret = fcntl(fd, F_SETLEASE, F_UNLCK); + if (ret == -1) { + return 8; + } + + ret = close(fd); + if (ret == -1) { + return 9; + } + + /* All is well. */ + return 0; +} + +static bool wait_for_child_oplock(struct torture_context *tctx, + const char *localdir, + const char *fname) +{ + int fds[2]; + int ret; + pid_t pid; + char *name = talloc_asprintf(tctx, + "%s/%s", + localdir, + fname); + + torture_assert(tctx, name != NULL, "talloc failed"); + + ret = pipe(fds); + torture_assert(tctx, ret != -1, "pipe failed"); + + pid = fork(); + torture_assert(tctx, pid != (pid_t)-1, "fork failed"); + + if (pid != (pid_t)0) { + char c; + /* Parent. */ + TALLOC_FREE(name); + ret = sys_read(fds[0], &c, 1); + torture_assert(tctx, ret == 1, "read failed"); + return true; + } + + /* Child process. */ + ret = do_child_process(fds[1], name); + _exit(ret); + /* Notreached. */ +} +#else +static bool wait_for_child_oplock(struct torture_context *tctx, + const char *localdir, + const char *fname) +{ + return false; +} +#endif + +/* + * Deal with a non-smbd process holding a kernel oplock. + */ + +static bool test_smb2_kernel_oplocks8(struct torture_context *tctx, + struct smb2_tree *tree) +{ + const char *fname = "test_kernel_oplock8.dat"; + const char *fname1 = "tmp_test_kernel_oplock8.dat"; + NTSTATUS status; + bool ret = true; + struct smb2_create io; + struct smb2_request *req = NULL; + struct smb2_handle h1 = {{0}}; + struct smb2_handle h2 = {{0}}; + const char *localdir = torture_setting_string(tctx, "localdir", NULL); + time_t start; + time_t end; + +#ifndef HAVE_KERNEL_OPLOCKS_LINUX + torture_skip(tctx, "Need kernel oplocks for test"); +#endif + + if (localdir == NULL) { + torture_skip(tctx, "Need localdir for test"); + } + + smb2_util_unlink(tree, fname); + smb2_util_unlink(tree, fname1); + status = torture_smb2_testfile(tree, fname, &h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "Error creating testfile\n"); + smb2_util_close(tree, h1); + ZERO_STRUCT(h1); + + /* Take the oplock locally in a sub-process. */ + ret = wait_for_child_oplock(tctx, localdir, fname); + torture_assert_goto(tctx, ret = true, ret, done, + "Wait for child process failed.\n"); + + /* + * Now try and open. This should block for 3 seconds. + * while the child process is still alive. + */ + + ZERO_STRUCT(io); + io.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; + io.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + io.in.create_disposition = NTCREATEX_DISP_OPEN; + io.in.share_access = + NTCREATEX_SHARE_ACCESS_DELETE| + NTCREATEX_SHARE_ACCESS_READ| + NTCREATEX_SHARE_ACCESS_WRITE; + io.in.create_options = 0; + io.in.fname = fname; + + req = smb2_create_send(tree, &io); + torture_assert(tctx, req != NULL, "smb2_create_send"); + + /* Ensure while the open is blocked the smbd is + still serving other requests. */ + io.in.fname = fname1; + io.in.create_disposition = NTCREATEX_DISP_CREATE; + + /* Time the start -> end of the request. */ + start = time(NULL); + status = smb2_create(tree, tctx, &io); + end = time(NULL); + + /* Should succeed. */ + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "Error opening the second file\n"); + h1 = io.out.file.handle; + + /* in less than 2 seconds. Otherwise the server blocks. */ + torture_assert(tctx, end - start < 2, "server was blocked !"); + + /* Pick up the return for the initial blocking open. */ + status = smb2_create_recv(req, tctx, &io); + + /* Which should also have succeeded. */ + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "Error opening the file\n"); + h2 = io.out.file.handle; + +done: + if (!smb2_util_handle_empty(h1)) { + smb2_util_close(tree, h1); + } + if (!smb2_util_handle_empty(h2)) { + smb2_util_close(tree, h2); + } + smb2_util_unlink(tree, fname); + smb2_util_unlink(tree, fname1); + return ret; +} + struct torture_suite *torture_smb2_kernel_oplocks_init(TALLOC_CTX *ctx) { struct torture_suite *suite = @@ -4802,6 +5037,7 @@ struct torture_suite *torture_smb2_kernel_oplocks_init(TALLOC_CTX *ctx) torture_suite_add_1smb2_test(suite, "kernel_oplocks5", test_smb2_kernel_oplocks5); torture_suite_add_2smb2_test(suite, "kernel_oplocks6", test_smb2_kernel_oplocks6); torture_suite_add_2smb2_test(suite, "kernel_oplocks7", test_smb2_kernel_oplocks7); + torture_suite_add_1smb2_test(suite, "kernel_oplocks8", test_smb2_kernel_oplocks8); suite->description = talloc_strdup(suite, "SMB2-KERNEL-OPLOCK tests"); From 53b7208fd6814cd7a973f11663e7a1c83283411e Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 14 Nov 2017 13:22:52 +0100 Subject: [PATCH 13/15] WHATSNEW: Add release notes for Samba 4.7.2. Signed-off-by: Karolin Seeger --- WHATSNEW.txt | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index 6de5de81478..8074a83e429 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -1,4 +1,60 @@ ============================= + Release Notes for Samba 4.7.2 + November 15, 2017 + ============================= + + +This is an additional bugfix release to address a possible data corruption +issue. Please update immediately! For details, please see + + https://bugzilla.samba.org/show_bug.cgi?id=13130 + +Samba 4.6.0 and newer is affected by this issue. + + +Changes since 4.7.1: +-------------------- + +o Jeremy Allison + * BUG 13121: Non-smbd processes using kernel oplocks can hang smbd. + +o Joe Guo + * BUG 13127: python: use communicate to fix Popen deadlock. + +o Volker Lendecke + * BUG 13130: smbd on disk file corruption bug under heavy threaded load. + +o Stefan Metzmacher + * BUG 13130: tevent: version 0.9.34. + +o Ralph Wuerthner + * BUG 13118: s3: smbd: Fix delete-on-close after smb2_find. + + +####################################### +Reporting bugs & Development Discussion +####################################### + +Please discuss this release on the samba-technical mailing list or by +joining the #samba-technical IRC channel on irc.freenode.net. + +If you do report problems then please try to send high quality +feedback. If you don't provide vital information to help us track down +the problem then you will probably be ignored. All bug reports should +be filed under the "Samba 4.1 and newer" product in the project's Bugzilla +database (https://bugzilla.samba.org/). + + +====================================================================== +== Our Code, Our Bugs, Our Responsibility. +== The Samba Team +====================================================================== + + +Release notes for older releases follow: +---------------------------------------- + + ============================= Release Notes for Samba 4.7.1 November 02, 2017 ============================= @@ -106,8 +162,8 @@ database (https://bugzilla.samba.org/). ====================================================================== -Release notes for older releases follow: ----------------------------------------- +---------------------------------------------------------------------- + ============================= Release Notes for Samba 4.7.0 From c5bb8ef9e793bb7cd82f8d53786f2c5daa431470 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 14 Nov 2017 13:23:27 +0100 Subject: [PATCH 14/15] VERSION: Disable GIT_SNAPSHOT for the 4.7.2 release. Signed-off-by: Karolin Seeger --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 04110837524..2f5c246562e 100644 --- a/VERSION +++ b/VERSION @@ -99,7 +99,7 @@ SAMBA_VERSION_RC_RELEASE= # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_GIT_SNAPSHOT=yes +SAMBA_VERSION_IS_GIT_SNAPSHOT=no ######################################################## # This is for specifying a release nickname # From 70d7a5c8dc5f73649440a9f50910d532e2eb2a34 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 14 Nov 2017 13:24:15 +0100 Subject: [PATCH 15/15] VERSION: Bump version up to 4.7.3... and re-enable GIT_SNAPSHOT. Signed-off-by: Karolin Seeger --- VERSION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 2f5c246562e..0ba31a362f2 100644 --- a/VERSION +++ b/VERSION @@ -25,7 +25,7 @@ ######################################################## SAMBA_VERSION_MAJOR=4 SAMBA_VERSION_MINOR=7 -SAMBA_VERSION_RELEASE=2 +SAMBA_VERSION_RELEASE=3 ######################################################## # If a official release has a serious bug # @@ -99,7 +99,7 @@ SAMBA_VERSION_RC_RELEASE= # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_GIT_SNAPSHOT=no +SAMBA_VERSION_IS_GIT_SNAPSHOT=yes ######################################################## # This is for specifying a release nickname #