1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-09 08:58:35 +03:00

s3:smbd: add lease related helper functions to oplock.c

Pair-Programmed-With: Jeremy Allison <jra@samba.org>
Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Volker Lendecke <vl@samba.org>
Signed-off-by: Jeremy Allison <jra@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
This commit is contained in:
Volker Lendecke 2014-10-28 15:31:46 -07:00 committed by Jeremy Allison
parent 205ef314bc
commit 91b2488c9a
2 changed files with 303 additions and 0 deletions

View File

@ -306,6 +306,301 @@ bool downgrade_oplock(files_struct *fsp)
return ret;
}
static void lease_timeout_handler(struct tevent_context *ctx,
struct tevent_timer *te,
struct timeval now,
void *private_data)
{
struct fsp_lease *lease =
talloc_get_type_abort(private_data,
struct fsp_lease);
struct files_struct *fsp;
struct share_mode_lock *lck;
uint16_t old_epoch = lease->lease.lease_epoch;
fsp = file_find_one_fsp_from_lease_key(lease->sconn,
&lease->lease.lease_key);
if (fsp == NULL) {
/* race? */
TALLOC_FREE(lease->timeout);
return;
}
lck = get_existing_share_mode_lock(
talloc_tos(), fsp->file_id);
if (lck == NULL) {
/* race? */
TALLOC_FREE(lease->timeout);
return;
}
fsp_lease_update(lck, fsp_client_guid(fsp), lease);
if (lease->lease.lease_epoch != old_epoch) {
/*
* If the epoch changed we need to wait for
* the next timeout to happen.
*/
DEBUG(10, ("lease break timeout race (epoch) for file %s - ignoring\n",
fsp_str_dbg(fsp)));
TALLOC_FREE(lck);
return;
}
if (!(lease->lease.lease_flags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS)) {
/*
* If the epoch changed we need to wait for
* the next timeout to happen.
*/
DEBUG(10, ("lease break timeout race (flags) for file %s - ignoring\n",
fsp_str_dbg(fsp)));
TALLOC_FREE(lck);
return;
}
DEBUG(1, ("lease break timed out for file %s -- replying anyway\n",
fsp_str_dbg(fsp)));
(void)downgrade_lease(lease->sconn->client->connections,
1,
&fsp->file_id,
&lease->lease.lease_key,
SMB2_LEASE_NONE);
TALLOC_FREE(lck);
}
bool fsp_lease_update(struct share_mode_lock *lck,
const struct GUID *client_guid,
struct fsp_lease *lease)
{
struct share_mode_data *d = lck->data;
int idx;
struct share_mode_lease *l = NULL;
idx = find_share_mode_lease(d, client_guid, &lease->lease.lease_key);
if (idx != -1) {
l = &d->leases[idx];
}
if (l == NULL) {
DEBUG(1, ("%s: Could not find lease entry\n", __func__));
TALLOC_FREE(lease->timeout);
lease->lease.lease_state = SMB2_LEASE_NONE;
lease->lease.lease_epoch += 1;
lease->lease.lease_flags = 0;
return false;
}
DEBUG(10,("%s: refresh lease state\n", __func__));
/* Ensure we're in sync with current lease state. */
if (lease->lease.lease_epoch != l->epoch) {
DEBUG(10,("%s: cancel outdated timeout\n", __func__));
TALLOC_FREE(lease->timeout);
}
lease->lease.lease_epoch = l->epoch;
lease->lease.lease_state = l->current_state;
if (l->breaking) {
lease->lease.lease_flags |= SMB2_LEASE_FLAG_BREAK_IN_PROGRESS;
if (lease->timeout == NULL) {
struct timeval t = timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0);
DEBUG(10,("%s: setup timeout handler\n", __func__));
lease->timeout = tevent_add_timer(lease->sconn->ev_ctx,
lease, t,
lease_timeout_handler,
lease);
if (lease->timeout == NULL) {
DEBUG(0, ("%s: Could not add lease timeout handler\n",
__func__));
}
}
} else {
lease->lease.lease_flags &= ~SMB2_LEASE_FLAG_BREAK_IN_PROGRESS;
TALLOC_FREE(lease->timeout);
}
return true;
}
struct downgrade_lease_additional_state {
struct tevent_immediate *im;
struct smbXsrv_connection *xconn;
uint32_t break_flags;
struct smb2_lease_key lease_key;
uint32_t break_from;
uint32_t break_to;
uint16_t new_epoch;
};
static void downgrade_lease_additional_trigger(struct tevent_context *ev,
struct tevent_immediate *im,
void *private_data)
{
struct downgrade_lease_additional_state *state =
talloc_get_type_abort(private_data,
struct downgrade_lease_additional_state);
struct smbXsrv_connection *xconn = state->xconn;
NTSTATUS status;
status = smbd_smb2_send_lease_break(xconn,
state->new_epoch,
state->break_flags,
&state->lease_key,
state->break_from,
state->break_to);
TALLOC_FREE(state);
if (!NT_STATUS_IS_OK(status)) {
smbd_server_connection_terminate(xconn,
nt_errstr(status));
return;
}
}
struct downgrade_lease_fsps_state {
struct file_id id;
struct share_mode_lock *lck;
const struct smb2_lease_key *key;
};
static struct files_struct *downgrade_lease_fsps(struct files_struct *fsp,
void *private_data)
{
struct downgrade_lease_fsps_state *state =
(struct downgrade_lease_fsps_state *)private_data;
if (fsp->oplock_type != LEASE_OPLOCK) {
return NULL;
}
if (!smb2_lease_key_equal(&fsp->lease->lease.lease_key, state->key)) {
return NULL;
}
if (!file_id_equal(&fsp->file_id, &state->id)) {
return NULL;
}
fsp_lease_update(state->lck, fsp_client_guid(fsp), fsp->lease);
return NULL;
}
NTSTATUS downgrade_lease(struct smbXsrv_connection *xconn,
uint32_t num_file_ids,
const struct file_id *ids,
const struct smb2_lease_key *key,
uint32_t lease_state)
{
struct smbd_server_connection *sconn = xconn->client->sconn;
struct share_mode_lock *lck;
struct share_mode_lease *l = NULL;
const struct file_id id = ids[0];
uint32_t i;
NTSTATUS status;
DEBUG(10, ("%s: Downgrading %s to %x\n", __func__,
file_id_string_tos(&id), (unsigned)lease_state));
lck = get_existing_share_mode_lock(talloc_tos(), id);
if (lck == NULL) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
status = downgrade_share_lease(sconn, lck, key, lease_state, &l);
DEBUG(10, ("%s: Downgrading %s to %x => %s\n", __func__,
file_id_string_tos(&id), (unsigned)lease_state, nt_errstr(status)));
if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)) {
struct downgrade_lease_additional_state *state;
state = talloc_zero(xconn,
struct downgrade_lease_additional_state);
if (state == NULL) {
TALLOC_FREE(lck);
return NT_STATUS_NO_MEMORY;
}
state->im = tevent_create_immediate(state);
if (state->im == NULL) {
TALLOC_FREE(state);
TALLOC_FREE(lck);
return NT_STATUS_NO_MEMORY;
}
state->xconn = xconn;
if (l->current_state & (~SMB2_LEASE_READ)) {
state->break_flags = SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED;
}
state->lease_key = l->lease_key;
state->break_from = l->current_state;
state->break_to = l->breaking_to_requested;
if (l->lease_version > 1) {
state->new_epoch = l->epoch;
}
if (state->break_flags == 0) {
/*
* This is an async break without
* SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED
*
* we need to store NONE state in the
* database.
*/
l->current_state = 0;
l->breaking_to_requested = 0;
l->breaking_to_required = 0;
l->breaking = false;
lck->data->modified = true;
}
tevent_schedule_immediate(state->im, xconn->ev_ctx,
downgrade_lease_additional_trigger,
state);
}
{
struct downgrade_lease_fsps_state state = {
.id = id, .lck = lck, .key = key,
};
files_forall(sconn, downgrade_lease_fsps, &state);
}
TALLOC_FREE(lck);
DEBUG(10, ("%s: Downgrading %s to %x => %s\n", __func__,
file_id_string_tos(&id), (unsigned)lease_state, nt_errstr(status)));
/*
* Dynamic share case. Ensure other opens are copies.
* This will only be breaking to NONE.
*/
for (i = 1; i < num_file_ids; i++) {
lck = get_existing_share_mode_lock(talloc_tos(), ids[i]);
if (lck == NULL) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
{
struct downgrade_lease_fsps_state state = {
.id = ids[i], .lck = lck, .key = key,
};
files_forall(sconn, downgrade_lease_fsps, &state);
}
DEBUG(10, ("%s: Downgrading %s to %x => %s\n", __func__,
file_id_string_tos(&ids[i]), (unsigned)lease_state, nt_errstr(status)));
TALLOC_FREE(lck);
}
return status;
}
/****************************************************************************
Set up an oplock break message.
****************************************************************************/

View File

@ -667,6 +667,14 @@ void break_kernel_oplock(struct messaging_context *msg_ctx, files_struct *fsp);
NTSTATUS set_file_oplock(files_struct *fsp);
bool remove_oplock(files_struct *fsp);
bool downgrade_oplock(files_struct *fsp);
bool fsp_lease_update(struct share_mode_lock *lck,
const struct GUID *client_guid,
struct fsp_lease *lease);
NTSTATUS downgrade_lease(struct smbXsrv_connection *xconn,
uint32_t num_file_ids,
const struct file_id *ids,
const struct smb2_lease_key *key,
uint32_t lease_state);
void contend_level2_oplocks_begin(files_struct *fsp,
enum level2_contention_type type);
void contend_level2_oplocks_end(files_struct *fsp,