summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2013-09-26 16:15:31 -0700
committerStefan Metzmacher <metze@samba.org>2013-10-23 11:58:56 +0200
commit20669d4a75386eef4fdcea07fb99812c4e09de13 (patch)
tree403e4ca912e16316e21f6467cc3e02886d03f4d8 /source3/smbd
parentccc808e0d72be5933ae2449ee8ee56262e631b72 (diff)
downloadsamba-20669d4a75386eef4fdcea07fb99812c4e09de13.tar.gz
samba-20669d4a75386eef4fdcea07fb99812c4e09de13.tar.bz2
samba-20669d4a75386eef4fdcea07fb99812c4e09de13.zip
smbd: Fix raw.batch.exclusive[59]
The level we have to break to depend on the breakers create_disposition: If we overwrite, we have to break to none. This patch overloads the "op_type" field in the break message we send across to the smbd holding the oplock with the oplock level we want to break to. Because it depends on the create_disposition in the breaking open, only the breaker can make that decision. We might want to use a different mechanism for this in the future, but for now using the op_type field seems acceptable to me. Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/open.c29
-rw-r--r--source3/smbd/oplock.c10
2 files changed, 29 insertions, 10 deletions
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index a9147f80b8..494145397d 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1168,7 +1168,8 @@ static NTSTATUS open_mode_check(connection_struct *conn,
*/
static NTSTATUS send_break_message(struct messaging_context *msg_ctx,
- const struct share_mode_entry *exclusive)
+ const struct share_mode_entry *exclusive,
+ uint16_t break_to)
{
NTSTATUS status;
char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
@@ -1179,6 +1180,9 @@ static NTSTATUS send_break_message(struct messaging_context *msg_ctx,
/* Create the message. */
share_mode_entry_to_message(msg, exclusive);
+ /* Overload entry->op_type */
+ SSVAL(msg,OP_BREAK_MSG_OP_TYPE_OFFSET, break_to);
+
status = messaging_send_buf(msg_ctx, exclusive->pid,
MSG_SMB_BREAK_REQUEST,
(uint8 *)msg, sizeof(msg));
@@ -1292,12 +1296,14 @@ static bool validate_oplock_types(struct share_mode_lock *lck)
static bool delay_for_oplock(files_struct *fsp,
int oplock_request,
struct share_mode_lock *lck,
- bool have_sharing_violation)
+ bool have_sharing_violation,
+ uint32_t create_disposition)
{
struct share_mode_data *d = lck->data;
struct share_mode_entry *entry;
uint32_t num_non_stat_opens = 0;
uint32_t i;
+ uint16_t break_to;
if ((oplock_request & INTERNAL_OPEN_ONLY) || is_stat_open(fsp->access_mask)) {
return false;
@@ -1342,11 +1348,21 @@ static bool delay_for_oplock(files_struct *fsp,
return false;
}
+ switch (create_disposition) {
+ case FILE_SUPERSEDE:
+ case FILE_OVERWRITE_IF:
+ break_to = NO_OPLOCK;
+ break;
+ default:
+ break_to = LEVEL_II_OPLOCK;
+ break;
+ }
+
if (have_sharing_violation && (entry->op_type & BATCH_OPLOCK)) {
if (share_mode_stale_pid(d, 0)) {
return false;
}
- send_break_message(fsp->conn->sconn->msg_ctx, entry);
+ send_break_message(fsp->conn->sconn->msg_ctx, entry, break_to);
return true;
}
if (have_sharing_violation) {
@@ -1366,7 +1382,7 @@ static bool delay_for_oplock(files_struct *fsp,
return false;
}
- send_break_message(fsp->conn->sconn->msg_ctx, entry);
+ send_break_message(fsp->conn->sconn->msg_ctx, entry, break_to);
return true;
}
@@ -2343,7 +2359,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
smb_panic("validate_oplock_types failed");
}
- if (delay_for_oplock(fsp, 0, lck, false)) {
+ if (delay_for_oplock(fsp, 0, lck, false, create_disposition)) {
schedule_defer_open(lck, request_time, req);
TALLOC_FREE(lck);
DEBUG(10, ("Sent oplock break request to kernel "
@@ -2455,7 +2471,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
if ((req != NULL) &&
delay_for_oplock(
fsp, oplock_request, lck,
- NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION))) {
+ NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION),
+ create_disposition)) {
schedule_defer_open(lck, request_time, req);
TALLOC_FREE(lck);
fd_close(fsp);
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index e2880c5de9..f1b89b4650 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -510,6 +510,7 @@ 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_to;
if (data->data == NULL) {
DEBUG(0, ("Got NULL buffer\n"));
@@ -523,9 +524,10 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
/* De-linearize incoming message. */
message_to_share_mode_entry(&msg, (char *)data->data);
+ break_to = msg.op_type;
- DEBUG(10, ("Got oplock break message from pid %s: %s/%llu\n",
- server_id_str(talloc_tos(), &src),
+ DEBUG(10, ("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));
@@ -545,8 +547,7 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
return;
}
- if (EXCLUSIVE_OPLOCK_TYPE(msg.op_type) &&
- !EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ if (break_to == fsp->oplock_type) {
DEBUG(3, ("Already downgraded oplock on %s: %s\n",
file_id_string_tos(&fsp->file_id),
fsp_str_dbg(fsp)));
@@ -556,6 +557,7 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
use_kernel = lp_kernel_oplocks(SNUM(fsp->conn)) && koplocks;
if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) &&
+ (break_to != NO_OPLOCK) &&
!(use_kernel && !(koplocks->flags & KOPLOCKS_LEVEL2_SUPPORTED)) &&
lp_level2_oplocks(SNUM(fsp->conn))) {
break_to_level2 = True;