1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-26 21:57:41 +03:00

smbd: Use share_mode_forall_entries() in delay_for_oplock()

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
Volker Lendecke 2019-08-20 14:47:27 +02:00 committed by Jeremy Allison
parent 30e62710c6
commit 2a784883a8

View File

@ -2166,6 +2166,125 @@ static int map_lease_type_to_oplock(uint32_t lease_type)
return result;
}
struct delay_for_oplock_state {
struct files_struct *fsp;
const struct smb2_lease *lease;
bool will_overwrite;
uint32_t delay_mask;
bool first_open_attempt;
bool got_handle_lease;
bool got_oplock;
bool have_other_lease;
bool delay;
};
static bool delay_for_oplock_fn(
struct share_mode_entry *e,
bool *modified,
void *private_data)
{
struct delay_for_oplock_state *state = private_data;
struct files_struct *fsp = state->fsp;
const struct smb2_lease *lease = state->lease;
bool e_is_lease = (e->op_type == LEASE_OPLOCK);
uint32_t e_lease_type = get_lease_type(e, fsp->file_id);
uint32_t break_to;
bool lease_is_breaking = false;
if (e_is_lease) {
NTSTATUS status;
if (lease != NULL) {
bool our_lease = is_same_lease(fsp, e, lease);
if (our_lease) {
DBG_DEBUG("Ignoring our own lease\n");
return false;
}
}
status = leases_db_get(
&e->client_guid,
&e->lease_key,
&fsp->file_id,
NULL, /* current_state */
&lease_is_breaking,
NULL, /* breaking_to_requested */
NULL, /* breaking_to_required */
NULL, /* lease_version */
NULL); /* epoch */
SMB_ASSERT(NT_STATUS_IS_OK(status));
}
if (!state->got_handle_lease &&
((e_lease_type & SMB2_LEASE_HANDLE) != 0) &&
!share_entry_stale_pid(e)) {
state->got_handle_lease = true;
}
if (!state->got_oplock &&
(e->op_type != LEASE_OPLOCK) &&
!share_entry_stale_pid(e)) {
state->got_oplock = true;
}
if (!state->have_other_lease &&
!is_same_lease(fsp, e, lease) &&
!share_entry_stale_pid(e)) {
state->have_other_lease = true;
}
break_to = e_lease_type & ~state->delay_mask;
if (state->will_overwrite) {
break_to &= ~(SMB2_LEASE_HANDLE|SMB2_LEASE_READ);
}
DBG_DEBUG("e_lease_type %u, will_overwrite: %u\n",
(unsigned)e_lease_type,
(unsigned)state->will_overwrite);
if ((e_lease_type & ~break_to) == 0) {
if (lease_is_breaking) {
state->delay = true;
}
return false;
}
if (share_entry_stale_pid(e)) {
return false;
}
if (state->will_overwrite) {
/*
* If we break anyway break to NONE directly.
* Otherwise vfs_set_filelen() will trigger the
* break.
*/
break_to &= ~(SMB2_LEASE_READ|SMB2_LEASE_WRITE);
}
if (!e_is_lease) {
/*
* Oplocks only support breaking to R or NONE.
*/
break_to &= ~(SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
}
DBG_DEBUG("breaking from %d to %d\n",
(int)e_lease_type,
(int)break_to);
send_break_message(
fsp->conn->sconn->msg_ctx, &fsp->file_id, e, break_to);
if (e_lease_type & state->delay_mask) {
state->delay = true;
}
if (lease_is_breaking && !state->first_open_attempt) {
state->delay = true;
}
return false;
};
static NTSTATUS delay_for_oplock(files_struct *fsp,
int oplock_request,
const struct smb2_lease *lease,
@ -2174,130 +2293,39 @@ static NTSTATUS delay_for_oplock(files_struct *fsp,
uint32_t create_disposition,
bool first_open_attempt)
{
struct share_mode_data *d = lck->data;
uint32_t i;
bool delay = false;
bool will_overwrite;
const uint32_t delay_mask = have_sharing_violation ?
SMB2_LEASE_HANDLE : SMB2_LEASE_WRITE;
bool got_handle_lease = false;
bool got_oplock = false;
bool have_other_lease = false;
struct delay_for_oplock_state state = {
.fsp = fsp,
.lease = lease,
.first_open_attempt = first_open_attempt,
};
uint32_t granted;
NTSTATUS status;
bool ok;
if (is_stat_open(fsp->access_mask)) {
goto grant;
}
state.delay_mask = have_sharing_violation ?
SMB2_LEASE_HANDLE : SMB2_LEASE_WRITE;
switch (create_disposition) {
case FILE_SUPERSEDE:
case FILE_OVERWRITE:
case FILE_OVERWRITE_IF:
will_overwrite = true;
state.will_overwrite = true;
break;
default:
will_overwrite = false;
state.will_overwrite = false;
break;
}
for (i=0; i<d->num_share_modes; i++) {
struct share_mode_entry *e = &d->share_modes[i];
bool e_is_lease = (e->op_type == LEASE_OPLOCK);
uint32_t e_lease_type = get_lease_type(e, d->id);
uint32_t break_to;
bool lease_is_breaking = false;
if (e_is_lease) {
if (lease != NULL) {
bool our_lease = is_same_lease(fsp, e, lease);
if (our_lease) {
DBG_DEBUG("Ignoring our own lease\n");
continue;
}
}
status = leases_db_get(
&e->client_guid,
&e->lease_key,
&fsp->file_id,
NULL, /* current_state */
&lease_is_breaking,
NULL, /* breaking_to_requested */
NULL, /* breaking_to_required */
NULL, /* lease_version */
NULL); /* epoch */
SMB_ASSERT(NT_STATUS_IS_OK(status));
}
if (!got_handle_lease &&
((e_lease_type & SMB2_LEASE_HANDLE) != 0) &&
!share_mode_stale_pid(d, i)) {
got_handle_lease = true;
}
if (!got_oplock &&
(e->op_type != LEASE_OPLOCK) &&
!share_mode_stale_pid(d, i)) {
got_oplock = true;
}
if (!have_other_lease &&
!is_same_lease(fsp, e, lease) &&
!share_mode_stale_pid(d, i)) {
have_other_lease = true;
}
break_to = e_lease_type & ~delay_mask;
if (will_overwrite) {
break_to &= ~(SMB2_LEASE_HANDLE|SMB2_LEASE_READ);
}
DEBUG(10, ("entry %u: e_lease_type %u, will_overwrite: %u\n",
(unsigned)i, (unsigned)e_lease_type,
(unsigned)will_overwrite));
if ((e_lease_type & ~break_to) == 0) {
if (lease_is_breaking) {
delay = true;
}
continue;
}
if (share_mode_stale_pid(d, i)) {
continue;
}
if (will_overwrite) {
/*
* If we break anyway break to NONE directly.
* Otherwise vfs_set_filelen() will trigger the
* break.
*/
break_to &= ~(SMB2_LEASE_READ|SMB2_LEASE_WRITE);
}
if (!e_is_lease) {
/*
* Oplocks only support breaking to R or NONE.
*/
break_to &= ~(SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
}
DEBUG(10, ("breaking from %d to %d\n",
(int)e_lease_type, (int)break_to));
send_break_message(fsp->conn->sconn->msg_ctx, &fsp->file_id,
e, break_to);
if (e_lease_type & delay_mask) {
delay = true;
}
if (lease_is_breaking && !first_open_attempt) {
delay = true;
}
ok = share_mode_forall_entries(lck, delay_for_oplock_fn, &state);
if (!ok) {
return NT_STATUS_INTERNAL_ERROR;
}
if (delay) {
if (state.delay) {
return NT_STATUS_RETRY;
}
@ -2343,7 +2371,7 @@ grant:
granted &= ~SMB2_LEASE_READ;
}
if (have_other_lease) {
if (state.have_other_lease) {
/*
* Can grant only one writer
*/
@ -2361,7 +2389,7 @@ grant:
}
if (oplock_request == LEASE_OPLOCK) {
if (got_oplock) {
if (state.got_oplock) {
granted &= ~SMB2_LEASE_HANDLE;
}
@ -2375,7 +2403,7 @@ grant:
DBG_DEBUG("lease_state=%d\n", fsp->lease->lease.lease_state);
} else {
if (got_handle_lease) {
if (state.got_handle_lease) {
granted = SMB2_LEASE_NONE;
}