Latest leases patchset - getting there !
Stefan (metze) Metzmacher
metze at samba.org
Fri Nov 14 01:26:17 MST 2014
Am 14.11.2014 um 09:23 schrieb Stefan (metze) Metzmacher:
> Am 14.11.2014 um 08:57 schrieb Stefan (metze) Metzmacher:
>> Am 14.11.2014 um 08:50 schrieb Stefan (metze) Metzmacher:
>>> Am 14.11.2014 um 08:39 schrieb Jeremy Allison:
>>>> On Fri, Nov 14, 2014 at 08:29:00AM +0100, Stefan (metze) Metzmacher wrote:
>>>>> Am 14.11.2014 um 08:12 schrieb Jeremy Allison:
>>>>>> On Thu, Nov 13, 2014 at 08:09:33PM -0800, Jeremy Allison wrote:
>>>>>>> On Fri, Nov 14, 2014 at 03:02:19AM +0100, Stefan (metze) Metzmacher wrote:
>>>>>>>>
>>>>>>>> This is fixed with todo19.diff.txt :-)
>>>>>>>>
>>>>>>>> There we just need to check what to do in the timeout handler.
>>>>>>>
>>>>>>> W00t! Great Metze !!!!!
>>>>>>>
>>>>>>> I think that's the last outstanding issue, right ?
>>>>>>
>>>>>> FYI. I'm making progress with the breaking2
>>>>>> test.
>>>>>>
>>>>>> I understand what is going on, but not quite
>>>>>> sure yet how to get to what is needed...
>>>>>>
>>>>>> The 'will_overwrite' is the key. I think we
>>>>>> can separate out the lease break inside
>>>>>> delay_for_oplock() when will_overwrite
>>>>>> is true from a direct break to NONE,
>>>>>> to a break to READ - and then have
>>>>>> the break to NONE happen when the
>>>>>> ftruncate happens when the open
>>>>>> actually takes place).
>>>>>
>>>>> Yep, I think the truncate needs to be wrapped into
>>>>> contend_level2_oplocks_begin() contend_level2_oplocks_end()
>>>>
>>>> It already is. Check the inside of the vfs_set_filelen()
>>>> call.
>>>>
>>>>> And we only need to downgrade to none in delay_for_oplocks()
>>>>> for real oplocks.
>>>>
>>>> Yep, we should go to READ for leases, and let
>>>> the truncate break to none.
>>>
>>> I have the patch almost finished...
>>
>> Doesn't fully work yet, but this should be the direction I think...
>
> Here's the full fix.:-)
>
> Only the timeout handling needs some test and fixes.
Sorry, here's the complete set on top of leases18.diff.txt
metze
-------------- next part --------------
From 165212ac9a7bdac5c2d3722efa6bf176975eee59 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 13 Nov 2014 11:50:14 +0100
Subject: [PATCH 1/6] TODO: breaking_to_state... works...
---
source3/locking/locking.c | 60 +++++++++--
source3/locking/proto.h | 4 +-
source3/smbd/globals.h | 6 +-
source3/smbd/open.c | 8 ++
source3/smbd/oplock.c | 244 +++++++++++++++++++++++++++++++++------------
source3/smbd/proto.h | 5 +-
source3/smbd/smb2_break.c | 30 ++++--
source3/smbd/smb2_create.c | 8 --
source3/smbd/smb2_server.c | 17 ++--
9 files changed, 276 insertions(+), 106 deletions(-)
diff --git a/source3/locking/locking.c b/source3/locking/locking.c
index 006d6d3..b3ab9ad 100644
--- a/source3/locking/locking.c
+++ b/source3/locking/locking.c
@@ -945,6 +945,7 @@ bool fsp_lease_broken(struct share_mode_lock *lck,
{
struct share_mode_data *d = lck->data;
struct share_mode_entry *e;
+ struct share_mode_oplock *o;
if (!file_id_equal(&fsp->file_id, &lck_id)) {
return false;
@@ -960,27 +961,42 @@ bool fsp_lease_broken(struct share_mode_lock *lck,
return false;
}
+ o = &d->leases[e->lease_idx];
+
if (!smb2_lease_equal(&fsp->conn->sconn->client->connections->smb2.client.guid,
- key,
- &d->leases[e->lease_idx].client_guid,
- &d->leases[e->lease_idx].lease_key)) {
+ key, &o->client_guid, &o->lease_key)) {
return false;
}
- fsp->sent_oplock_break = NO_BREAK_SENT;
+
TALLOC_FREE(fsp->oplock_timeout);
- fsp->lease->lease.lease_state = new_lease_state;
+
+ DEBUG(0,("%s: refresh lease state - line(%d)\n", __func__, __LINE__));
+ /* Ensure we're in sync with current lease state. */
+ fsp->lease->lease.lease_state = o->current_state;
+ fsp->lease->lease.lease_epoch = o->epoch;
+ if (o->breaking) {
+ DEBUG(0,("%s: refresh lease state - line(%d)\n", __func__, __LINE__));
+ fsp->lease->lease.lease_flags |= SMB2_LEASE_FLAG_BREAK_IN_PROGRESS;
+ } else {
+ DEBUG(0,("%s: refresh lease state - line(%d)\n", __func__, __LINE__));
+ fsp->lease->lease.lease_flags &= ~SMB2_LEASE_FLAG_BREAK_IN_PROGRESS;
+ }
+
return true;
}
NTSTATUS downgrade_share_lease(struct smbd_server_connection *sconn,
struct share_mode_lock *lck,
const struct smb2_lease_key *key,
- uint32_t new_lease_state)
+ uint32_t new_lease_state,
+ struct share_mode_oplock **_l)
{
struct share_mode_data *d = lck->data;
struct share_mode_oplock *l;
uint32_t i;
+ *_l = NULL;
+
for (i=0; i<d->num_leases; i++) {
if (smb2_lease_equal(&sconn->client->connections->smb2.client.guid,
key,
@@ -996,18 +1012,44 @@ NTSTATUS downgrade_share_lease(struct smbd_server_connection *sconn,
l = &d->leases[i];
+ if (!l->breaking) {
+ DEBUG(0, ("Attempt to break from %d to %d - but we're not in breaking state\n",
+ (int)l->current_state, (int)new_lease_state));
+ return NT_STATUS_INVALID_OPLOCK_PROTOCOL;
+ }
+
/*
* Can't upgrade anything: l->current_state must be a strict bitwise
* superset of new_lease_state
*/
if ((new_lease_state & l->current_state) != new_lease_state) {
- DEBUG(10, ("Attempt to upgrade from %d to %d\n",
- (int)l->current_state, (int)new_lease_state));
+ DEBUG(0, ("Attempt to upgrade from %d to %d - expected %d\n",
+ (int)l->current_state, (int)new_lease_state,
+ (int)l->breaking_to_state));
return NT_STATUS_REQUEST_NOT_ACCEPTED;
}
- l->current_state = new_lease_state;
+ if (l->current_state != new_lease_state) {
+ l->current_state = new_lease_state;
+ d->modified = true;
+ }
+
+ if ((new_lease_state & ~l->breaking_to_state) != 0) {
+ DEBUG(0, ("lease state %d not fully broken from %d to %d\n",
+ (int)new_lease_state,
+ (int)l->current_state,
+ (int)l->breaking_to_state));
+ *_l = l;
+ return NT_STATUS_OPLOCK_BREAK_IN_PROGRESS;
+ }
+
+ //TODO: verify new_lease_state == l->breaking_to_state ???
+
+ DEBUG(0, ("breaking from %d to %d - expected %d\n",
+ (int)l->current_state, (int)new_lease_state,
+ (int)l->breaking_to_state));
+
l->breaking_to_state = 0;
l->breaking = 0;
diff --git a/source3/locking/proto.h b/source3/locking/proto.h
index 94e9b8f..c48cd89 100644
--- a/source3/locking/proto.h
+++ b/source3/locking/proto.h
@@ -179,10 +179,12 @@ bool fsp_lease_broken(struct share_mode_lock *lck,
struct file_id lck_id,
const struct smb2_lease_key *key,
files_struct *fsp, uint32_t new_lease_state);
+struct share_mode_oplock;
NTSTATUS downgrade_share_lease(struct smbd_server_connection *sconn,
struct share_mode_lock *lck,
const struct smb2_lease_key *key,
- uint32_t new_lease_state);
+ uint32_t new_lease_state,
+ struct share_mode_oplock **_l);
bool get_delete_on_close_token(struct share_mode_lock *lck,
uint32_t name_hash,
const struct security_token **pp_nt_tok,
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index f297ff7..0ce1982 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -251,8 +251,6 @@ NTSTATUS smbd_smb2_send_oplock_break(struct smbXsrv_connection *xconn,
struct smbXsrv_open *op,
uint8_t oplock_level);
NTSTATUS smbd_smb2_send_lease_break(struct smbXsrv_connection *xconn,
- struct smbXsrv_session *session,
- struct smbXsrv_tcon *tcon,
uint16_t new_epoch,
uint32_t lease_flags,
struct smb2_lease_key *lease_key,
@@ -306,7 +304,9 @@ void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
struct deferred_open_record;
/* SMB1 -> SMB2 glue. */
-void send_break_message_smb2(files_struct *fsp, uint32_t break_to);
+void send_break_message_smb2(files_struct *fsp,
+ uint32_t break_from,
+ uint32_t break_to);
struct blocking_lock_record *get_pending_smb2req_blr(struct smbd_smb2_request *smb2req);
bool push_blocking_lock_request_smb2( struct byte_range_lock *br_lck,
struct smb_request *req,
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 804b6f0..33a2bf9 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1430,6 +1430,14 @@ static bool delay_for_oplock(files_struct *fsp,
if (share_mode_stale_pid(d, i)) {
continue;
}
+
+ //if (e->op_type == LEASE_OPLOCK) {
+ // struct share_mode_oplock *o = NULL;
+ // o = &d->leases[e->lease_idx];
+ // if (o->breaking) {
+ // continue;
+ // }
+ //}
send_break_message(fsp->conn->sconn->msg_ctx, e,
e_lease_type & ~SMB2_LEASE_HANDLE);
have_broken = true;
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index 4755ca6..240ff59 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -291,6 +291,40 @@ bool downgrade_oplock(files_struct *fsp)
return ret;
}
+struct downgrade_lease_additional_state {
+ struct tevent_immediate *im;
+ struct smbXsrv_connection *xconn;
+ uint32_t lease_flags;
+ struct smb2_lease_key lease_key;
+ uint32_t current_lease_state;
+ uint32_t new_lease_state;
+ 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->lease_flags,
+ &state->lease_key,
+ state->current_lease_state,
+ state->new_lease_state);
+ 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;
@@ -312,22 +346,59 @@ static struct files_struct *downgrade_lease_fsps(struct files_struct *fsp,
return NULL;
}
-NTSTATUS downgrade_lease(struct smbd_server_connection *sconn,
+NTSTATUS downgrade_lease(struct smbXsrv_connection *xconn,
const struct file_id id,
- const struct smb2_lease_key *key,
+ const struct smb2_lease *lease,
uint32_t lease_state)
{
+ struct smbd_server_connection *sconn = xconn->client->sconn;
+ const struct smb2_lease_key *key = &lease->lease_key;
struct share_mode_lock *lck;
+ struct share_mode_oplock *l = NULL;
NTSTATUS status;
- DEBUG(10, ("%s: Downgrading %s to %x\n", __func__,
+ DEBUG(0, ("%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);
+ status = downgrade_share_lease(sconn, lck, key, lease_state, &l);
+
+ DEBUG(0, ("%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;
+ state->lease_flags = SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED;
+ state->lease_key = l->lease_key;
+ state->current_lease_state = l->current_state;
+ state->new_lease_state = l->breaking_to_state;
+ if (l->lease_version > 1) {
+ state->new_epoch = lease->lease_epoch;
+ }
+
+ tevent_schedule_immediate(state->im, xconn->ev_ctx,
+ downgrade_lease_additional_trigger,
+ state);
+ }
/*
* This sucks. We have to reset fsp->sent_oplock_break on all fsps
@@ -346,6 +417,8 @@ NTSTATUS downgrade_lease(struct smbd_server_connection *sconn,
}
TALLOC_FREE(lck);
+ DEBUG(0, ("%s: Downgrading %s to %x => %s\n", __func__,
+ file_id_string_tos(&id), (unsigned)lease_state, nt_errstr(status)));
return status;
}
@@ -444,6 +517,11 @@ static void oplock_timeout_handler(struct tevent_context *ctx,
{
files_struct *fsp = (files_struct *)private_data;
+ if (fsp->oplock_type == LEASE_OPLOCK) {
+ //TODO
+ SMB_ASSERT(false);
+ }
+
SMB_ASSERT(fsp->sent_oplock_break != NO_BREAK_SENT);
/* Remove the timed event handler. */
@@ -526,7 +604,9 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
struct smbd_server_connection);
struct server_id self = messaging_server_id(sconn->msg_ctx);
struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
+ uint16_t break_from;
uint16_t break_to;
+ bool break_needed = true;
if (data->data == NULL) {
DEBUG(0, ("Got NULL buffer\n"));
@@ -542,7 +622,7 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
message_to_share_mode_entry(&msg, (char *)data->data);
break_to = msg.op_type;
- DEBUG(10, ("Got oplock break to %u message from pid %s: %s/%llu\n",
+ DEBUG(0, ("Got oplock break to %u message from pid %s: %s/%llu\n",
(unsigned)break_to, server_id_str(talloc_tos(), &src),
file_id_string_tos(&msg.id),
(unsigned long long)msg.share_file_id));
@@ -556,13 +636,21 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
return;
}
- if (fsp->sent_oplock_break != NO_BREAK_SENT) {
- /*
- * Nothing to do anymore
- */
- DEBUG(10, ("fsp->sent_oplock_break = %d\n",
- fsp->sent_oplock_break));
- return;
+ if (fsp->oplock_timeout != NULL) {
+// return;
+ }
+
+ break_from = fsp_lease_type(fsp);
+
+ if (fsp->oplock_type != LEASE_OPLOCK) {
+ if (fsp->sent_oplock_break != NO_BREAK_SENT) {
+ /*
+ * Nothing to do anymore
+ */
+ DEBUG(10, ("fsp->sent_oplock_break = %d\n",
+ fsp->sent_oplock_break));
+ return;
+ }
}
if (!(global_client_caps & CAP_LEVEL_II_OPLOCKS)) {
@@ -581,30 +669,15 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
break_to &= ~SMB2_LEASE_READ;
}
- DEBUG(10, ("msg.op_type=%u, break_to=%u\n",
- (unsigned)msg.op_type, (unsigned)break_to));
-
- if (fsp->oplock_type == NO_OPLOCK) {
- DEBUG(3, ("Already downgraded oplock to none on %s: %s\n",
- file_id_string_tos(&fsp->file_id),
- fsp_str_dbg(fsp)));
- return;
- }
- if ((break_to & SMB2_LEASE_READ) &&
- (fsp->oplock_type == LEVEL_II_OPLOCK)) {
- DEBUG(3, ("Already downgraded oplock to level2 on %s: %s\n",
- file_id_string_tos(&fsp->file_id),
- fsp_str_dbg(fsp)));
- return;
- }
-
if (fsp->oplock_type == LEASE_OPLOCK) {
struct share_mode_lock *lck;
int idx;
+ DEBUG(0,("%s: refresh lease state - begin\n", __func__));
lck = get_existing_share_mode_lock(
talloc_tos(), fsp->file_id);
+ DEBUG(0,("%s: refresh lease state - line(%d)\n", __func__, __LINE__));
idx = find_share_mode_oplock(
lck->data,
&fsp->conn->sconn->client->connections->
@@ -613,16 +686,78 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
if (idx != -1) {
struct share_mode_oplock *o;
o = &lck->data->leases[idx];
+
+ DEBUG(0,("%s: refresh lease state - line(%d)\n", __func__, __LINE__));
+ break_from = o->current_state;
+ break_to &= o->current_state;
+
+ if (o->breaking) {
+ DEBUG(0,("%s: refresh lease state - line(%d)\n", __func__, __LINE__));
+ break_to &= o->breaking_to_state;
+ if (o->breaking_to_state != break_to) {
+ DEBUG(0,("%s: refresh lease state - line(%d)\n", __func__, __LINE__));
+ o->breaking_to_state = break_to;
+ lck->data->modified = true;
+ }
+ break_needed = false;
+ } else if (o->current_state == break_to) {
+ DEBUG(0,("%s: refresh lease state - line(%d)\n", __func__, __LINE__));
+ break_needed = false;
+ } else if (o->current_state == SMB2_LEASE_READ) {
+ DEBUG(0,("%s: refresh lease state - line(%d)\n", __func__, __LINE__));
+ o->current_state = SMB2_LEASE_NONE;
+ lck->data->modified = true;
+ } else {
+ DEBUG(0,("%s: refresh lease state - line(%d)\n", __func__, __LINE__));
+ o->breaking = true;
+ o->breaking_to_state = break_to;
+ lck->data->modified = true;
+ }
+
+ /* Need to increment the epoch */
+ if (lck->data->modified) {
+ DEBUG(0,("%s: refresh lease state - line(%d)\n", __func__, __LINE__));
+ o->epoch += 1;
+ }
+
/* Ensure we're in sync with current lease state. */
fsp->lease->lease.lease_state = o->current_state;
- /* Need to increment the epoch */
- o->epoch += 1;
fsp->lease->lease.lease_epoch = o->epoch;
- /* And remember to write it out again.. */
- lck->data->modified = true;
+ if (o->breaking) {
+ DEBUG(0,("%s: refresh lease state - line(%d)\n", __func__, __LINE__));
+ fsp->lease->lease.lease_flags |= SMB2_LEASE_FLAG_BREAK_IN_PROGRESS;
+ } else {
+ DEBUG(0,("%s: refresh lease state - line(%d)\n", __func__, __LINE__));
+ fsp->lease->lease.lease_flags &= ~SMB2_LEASE_FLAG_BREAK_IN_PROGRESS;
+ }
}
+ DEBUG(0,("%s: refresh lease state - line(%d)\n", __func__, __LINE__));
TALLOC_FREE(lck);
+ DEBUG(0,("%s: refresh lease state - end\n", __func__));
+ }
+
+ if (!break_needed) {
+ DEBUG(0,("%s: skip break\n", __func__));
+ return;
+ }
+
+ if ((break_from == SMB2_LEASE_NONE) && !break_needed) {
+ DEBUG(3, ("Already downgraded oplock to none on %s: %s\n",
+ file_id_string_tos(&fsp->file_id),
+ fsp_str_dbg(fsp)));
+ return;
+ }
+
+ DEBUG(0, ("msg.op_type=%u, break_to=%u\n",
+ (unsigned)msg.op_type, (unsigned)break_to));
+
+ if ((break_from == break_to) && !break_needed) {
+ DEBUG(3, ("Already downgraded oplock to %u on %s: %s\n",
+ (unsigned)break_to,
+ file_id_string_tos(&fsp->file_id),
+ fsp_str_dbg(fsp)));
+ return;
}
/* Need to wait before sending a break
@@ -632,33 +767,31 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
}
if (sconn->using_smb2) {
- send_break_message_smb2(fsp, break_to);
+ DEBUG(0,("%s: send_break_message_smb2 \n", __func__));
+ send_break_message_smb2(fsp, break_from, break_to);
} else {
send_break_message_smb1(fsp, (break_to & SMB2_LEASE_READ) ?
OPLOCKLEVEL_II : OPLOCKLEVEL_NONE);
}
- if ((fsp_lease_type(fsp) == SMB2_LEASE_READ) &&
+ if ((break_from == SMB2_LEASE_READ) &&
(break_to == SMB2_LEASE_NONE)) {
/*
* This is an async break without a reply and thus no timeout
+ *
+ * leases are handled above.
*/
- if (fsp->oplock_type == LEASE_OPLOCK) {
- /*
- * We must leave the lease around, it might be
- * upgraded later
- */
- downgrade_lease(fsp->conn->sconn, fsp->file_id,
- &fsp->lease->lease.lease_key,
- break_to);
- } else {
+ if (fsp->oplock_type != LEASE_OPLOCK) {
remove_oplock(fsp);
}
return;
}
- fsp->sent_oplock_break = (break_to & SMB2_LEASE_READ) ?
- LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT;
+ if (fsp->oplock_type != LEASE_OPLOCK) {
+ fsp->sent_oplock_break = (break_to & SMB2_LEASE_READ) ?
+ LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT;
+ }
+ DEBUG(0,("%s: add_oplock_timeout_handler \n", __func__));
add_oplock_timeout_handler(fsp);
}
@@ -713,7 +846,7 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx,
}
if (sconn->using_smb2) {
- send_break_message_smb2(fsp, OPLOCKLEVEL_NONE);
+ send_break_message_smb2(fsp, 0, OPLOCKLEVEL_NONE);
} else {
send_break_message_smb1(fsp, OPLOCKLEVEL_NONE);
}
@@ -937,23 +1070,6 @@ done:
return;
}
-bool break_in_progress(const files_struct *fsp)
-{
- files_struct *new_fsp;
-
- for (new_fsp = file_find_di_first(fsp->conn->sconn, fsp->file_id);
- new_fsp != NULL;
- new_fsp = file_find_di_next(new_fsp)) {
- if (new_fsp == fsp) {
- continue;
- }
- if (new_fsp->sent_oplock_break != NO_BREAK_SENT) {
- return true;
- }
- }
- return false;
-}
-
void smbd_contend_level2_oplocks_begin(files_struct *fsp,
enum level2_contention_type type)
{
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index c8e404e..c4f8920 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -667,11 +667,10 @@ 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);
-NTSTATUS downgrade_lease(struct smbd_server_connection *sconn,
+NTSTATUS downgrade_lease(struct smbXsrv_connection *xconn,
const struct file_id id,
- const struct smb2_lease_key *key,
+ const struct smb2_lease *lease,
uint32_t lease_state);
-bool break_in_progress(const files_struct *fsp);
void contend_level2_oplocks_begin(files_struct *fsp,
enum level2_contention_type type);
void contend_level2_oplocks_end(files_struct *fsp,
diff --git a/source3/smbd/smb2_break.c b/source3/smbd/smb2_break.c
index 9ab118d..f9fce5a 100644
--- a/source3/smbd/smb2_break.c
+++ b/source3/smbd/smb2_break.c
@@ -354,8 +354,15 @@ static struct tevent_req *smbd_smb2_lease_break_send(
return tevent_req_post(req, ev);
}
- status = downgrade_lease(smb2_req->sconn, fsp->file_id, &in_lease_key,
- in_lease_state);
+ status = downgrade_lease(smb2_req->xconn, fsp->file_id,
+ &fsp->lease->lease, in_lease_state);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_BREAK_IN_PROGRESS)) {
+ /*
+ * here we keep the fsp->oplock_timeout
+ */
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
if (tevent_req_nterror(req, status)) {
DEBUG(10, ("downgrade_lease returned %s\n",
nt_errstr(status)));
@@ -386,7 +393,9 @@ static NTSTATUS smbd_smb2_lease_break_recv(struct tevent_req *req,
SMB2 OPLOCK_BREAK_NOTIFICATION.
*********************************************************/
-void send_break_message_smb2(files_struct *fsp, uint32_t break_to)
+void send_break_message_smb2(files_struct *fsp,
+ uint32_t break_from,
+ uint32_t break_to)
{
NTSTATUS status;
struct smbXsrv_connection *xconn = NULL;
@@ -425,11 +434,12 @@ void send_break_message_smb2(files_struct *fsp, uint32_t break_to)
(unsigned int)break_to ));
if (fsp->oplock_type == LEASE_OPLOCK) {
- bool no_ack;
+ uint32_t break_flags = 0;
uint16_t new_epoch;
- no_ack = ((fsp->lease->lease.lease_state == SMB2_LEASE_READ) &&
- (break_to == SMB2_LEASE_NONE));
+ if (fsp->lease->lease.lease_state != SMB2_LEASE_NONE) {
+ break_flags = SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED;
+ }
if (fsp->lease->lease.lease_version > 1) {
new_epoch = fsp->lease->lease.lease_epoch;
@@ -437,11 +447,9 @@ void send_break_message_smb2(files_struct *fsp, uint32_t break_to)
new_epoch = 0;
}
- status = smbd_smb2_send_lease_break(
- xconn, session, fsp->conn->tcon, new_epoch,
- no_ack ? 0 : SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED,
- &fsp->lease->lease.lease_key,
- fsp->lease->lease.lease_state, break_to);
+ status = smbd_smb2_send_lease_break(xconn, new_epoch, break_flags,
+ &fsp->lease->lease.lease_key,
+ break_from, break_to);
} else {
uint8_t smb2_oplock_level;
smb2_oplock_level = (break_to & SMB2_LEASE_READ) ?
diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 482bb66..91583fa 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -1204,14 +1204,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
uint8_t buf[52];
lease = result->lease->lease;
- lease.lease_flags &=
- SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET;
-
- /* Is there a break in progress ? */
- if (break_in_progress(result)) {
- lease.lease_flags |=
- SMB2_LEASE_FLAG_BREAK_IN_PROGRESS;
- }
lease_len = sizeof(buf);
if (lease.lease_version == 1) {
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 36ac0d7..16eed90 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2760,14 +2760,19 @@ static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
size_t body_len)
{
struct smbd_smb2_send_break_state *state;
- bool do_encryption = session->global->encryption_required;
+ bool do_encryption = false;
+ uint64_t session_wire_id = 0;
uint64_t nonce_high = 0;
uint64_t nonce_low = 0;
NTSTATUS status;
size_t statelen;
- if (tcon->global->encryption_required) {
- do_encryption = true;
+ if (session != NULL) {
+ session_wire_id = session->global->session_wire_id;
+ do_encryption = session->global->encryption_required;
+ if (tcon->global->encryption_required) {
+ do_encryption = true;
+ }
}
statelen = offsetof(struct smbd_smb2_send_break_state, body) +
@@ -2793,7 +2798,7 @@ static NTSTATUS smbd_smb2_send_break(struct smbXsrv_connection *xconn,
SIVAL(state->tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
SBVAL(state->tf, SMB2_TF_NONCE+0, nonce_low);
SBVAL(state->tf, SMB2_TF_NONCE+8, nonce_high);
- SBVAL(state->tf, SMB2_TF_SESSION_ID, session->global->session_wire_id);
+ SBVAL(state->tf, SMB2_TF_SESSION_ID, session_wire_id);
SIVAL(state->hdr, 0, SMB2_MAGIC);
SSVAL(state->hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
@@ -2889,8 +2894,6 @@ NTSTATUS smbd_smb2_send_oplock_break(struct smbXsrv_connection *xconn,
}
NTSTATUS smbd_smb2_send_lease_break(struct smbXsrv_connection *xconn,
- struct smbXsrv_session *session,
- struct smbXsrv_tcon *tcon,
uint16_t new_epoch,
uint32_t lease_flags,
struct smb2_lease_key *lease_key,
@@ -2910,7 +2913,7 @@ NTSTATUS smbd_smb2_send_lease_break(struct smbXsrv_connection *xconn,
SIVAL(body, 0x24, 0); /* AccessMaskHint, MUST be 0 */
SIVAL(body, 0x28, 0); /* ShareMaskHint, MUST be 0 */
- return smbd_smb2_send_break(xconn, session, tcon, body, sizeof(body));
+ return smbd_smb2_send_break(xconn, NULL, NULL, body, sizeof(body));
}
static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)
--
1.9.1
From 47ca1ad0bc82ab038f8f1026aeb794b4156e536f Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 14 Nov 2014 09:18:51 +0100
Subject: [PATCH 2/6] grant_fsp_lease don't upgrade when in breaking state
---
source3/smbd/open.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 33a2bf9..29bb463 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1660,6 +1660,11 @@ static NTSTATUS grant_fsp_lease(files_struct *fsp, struct share_mode_data *d,
*/
do_upgrade &= (granted == requested);
+ /*
+ * only upgrade if we are not in breaking state
+ */
+ do_upgrade &= !o->breaking;
+
DEBUG(10, ("existing=%"PRIu32", requested=%"PRIu32", "
"granted=%"PRIu32", do_upgrade=%d\n",
existing, requested, granted, (int)do_upgrade));
@@ -1667,9 +1672,16 @@ static NTSTATUS grant_fsp_lease(files_struct *fsp, struct share_mode_data *d,
if (do_upgrade) {
o->current_state = granted;
o->epoch += 1;
- fsp->lease->lease.lease_epoch = o->epoch;
}
+
+ /* Ensure we're in sync with current lease state. */
fsp->lease->lease.lease_state = o->current_state;
+ fsp->lease->lease.lease_epoch = o->epoch;
+ if (o->breaking) {
+ fsp->lease->lease.lease_flags |= SMB2_LEASE_FLAG_BREAK_IN_PROGRESS;
+ } else {
+ fsp->lease->lease.lease_flags &= ~SMB2_LEASE_FLAG_BREAK_IN_PROGRESS;
+ }
return NT_STATUS_OK;
}
--
1.9.1
From 1c355eb1a8b653bdf0dbd4342422f53a035155ab Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 14 Nov 2014 03:18:32 +0100
Subject: [PATCH 3/6] SQ only copy the required fields to fsp->lease->lease
---
source3/smbd/open.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 29bb463..a2a5de1 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1699,23 +1699,24 @@ static NTSTATUS grant_fsp_lease(files_struct *fsp, struct share_mode_data *d,
}
d->leases = tmp;
- fsp->lease = talloc(fsp->conn->sconn, struct fsp_lease);
+ fsp->lease = talloc_zero(fsp->conn->sconn, struct fsp_lease);
if (fsp->lease == NULL) {
return NT_STATUS_INSUFFICIENT_RESOURCES;
}
fsp->lease->ref_count = 1;
- fsp->lease->lease = *lease;
+ fsp->lease->lease.lease_version = lease->lease_version;
+ fsp->lease->lease.lease_key = lease->lease_key;
fsp->lease->lease.lease_state = granted;
- fsp->lease->lease.lease_epoch += 1;
+ fsp->lease->lease.lease_epoch = lease->lease_epoch + 1;
*p_lease_idx = d->num_leases;
d->leases[d->num_leases] = (struct share_mode_oplock) {
.client_guid = *client_guid,
.lease_key = fsp->lease->lease.lease_key,
+ .current_state = fsp->lease->lease.lease_state,
.lease_version = fsp->lease->lease.lease_version,
.epoch = fsp->lease->lease.lease_epoch,
- .current_state = granted,
};
status = leases_db_add(client_guid, &lease->lease_key,
--
1.9.1
From 2c17e1ce00fdd93b4e959f35414c0adfd1d94d21 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 14 Nov 2014 03:10:16 +0100
Subject: [PATCH 4/6] TODO lease->lease_flags &=
~SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET not needed???
---
libcli/smb/smb2_lease.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/libcli/smb/smb2_lease.c b/libcli/smb/smb2_lease.c
index 7705256..fc641ff 100644
--- a/libcli/smb/smb2_lease.c
+++ b/libcli/smb/smb2_lease.c
@@ -48,7 +48,6 @@ ssize_t smb2_lease_pull(const uint8_t *buf, size_t len,
switch (version) {
case 1:
ZERO_STRUCT(lease->parent_lease_key);
- lease->lease_flags &= ~SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET;
lease->lease_epoch = 0;
break;
case 2:
--
1.9.1
From 021abf204660b82484e76dad60f754d68826c049 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 14 Nov 2014 08:56:38 +0100
Subject: [PATCH 5/6] delay_for_oplock only read...
---
source3/smbd/open.c | 116 +++++++++++++++++++++-------------------------------
1 file changed, 47 insertions(+), 69 deletions(-)
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index a2a5de1..5b13bf7 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1416,41 +1416,6 @@ static bool delay_for_oplock(files_struct *fsp,
return false;
}
- if (have_sharing_violation) {
- for (i=0; i<d->num_share_modes; i++) {
- struct share_mode_entry *e = &d->share_modes[i];
- uint32_t e_lease_type = get_lease_type(d, e);
-
- if (!(e_lease_type & SMB2_LEASE_HANDLE)) {
- continue;
- }
- if (is_same_lease(fsp, d, e, lease)) {
- continue;
- }
- if (share_mode_stale_pid(d, i)) {
- continue;
- }
-
- //if (e->op_type == LEASE_OPLOCK) {
- // struct share_mode_oplock *o = NULL;
- // o = &d->leases[e->lease_idx];
- // if (o->breaking) {
- // continue;
- // }
- //}
- send_break_message(fsp->conn->sconn->msg_ctx, e,
- e_lease_type & ~SMB2_LEASE_HANDLE);
- have_broken = true;
- }
- }
-
- if (have_broken) {
- return true;
- }
- if (have_sharing_violation) {
- return false;
- }
-
switch (create_disposition) {
case FILE_SUPERSEDE:
case FILE_OVERWRITE:
@@ -1464,56 +1429,69 @@ static bool delay_for_oplock(files_struct *fsp,
for (i=0; i<d->num_share_modes; i++) {
struct share_mode_entry *e = &d->share_modes[i];
+ struct share_mode_oplock *o = NULL;
uint32_t e_lease_type = get_lease_type(d, e);
+ uint32_t break_to;
+
+ if (e->op_type == LEASE_OPLOCK) {
+ o = &d->leases[e->lease_idx];
+ }
+
+ if (have_sharing_violation) {
+ break_to = e_lease_type & ~SMB2_LEASE_HANDLE;
+ } else {
+ break_to = e_lease_type & ~SMB2_LEASE_WRITE;
+ }
+
+ if (e->op_type != LEASE_OPLOCK) {
+ break_to &= ~(SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
+ }
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 & SMB2_LEASE_WRITE) {
- uint32_t break_to;
+ if (lease != NULL && o != NULL) {
+ bool ign;
- if (share_mode_stale_pid(d, i)) {
- return false;
+ ign = smb2_lease_equal(fsp_client_guid(fsp),
+ &lease->lease_key,
+ &o->client_guid,
+ &o->lease_key);
+ if (ign) {
+ continue;
}
- if ((e->op_type == LEASE_OPLOCK) &&
- (lease != NULL) &&
- smb2_lease_equal(fsp_client_guid(fsp),
- &lease->lease_key,
- &d->leases[e->lease_idx].client_guid,
- &d->leases[e->lease_idx].lease_key)) {
- return false;
+ }
+
+ if ((e_lease_type & ~break_to) == 0) {
+ if (o == NULL) {
+ continue;
}
- break_to = e_lease_type & ~SMB2_LEASE_WRITE;
- if (will_overwrite) {
- /*
- * There's no H only lease that we could break
- * to
- */
- break_to = SMB2_LEASE_NONE;
+ if (o->breaking) {
+ have_broken = true;
}
+ continue;
+ }
- DEBUG(10, ("breaking SMB2_LEASE_WRITE to %d\n",
- (int)break_to));
- send_break_message(fsp->conn->sconn->msg_ctx, e,
- break_to);
- return true;
+ if (share_mode_stale_pid(d, i)) {
+ continue;
}
- if (will_overwrite && (e_lease_type & SMB2_LEASE_READ)) {
- if (share_mode_stale_pid(d, i)) {
- continue;
+ if (will_overwrite) {
+ if (e->op_type == LEASE_OPLOCK) {
+ break_to &= ~SMB2_LEASE_HANDLE;
+ } else {
+ break_to &= ~SMB2_LEASE_READ;
}
- DEBUG(10, ("breaking SMB2_LEASE_READ\n"));
- send_break_message(fsp->conn->sconn->msg_ctx, e,
- SMB2_LEASE_NONE);
- /*
- * This is an async break. No need to wait for a
- * response.
- */
- continue;
}
+
+ DEBUG(10, ("breaking SMB2_LEASE_WRITE to %d\n",
+ (int)break_to));
+ send_break_message(fsp->conn->sconn->msg_ctx, e,
+ break_to);
+ have_broken = true;
+ continue;
}
return have_broken;
--
1.9.1
From 5936a0f5f9b0f33cbeb759e3f98a144a919f63f7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 14 Nov 2014 09:24:14 +0100
Subject: [PATCH 6/6] Revert "skip test_lease_breaking2"
This reverts commit 3a9ca0328059284c8c1e2619ab44acdee73bce62.
---
source4/torture/smb2/lease.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/source4/torture/smb2/lease.c b/source4/torture/smb2/lease.c
index 2b47611..221d45c 100644
--- a/source4/torture/smb2/lease.c
+++ b/source4/torture/smb2/lease.c
@@ -2373,7 +2373,7 @@ struct torture_suite *torture_smb2_lease_init(void)
torture_suite_add_1smb2_test(suite, "oplock", test_lease_oplock);
torture_suite_add_1smb2_test(suite, "multibreak", test_lease_multibreak);
torture_suite_add_1smb2_test(suite, "breaking1", test_lease_breaking1);
- //torture_suite_add_1smb2_test(suite, "breaking2", test_lease_breaking2);
+ torture_suite_add_1smb2_test(suite, "breaking2", test_lease_breaking2);
torture_suite_add_1smb2_test(suite, "complex1", test_lease_complex1);
torture_suite_add_1smb2_test(suite, "v2_request_parent",
test_lease_v2_request_parent);
--
1.9.1
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20141114/53437782/attachment.pgp>
More information about the samba-technical
mailing list