1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00
samba-mirror/source4/torture/smb2/oplock_break_handler.c
Stefan Metzmacher ae1c3a0d9a s4:torture/smb2: provide verbose output when we're waiting for potential lease/oplock breaks
It makes it easier to follow manual tests.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14449

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
2021-03-29 19:36:37 +00:00

170 lines
4.6 KiB
C

/*
* Unix SMB/CIFS implementation.
*
* test suite for SMB2 replay
*
* Copyright (C) Anubhav Rakshit 2014
* Copyright (C) Stefan Metzmacher 2014
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "libcli/smb2/smb2.h"
#include "libcli/smb2/smb2_calls.h"
#include "torture/torture.h"
#include "torture/smb2/proto.h"
#include "../libcli/smb/smbXcli_base.h"
#include "oplock_break_handler.h"
#include "lib/events/events.h"
struct break_info break_info;
static void torture_oplock_ack_callback(struct smb2_request *req)
{
NTSTATUS status;
status = smb2_break_recv(req, &break_info.br);
if (!NT_STATUS_IS_OK(status)) {
break_info.failures++;
break_info.failure_status = status;
}
}
/**
* A general oplock break notification handler. This should be used when a
* test expects to break from batch or exclusive to a lower level.
*/
bool torture_oplock_ack_handler(struct smb2_transport *transport,
const struct smb2_handle *handle,
uint8_t level,
void *private_data)
{
struct smb2_tree *tree = private_data;
const char *name;
struct smb2_request *req;
ZERO_STRUCT(break_info.br);
break_info.handle = *handle;
break_info.level = level;
break_info.count++;
switch (level) {
case SMB2_OPLOCK_LEVEL_II:
name = "level II";
break;
case SMB2_OPLOCK_LEVEL_NONE:
name = "none";
break;
default:
name = "unknown";
break_info.failures++;
}
break_info.br.in.file.handle = *handle;
break_info.br.in.oplock_level = level;
break_info.br.in.reserved = 0;
break_info.br.in.reserved2 = 0;
break_info.received_transport = tree->session->transport;
SMB_ASSERT(tree->session->transport == transport);
if (break_info.oplock_skip_ack) {
torture_comment(break_info.tctx,
"transport[%p] skip acking to %s [0x%02X] in oplock handler\n",
transport, name, level);
return true;
}
torture_comment(break_info.tctx,
"transport[%p] Acking to %s [0x%02X] in oplock handler\n",
transport, name, level);
req = smb2_break_send(tree, &break_info.br);
req->async.fn = torture_oplock_ack_callback;
req->async.private_data = NULL;
return true;
}
/**
* A oplock break handler designed to ignore incoming break requests.
* This is used when incoming oplock break requests need to be ignored
*/
bool torture_oplock_ignore_handler(struct smb2_transport *transport,
const struct smb2_handle *handle,
uint8_t level, void *private_data)
{
return true;
}
/*
* Timer handler function notifies the registering function that time is up
*/
static void timeout_cb(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval current_time,
void *private_data)
{
bool *timesup = (bool *)private_data;
*timesup = true;
}
/*
* Wait a short period of time to receive a single oplock break request
*/
void torture_wait_for_oplock_break(struct torture_context *tctx)
{
TALLOC_CTX *tmp_ctx = talloc_new(NULL);
struct tevent_timer *te = NULL;
struct timeval ne;
bool timesup = false;
int old_count = break_info.count;
/* Wait 1 second for an oplock break */
ne = tevent_timeval_current_ofs(0, 1000000);
te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, &timesup);
if (te == NULL) {
torture_comment(tctx, "Failed to wait for an oplock break. "
"test results may not be accurate.\n");
goto done;
}
torture_comment(tctx, "Waiting for a potential oplock break...\n");
while (!timesup && break_info.count < old_count + 1) {
if (tevent_loop_once(tctx->ev) != 0) {
torture_comment(tctx, "Failed to wait for an oplock "
"break. test results may not be "
"accurate\n.");
goto done;
}
}
if (timesup) {
torture_comment(tctx, "... waiting for an oplock break timed out\n");
} else {
torture_comment(tctx, "Got %u oplock breaks\n",
break_info.count - old_count);
}
done:
/* We don't know if the timed event fired and was freed, we received
* our oplock break, or some other event triggered the loop. Thus,
* we create a tmp_ctx to be able to safely free/remove the timed
* event in all 3 cases.
*/
talloc_free(tmp_ctx);
}