From: Volker Lendecke Date: Tue, 20 Aug 2019 12:47:27 +0000 (+0200) Subject: smbd: Use share_mode_forall_entries() in delay_for_oplock() X-Git-Tag: talloc-2.3.1~801 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2a784883a889b517b86cce328f0798c92b69a2d5;p=thirdparty%2Fsamba.git smbd: Use share_mode_forall_entries() in delay_for_oplock() Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- diff --git a/source3/smbd/open.c b/source3/smbd/open.c index f714ccd29bd..a9b3c8cf323 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -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; inum_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; }