X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fsmbd%2Foplock.c;h=a414b72d3134fed4ed6aa44cad32f1b47ca7bd1b;hb=6fc8dc98ab0de1f2de7d086eee299d89f0527b6e;hp=dd8d5372fb4995de476627243a1fe15dbbb5f98c;hpb=5a8d70d465f28ae02f4df7a3c2905e028c2e3142;p=kai%2Fsamba.git diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c index dd8d5372fb4..a414b72d313 100644 --- a/source3/smbd/oplock.c +++ b/source3/smbd/oplock.c @@ -4,24 +4,27 @@ Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Jeremy Allison 1998 - 2001 Copyright (C) Volker Lendecke 2005 - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ #define DBGC_CLASS DBGC_LOCKING #include "includes.h" +#include "smbd/smbd.h" #include "smbd/globals.h" +#include "messages.h" +#include "../librpc/gen_ndr/open_files.h" /**************************************************************************** Get the number of current exclusive oplocks. @@ -46,24 +49,28 @@ void break_kernel_oplock(struct messaging_context *msg_ctx, files_struct *fsp) /* Don't need to be root here as we're only ever sending to ourselves. */ - messaging_send_buf(msg_ctx, procid_self(), + messaging_send_buf(msg_ctx, messaging_server_id(msg_ctx), MSG_SMB_KERNEL_BREAK, msg, MSG_SMB_KERNEL_BREAK_SIZE); } /**************************************************************************** - Attempt to set an oplock on a file. Always succeeds if kernel oplocks are - disabled (just sets flags). Returns True if oplock set. + Attempt to set an oplock on a file. Succeeds if kernel oplocks are + disabled (just sets flags) and no byte-range locks in the file. Returns True + if oplock set. ****************************************************************************/ bool set_file_oplock(files_struct *fsp, int oplock_type) { - if ((fsp->oplock_type == LEVEL_II_OPLOCK) - && koplocks && !(koplocks->flags & KOPLOCKS_LEVEL2_SUPPORTED)) { - DEBUG(10, ("Refusing level2 oplock, kernel oplocks don't " - "support them\n")); - return false; + if (fsp->oplock_type == LEVEL_II_OPLOCK) { + if (koplocks && + !(koplocks->flags & KOPLOCKS_LEVEL2_SUPPORTED)) { + DEBUG(10, ("Refusing level2 oplock, kernel oplocks " + "don't support them\n")); + return false; + } } + if ((fsp->oplock_type != NO_OPLOCK) && (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK) && koplocks && @@ -118,6 +125,7 @@ void release_file_oplock(files_struct *fsp) fsp->sent_oplock_break = NO_BREAK_SENT; flush_write_cache(fsp, OPLOCK_RELEASE_FLUSH); + delete_write_cache(fsp); TALLOC_FREE(fsp->oplock_timeout); } @@ -214,10 +222,10 @@ bool should_notify_deferred_opens() Set up an oplock break message. ****************************************************************************/ -static char *new_break_smb_message(TALLOC_CTX *mem_ctx, - files_struct *fsp, uint8 cmd) +static char *new_break_message_smb1(TALLOC_CTX *mem_ctx, + files_struct *fsp, int cmd) { - char *result = TALLOC_ARRAY(mem_ctx, char, smb_size + 8*2 + 0); + char *result = talloc_array(mem_ctx, char, smb_size + 8*2 + 0); if (result == NULL) { DEBUG(0, ("talloc failed\n")); @@ -255,7 +263,9 @@ static void wait_before_sending_break(void) Ensure that we have a valid oplock. ****************************************************************************/ -static files_struct *initial_break_processing(struct file_id id, unsigned long file_id) +static files_struct *initial_break_processing( + struct smbd_server_connection *sconn, struct file_id id, + unsigned long file_id) { files_struct *fsp = NULL; @@ -272,7 +282,7 @@ static files_struct *initial_break_processing(struct file_id id, unsigned long f * we have an oplock on it. */ - fsp = file_find_dif(id, file_id); + fsp = file_find_dif(sconn, id, file_id); if(fsp == NULL) { /* The file could have been closed in the meantime - return success. */ @@ -319,7 +329,6 @@ static void oplock_timeout_handler(struct event_context *ctx, TALLOC_FREE(fsp->oplock_timeout); DEBUG(0, ("Oplock break failed for file %s -- replying anyway\n", fsp_str_dbg(fsp))); - global_client_failed_oplock_break = True; remove_oplock(fsp); reply_to_oplock_break_requests(fsp); } @@ -345,18 +354,39 @@ static void add_oplock_timeout_handler(files_struct *fsp) } fsp->oplock_timeout = - event_add_timed(smbd_event_context(), NULL, - timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0), - oplock_timeout_handler, fsp); + tevent_add_timer(fsp->conn->sconn->ev_ctx, fsp, + timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0), + oplock_timeout_handler, fsp); if (fsp->oplock_timeout == NULL) { DEBUG(0, ("Could not add oplock timeout handler\n")); } } +static void send_break_message_smb1(files_struct *fsp, int level) +{ + char *break_msg = new_break_message_smb1(talloc_tos(), + fsp, + level); + if (break_msg == NULL) { + exit_server("Could not talloc break_msg\n"); + } + + show_msg(break_msg); + if (!srv_send_smb(fsp->conn->sconn, + break_msg, false, 0, + IS_CONN_ENCRYPTED(fsp->conn), + NULL)) { + exit_server_cleanly("send_break_message_smb1: " + "srv_send_smb failed."); + } + + TALLOC_FREE(break_msg); +} + void break_level2_to_none_async(files_struct *fsp) { - char *break_msg; + struct smbd_server_connection *sconn = fsp->conn->sconn; if (fsp->oplock_type == NO_OPLOCK) { /* We already got a "break to none" message and we've handled @@ -382,24 +412,14 @@ void break_level2_to_none_async(files_struct *fsp) fsp_str_dbg(fsp))); /* Now send a break to none message to our client. */ - break_msg = new_break_smb_message(NULL, fsp, OPLOCKLEVEL_NONE); - if (break_msg == NULL) { - exit_server("Could not talloc break_msg\n"); - } - - show_msg(break_msg); - if (!srv_send_smb(smbd_server_fd(), - break_msg, false, 0, - IS_CONN_ENCRYPTED(fsp->conn), - NULL)) { - exit_server_cleanly("oplock_break: srv_send_smb failed."); + if (sconn->using_smb2) { + send_break_message_smb2(fsp, OPLOCKLEVEL_NONE); + } else { + send_break_message_smb1(fsp, OPLOCKLEVEL_NONE); } - TALLOC_FREE(break_msg); - /* Async level2 request, don't send a reply, just remove the oplock. */ remove_oplock(fsp); - } /******************************************************************* @@ -418,6 +438,13 @@ void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx { struct share_mode_entry msg; files_struct *fsp; + struct smbd_server_connection *sconn = + talloc_get_type(private_data, + struct smbd_server_connection); + + if (sconn == NULL) { + return; + } if (data->data == NULL) { DEBUG(0, ("Got NULL buffer\n")); @@ -433,10 +460,11 @@ void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx message_to_share_mode_entry(&msg, (char *)data->data); DEBUG(10, ("Got oplock async level 2 break message from pid %s: " - "%s/%lu\n", procid_str(debug_ctx(), &src), - file_id_string_tos(&msg.id), msg.share_file_id)); + "%s/%llu\n", server_id_str(talloc_tos(), &src), + file_id_string_tos(&msg.id), + (unsigned long long)msg.share_file_id)); - fsp = initial_break_processing(msg.id, msg.share_file_id); + fsp = initial_break_processing(sconn, msg.id, msg.share_file_id); if (fsp == NULL) { /* We hit a race here. Break messages are sent, and before we @@ -461,8 +489,14 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, { struct share_mode_entry msg; files_struct *fsp; - char *break_msg; bool break_to_level2 = False; + struct smbd_server_connection *sconn = + talloc_get_type(private_data, + struct smbd_server_connection); + + if (sconn == NULL) { + return; + } if (data->data == NULL) { DEBUG(0, ("Got NULL buffer\n")); @@ -477,14 +511,15 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, /* De-linearize incoming message. */ message_to_share_mode_entry(&msg, (char *)data->data); - DEBUG(10, ("Got oplock break message from pid %s: %s/%lu\n", - procid_str(debug_ctx(), &src), file_id_string_tos(&msg.id), - msg.share_file_id)); + DEBUG(10, ("Got oplock break message from pid %s: %s/%llu\n", + server_id_str(talloc_tos(), &src), + file_id_string_tos(&msg.id), + (unsigned long long)msg.share_file_id)); - fsp = initial_break_processing(msg.id, msg.share_file_id); + fsp = initial_break_processing(sconn, msg.id, msg.share_file_id); if (fsp == NULL) { - /* a We hit race here. Break messages are sent, and before we + /* We hit a race here. Break messages are sent, and before we * get to process this message, we have closed the file. Reply * with 'ok, oplock broken' */ DEBUG(3, ("Did not find fsp\n")); @@ -525,27 +560,20 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, break_to_level2 = True; } - break_msg = new_break_smb_message(NULL, fsp, break_to_level2 ? - OPLOCKLEVEL_II : OPLOCKLEVEL_NONE); - if (break_msg == NULL) { - exit_server("Could not talloc break_msg\n"); - } - - /* Need to wait before sending a break message if we sent ourselves this message. */ + /* Need to wait before sending a break + message if we sent ourselves this message. */ if (procid_is_me(&src)) { wait_before_sending_break(); } - show_msg(break_msg); - if (!srv_send_smb(smbd_server_fd(), - break_msg, false, 0, - IS_CONN_ENCRYPTED(fsp->conn), - NULL)) { - exit_server_cleanly("oplock_break: srv_send_smb failed."); + if (sconn->using_smb2) { + send_break_message_smb2(fsp, break_to_level2 ? + OPLOCKLEVEL_II : OPLOCKLEVEL_NONE); + } else { + send_break_message_smb1(fsp, break_to_level2 ? + OPLOCKLEVEL_II : OPLOCKLEVEL_NONE); } - TALLOC_FREE(break_msg); - fsp->sent_oplock_break = break_to_level2 ? LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT; msg.pid = src; @@ -569,7 +597,13 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx, struct file_id id; unsigned long file_id; files_struct *fsp; - char *break_msg; + struct smbd_server_connection *sconn = + talloc_get_type(private_data, + struct smbd_server_connection); + + if (sconn == NULL) { + return; + } if (data->data == NULL) { DEBUG(0, ("Got NULL buffer\n")); @@ -586,10 +620,10 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx, file_id = (unsigned long)IVAL(data->data, 24); DEBUG(10, ("Got kernel oplock break message from pid %s: %s/%u\n", - procid_str(debug_ctx(), &src), file_id_string_tos(&id), + server_id_str(talloc_tos(), &src), file_id_string_tos(&id), (unsigned int)file_id)); - fsp = initial_break_processing(id, file_id); + fsp = initial_break_processing(sconn, id, file_id); if (fsp == NULL) { DEBUG(3, ("Got a kernel oplock break message for a file " @@ -604,21 +638,12 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx, return; } - break_msg = new_break_smb_message(NULL, fsp, OPLOCKLEVEL_NONE); - if (break_msg == NULL) { - exit_server("Could not talloc break_msg\n"); - } - - show_msg(break_msg); - if (!srv_send_smb(smbd_server_fd(), - break_msg, false, 0, - IS_CONN_ENCRYPTED(fsp->conn), - NULL)) { - exit_server_cleanly("oplock_break: srv_send_smb failed."); + if (sconn->using_smb2) { + send_break_message_smb2(fsp, OPLOCKLEVEL_NONE); + } else { + send_break_message_smb1(fsp, OPLOCKLEVEL_NONE); } - TALLOC_FREE(break_msg); - fsp->sent_oplock_break = BREAK_TO_NONE_SENT; add_oplock_timeout_handler(fsp); @@ -643,7 +668,7 @@ void reply_to_oplock_break_requests(files_struct *fsp) share_mode_entry_to_message(msg, e); - messaging_send_buf(smbd_messaging_context(), e->pid, + messaging_send_buf(fsp->conn->sconn->msg_ctx, e->pid, MSG_SMB_BREAK_RESPONSE, (uint8 *)msg, MSG_SMB_SHARE_MODE_ENTRY_SIZE); @@ -666,6 +691,13 @@ static void process_oplock_break_response(struct messaging_context *msg_ctx, DATA_BLOB *data) { struct share_mode_entry msg; + struct smbd_server_connection *sconn = + talloc_get_type(private_data, + struct smbd_server_connection); + + if (sconn == NULL) { + return; + } if (data->data == NULL) { DEBUG(0, ("Got NULL buffer\n")); @@ -681,12 +713,13 @@ static void process_oplock_break_response(struct messaging_context *msg_ctx, /* De-linearize incoming message. */ message_to_share_mode_entry(&msg, (char *)data->data); - DEBUG(10, ("Got oplock break response from pid %s: %s/%lu mid %u\n", - procid_str(debug_ctx(), &src), file_id_string_tos(&msg.id), - msg.share_file_id, (unsigned int)msg.op_mid)); + DEBUG(10, ("Got oplock break response from pid %s: %s/%llu mid %llu\n", + server_id_str(talloc_tos(), &src), + file_id_string_tos(&msg.id), + (unsigned long long)msg.share_file_id, + (unsigned long long)msg.op_mid)); - /* Here's the hack from open.c, store the mid in the 'port' field */ - schedule_deferred_open_smb_message(msg.op_mid); + schedule_deferred_open_message_smb(sconn, msg.op_mid); } static void process_open_retry_message(struct messaging_context *msg_ctx, @@ -696,7 +729,14 @@ static void process_open_retry_message(struct messaging_context *msg_ctx, DATA_BLOB *data) { struct share_mode_entry msg; - + struct smbd_server_connection *sconn = + talloc_get_type(private_data, + struct smbd_server_connection); + + if (sconn == NULL) { + return; + } + if (data->data == NULL) { DEBUG(0, ("Got NULL buffer\n")); return; @@ -710,11 +750,11 @@ static void process_open_retry_message(struct messaging_context *msg_ctx, /* De-linearize incoming message. */ message_to_share_mode_entry(&msg, (char *)data->data); - DEBUG(10, ("Got open retry msg from pid %s: %s mid %u\n", - procid_str(debug_ctx(), &src), file_id_string_tos(&msg.id), - (unsigned int)msg.op_mid)); + DEBUG(10, ("Got open retry msg from pid %s: %s mid %llu\n", + server_id_str(talloc_tos(), &src), file_id_string_tos(&msg.id), + (unsigned long long)msg.op_mid)); - schedule_deferred_open_smb_message(msg.op_mid); + schedule_deferred_open_message_smb(sconn, msg.op_mid); } /**************************************************************************** @@ -802,10 +842,19 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp, */ if (procid_is_me(&share_entry->pid)) { + struct files_struct *cur_fsp = + initial_break_processing(fsp->conn->sconn, + share_entry->id, + share_entry->share_file_id); wait_before_sending_break(); - break_level2_to_none_async(fsp); + if (cur_fsp != NULL) { + break_level2_to_none_async(cur_fsp); + } else { + DEBUG(3, ("release_level_2_oplocks_on_change: " + "Did not find fsp, ignoring\n")); + } } else { - messaging_send_buf(smbd_messaging_context(), + messaging_send_buf(fsp->conn->sconn->msg_ctx, share_entry->pid, MSG_SMB_ASYNC_LEVEL2_BREAK, (uint8 *)msg, @@ -819,7 +868,7 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp, TALLOC_FREE(lck); } -void contend_level2_oplocks_begin(files_struct *fsp, +void smbd_contend_level2_oplocks_begin(files_struct *fsp, enum level2_contention_type type) { if (koplocks && koplocks->ops->contend_level2_oplocks_begin) { @@ -830,7 +879,7 @@ void contend_level2_oplocks_begin(files_struct *fsp, contend_level2_oplocks_begin_default(fsp, type); } -void contend_level2_oplocks_end(files_struct *fsp, +void smbd_contend_level2_oplocks_end(files_struct *fsp, enum level2_contention_type type) { /* Only kernel oplocks implement this so far */ @@ -845,21 +894,20 @@ void contend_level2_oplocks_end(files_struct *fsp, void share_mode_entry_to_message(char *msg, const struct share_mode_entry *e) { - SIVAL(msg,0,(uint32)e->pid.pid); - SSVAL(msg,4,e->op_mid); - SSVAL(msg,6,e->op_type); - SIVAL(msg,8,e->access_mask); - SIVAL(msg,12,e->share_access); - SIVAL(msg,16,e->private_options); - SIVAL(msg,20,(uint32)e->time.tv_sec); - SIVAL(msg,24,(uint32)e->time.tv_usec); - push_file_id_24(msg+28, &e->id); - SIVAL(msg,52,e->share_file_id); - SIVAL(msg,56,e->uid); - SSVAL(msg,60,e->flags); -#ifdef CLUSTER_SUPPORT - SIVAL(msg,62,e->pid.vnn); -#endif + SIVAL(msg,OP_BREAK_MSG_PID_OFFSET,(uint32)e->pid.pid); + SBVAL(msg,OP_BREAK_MSG_MID_OFFSET,e->op_mid); + SSVAL(msg,OP_BREAK_MSG_OP_TYPE_OFFSET,e->op_type); + SIVAL(msg,OP_BREAK_MSG_ACCESS_MASK_OFFSET,e->access_mask); + SIVAL(msg,OP_BREAK_MSG_SHARE_ACCESS_OFFSET,e->share_access); + SIVAL(msg,OP_BREAK_MSG_PRIV_OFFSET,e->private_options); + SIVAL(msg,OP_BREAK_MSG_TIME_SEC_OFFSET,(uint32_t)e->time.tv_sec); + SIVAL(msg,OP_BREAK_MSG_TIME_USEC_OFFSET,(uint32_t)e->time.tv_usec); + push_file_id_24(msg+OP_BREAK_MSG_DEV_OFFSET, &e->id); + SIVAL(msg,OP_BREAK_MSG_FILE_ID_OFFSET,e->share_file_id); + SIVAL(msg,OP_BREAK_MSG_UID_OFFSET,e->uid); + SSVAL(msg,OP_BREAK_MSG_FLAGS_OFFSET,e->flags); + SIVAL(msg,OP_BREAK_MSG_NAME_HASH_OFFSET,e->name_hash); + SIVAL(msg,OP_BREAK_MSG_VNN_OFFSET,e->pid.vnn); } /**************************************************************************** @@ -868,49 +916,49 @@ void share_mode_entry_to_message(char *msg, const struct share_mode_entry *e) void message_to_share_mode_entry(struct share_mode_entry *e, char *msg) { - e->pid.pid = (pid_t)IVAL(msg,0); - e->op_mid = SVAL(msg,4); - e->op_type = SVAL(msg,6); - e->access_mask = IVAL(msg,8); - e->share_access = IVAL(msg,12); - e->private_options = IVAL(msg,16); - e->time.tv_sec = (time_t)IVAL(msg,20); - e->time.tv_usec = (int)IVAL(msg,24); - pull_file_id_24(msg+28, &e->id); - e->share_file_id = (unsigned long)IVAL(msg,52); - e->uid = (uint32)IVAL(msg,56); - e->flags = (uint16)SVAL(msg,60); -#ifdef CLUSTER_SUPPORT - e->pid.vnn = IVAL(msg,62); -#endif + e->pid.pid = (pid_t)IVAL(msg,OP_BREAK_MSG_PID_OFFSET); + e->op_mid = BVAL(msg,OP_BREAK_MSG_MID_OFFSET); + e->op_type = SVAL(msg,OP_BREAK_MSG_OP_TYPE_OFFSET); + e->access_mask = IVAL(msg,OP_BREAK_MSG_ACCESS_MASK_OFFSET); + e->share_access = IVAL(msg,OP_BREAK_MSG_SHARE_ACCESS_OFFSET); + e->private_options = IVAL(msg,OP_BREAK_MSG_PRIV_OFFSET); + e->time.tv_sec = (time_t)IVAL(msg,OP_BREAK_MSG_TIME_SEC_OFFSET); + e->time.tv_usec = (int)IVAL(msg,OP_BREAK_MSG_TIME_USEC_OFFSET); + pull_file_id_24(msg+OP_BREAK_MSG_DEV_OFFSET, &e->id); + e->share_file_id = (unsigned long)IVAL(msg,OP_BREAK_MSG_FILE_ID_OFFSET); + e->uid = (uint32)IVAL(msg,OP_BREAK_MSG_UID_OFFSET); + e->flags = (uint16)SVAL(msg,OP_BREAK_MSG_FLAGS_OFFSET); + e->name_hash = IVAL(msg,OP_BREAK_MSG_NAME_HASH_OFFSET); + e->pid.vnn = IVAL(msg,OP_BREAK_MSG_VNN_OFFSET); } /**************************************************************************** Setup oplocks for this process. ****************************************************************************/ -bool init_oplocks(struct messaging_context *msg_ctx) +bool init_oplocks(struct smbd_server_connection *sconn) { DEBUG(3,("init_oplocks: initializing messages.\n")); - messaging_register(msg_ctx, NULL, MSG_SMB_BREAK_REQUEST, + messaging_register(sconn->msg_ctx, sconn, MSG_SMB_BREAK_REQUEST, process_oplock_break_message); - messaging_register(msg_ctx, NULL, MSG_SMB_ASYNC_LEVEL2_BREAK, + messaging_register(sconn->msg_ctx, sconn, MSG_SMB_ASYNC_LEVEL2_BREAK, process_oplock_async_level2_break_message); - messaging_register(msg_ctx, NULL, MSG_SMB_BREAK_RESPONSE, + messaging_register(sconn->msg_ctx, sconn, MSG_SMB_BREAK_RESPONSE, process_oplock_break_response); - messaging_register(msg_ctx, NULL, MSG_SMB_KERNEL_BREAK, + messaging_register(sconn->msg_ctx, sconn, MSG_SMB_KERNEL_BREAK, process_kernel_oplock_break); - messaging_register(msg_ctx, NULL, MSG_SMB_OPEN_RETRY, + messaging_register(sconn->msg_ctx, sconn, MSG_SMB_OPEN_RETRY, process_open_retry_message); if (lp_kernel_oplocks()) { #if HAVE_KERNEL_OPLOCKS_IRIX - koplocks = irix_init_kernel_oplocks(talloc_autofree_context()); + koplocks = irix_init_kernel_oplocks(sconn); #elif HAVE_KERNEL_OPLOCKS_LINUX - koplocks = linux_init_kernel_oplocks(talloc_autofree_context()); + koplocks = linux_init_kernel_oplocks(sconn); #elif HAVE_ONEFS - koplocks = onefs_init_kernel_oplocks(talloc_autofree_context()); +#error Isilon, please check if the NULL context is okay here. Thanks! + koplocks = onefs_init_kernel_oplocks(sconn); #endif }