s3-talloc Change TALLOC_ARRAY() to talloc_array()
[samba.git] / source3 / smbd / oplock.c
index 26ee52b797c7d5cf71f4ef45b7819f3a9745e3a0..8482a00f641a0fe30cddf280e89f06952ebec373 100644 (file)
@@ -7,7 +7,7 @@
    
    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
    
    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 2 of the License, or
+   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,
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    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, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #define DBGC_CLASS DBGC_LOCKING
 #include "includes.h"
 */
 
 #define DBGC_CLASS DBGC_LOCKING
 #include "includes.h"
-
-/* Current number of oplocks we have outstanding. */
-static int32 exclusive_oplocks_open = 0;
-static int32 level_II_oplocks_open = 0;
-BOOL global_client_failed_oplock_break = False;
-
-extern uint32 global_client_caps;
-extern int smb_read_error;
-
-static struct kernel_oplocks *koplocks;
+#include "smbd/smbd.h"
+#include "smbd/globals.h"
+#include "messages.h"
 
 /****************************************************************************
  Get the number of current exclusive oplocks.
 
 /****************************************************************************
  Get the number of current exclusive oplocks.
@@ -42,72 +34,46 @@ int32 get_number_of_exclusive_open_oplocks(void)
   return exclusive_oplocks_open;
 }
 
   return exclusive_oplocks_open;
 }
 
-/****************************************************************************
- Return True if an oplock message is pending.
-****************************************************************************/
-
-BOOL oplock_message_waiting(fd_set *fds)
+/*
+ * helper function used by the kernel oplock backends to post the break message
+ */
+void break_kernel_oplock(struct messaging_context *msg_ctx, files_struct *fsp)
 {
 {
-       if (koplocks && koplocks->msg_waiting(fds)) {
-               return True;
-       }
+       uint8_t msg[MSG_SMB_KERNEL_BREAK_SIZE];
+
+       /* Put the kernel break info into the message. */
+       push_file_id_24((char *)msg, &fsp->file_id);
+       SIVAL(msg,24,fsp->fh->gen_id);
+
+       /* Don't need to be root here as we're only ever
+          sending to ourselves. */
 
 
-       return False;
+       messaging_send_buf(msg_ctx, messaging_server_id(msg_ctx),
+                          MSG_SMB_KERNEL_BREAK,
+                          msg, MSG_SMB_KERNEL_BREAK_SIZE);
 }
 
 /****************************************************************************
 }
 
 /****************************************************************************
- Find out if there are any kernel oplock messages waiting and process them
- if so. pfds is the fd_set from the main select loop (which contains any
- kernel oplock fd if that's what the system uses (IRIX). If may be NULL if
- we're calling this in a shutting down state.
+ 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.
 ****************************************************************************/
 
 ****************************************************************************/
 
-void process_kernel_oplocks(fd_set *pfds)
+bool set_file_oplock(files_struct *fsp, int oplock_type)
 {
 {
-       /*
-        * We need to check for kernel oplocks before going into the select
-        * here, as the EINTR generated by the linux kernel oplock may have
-        * already been eaten. JRA.
-        */
-
-       if (!koplocks) {
-               return;
-       }
-
-       while (koplocks->msg_waiting(pfds)) { 
-               files_struct *fsp;
-               char msg[MSG_SMB_KERNEL_BREAK_SIZE];
-
-               fsp = koplocks->receive_message(pfds);
-
-               if (fsp == NULL) {
-                       DEBUG(3, ("Kernel oplock message announced, but none "
-                                 "received\n"));
-                       return;
+       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;
                }
                }
-
-               /* Put the kernel break info into the message. */
-               SDEV_T_VAL(msg,0,fsp->dev);
-               SINO_T_VAL(msg,8,fsp->inode);
-               SIVAL(msg,16,fsp->fh->file_id);
-
-               /* Don't need to be root here as we're only ever
-                  sending to ourselves. */
-
-               message_send_pid(pid_to_procid(sys_getpid()),
-                                MSG_SMB_KERNEL_BREAK,
-                                &msg, MSG_SMB_KERNEL_BREAK_SIZE, True);
        }
        }
-}
-
-/****************************************************************************
- Attempt to set an oplock on a file. Always succeeds if kernel oplocks are
- disabled (just sets flags). Returns True if oplock set.
-****************************************************************************/
 
 
-BOOL set_file_oplock(files_struct *fsp, int oplock_type)
-{
-       if (koplocks && !koplocks->set_oplock(fsp, oplock_type)) {
+       if ((fsp->oplock_type != NO_OPLOCK) &&
+           (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK) &&
+           koplocks &&
+           !koplocks->ops->set_oplock(koplocks, fsp, oplock_type)) {
                return False;
        }
 
                return False;
        }
 
@@ -115,14 +81,14 @@ BOOL set_file_oplock(files_struct *fsp, int oplock_type)
        fsp->sent_oplock_break = NO_BREAK_SENT;
        if (oplock_type == LEVEL_II_OPLOCK) {
                level_II_oplocks_open++;
        fsp->sent_oplock_break = NO_BREAK_SENT;
        if (oplock_type == LEVEL_II_OPLOCK) {
                level_II_oplocks_open++;
-       } else {
+       } else if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
                exclusive_oplocks_open++;
        }
 
                exclusive_oplocks_open++;
        }
 
-       DEBUG(5,("set_file_oplock: granted oplock on file %s, 0x%x/%.0f/%lu, "
+       DEBUG(5,("set_file_oplock: granted oplock on file %s, %s/%lu, "
                    "tv_sec = %x, tv_usec = %x\n",
                    "tv_sec = %x, tv_usec = %x\n",
-                fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode,
-                fsp->fh->file_id, (int)fsp->open_time.tv_sec,
+                fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id),
+                fsp->fh->gen_id, (int)fsp->open_time.tv_sec,
                 (int)fsp->open_time.tv_usec ));
 
        return True;
                 (int)fsp->open_time.tv_usec ));
 
        return True;
@@ -137,7 +103,7 @@ void release_file_oplock(files_struct *fsp)
        if ((fsp->oplock_type != NO_OPLOCK) &&
            (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK) &&
            koplocks) {
        if ((fsp->oplock_type != NO_OPLOCK) &&
            (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK) &&
            koplocks) {
-               koplocks->release_oplock(fsp);
+               koplocks->ops->release_oplock(koplocks, fsp, NO_OPLOCK);
        }
 
        if (fsp->oplock_type == LEVEL_II_OPLOCK) {
        }
 
        if (fsp->oplock_type == LEVEL_II_OPLOCK) {
@@ -148,11 +114,19 @@ void release_file_oplock(files_struct *fsp)
 
        SMB_ASSERT(exclusive_oplocks_open>=0);
        SMB_ASSERT(level_II_oplocks_open>=0);
 
        SMB_ASSERT(exclusive_oplocks_open>=0);
        SMB_ASSERT(level_II_oplocks_open>=0);
-       
-       fsp->oplock_type = NO_OPLOCK;
+
+       if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+               /* This doesn't matter for close. */
+               fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
+       } else {
+               fsp->oplock_type = NO_OPLOCK;
+       }
        fsp->sent_oplock_break = NO_BREAK_SENT;
        fsp->sent_oplock_break = NO_BREAK_SENT;
-       
+
        flush_write_cache(fsp, OPLOCK_RELEASE_FLUSH);
        flush_write_cache(fsp, OPLOCK_RELEASE_FLUSH);
+       delete_write_cache(fsp);
+
+       TALLOC_FREE(fsp->oplock_timeout);
 }
 
 /****************************************************************************
 }
 
 /****************************************************************************
@@ -161,8 +135,13 @@ void release_file_oplock(files_struct *fsp)
 
 static void downgrade_file_oplock(files_struct *fsp)
 {
 
 static void downgrade_file_oplock(files_struct *fsp)
 {
+       if (!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+               DEBUG(0, ("trying to downgrade an already-downgraded oplock!\n"));
+               return;
+       }
+
        if (koplocks) {
        if (koplocks) {
-               koplocks->release_oplock(fsp);
+               koplocks->ops->release_oplock(koplocks, fsp, LEVEL_II_OPLOCK);
        }
        fsp->oplock_type = LEVEL_II_OPLOCK;
        exclusive_oplocks_open--;
        }
        fsp->oplock_type = LEVEL_II_OPLOCK;
        exclusive_oplocks_open--;
@@ -176,26 +155,25 @@ static void downgrade_file_oplock(files_struct *fsp)
  to none even if a "break-to-level II" was sent.
 ****************************************************************************/
 
  to none even if a "break-to-level II" was sent.
 ****************************************************************************/
 
-BOOL remove_oplock(files_struct *fsp)
+bool remove_oplock(files_struct *fsp)
 {
 {
-       SMB_DEV_T dev = fsp->dev;
-       SMB_INO_T inode = fsp->inode;
-       BOOL ret;
+       bool ret;
        struct share_mode_lock *lck;
 
        /* Remove the oplock flag from the sharemode. */
        struct share_mode_lock *lck;
 
        /* Remove the oplock flag from the sharemode. */
-       lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL);
+       lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
+                                 NULL);
        if (lck == NULL) {
                DEBUG(0,("remove_oplock: failed to lock share entry for "
        if (lck == NULL) {
                DEBUG(0,("remove_oplock: failed to lock share entry for "
-                        "file %s\n", fsp->fsp_name ));
+                        "file %s\n", fsp_str_dbg(fsp)));
                return False;
        }
        ret = remove_share_oplock(lck, fsp);
        if (!ret) {
                DEBUG(0,("remove_oplock: failed to remove share oplock for "
                return False;
        }
        ret = remove_share_oplock(lck, fsp);
        if (!ret) {
                DEBUG(0,("remove_oplock: failed to remove share oplock for "
-                        "file %s fnum %d, 0x%x/%.0f\n",
-                        fsp->fsp_name, fsp->fnum, (unsigned int)dev,
-                        (double)inode));
+                        "file %s fnum %d, %s\n",
+                        fsp_str_dbg(fsp), fsp->fnum,
+                        file_id_string_tos(&fsp->file_id)));
        }
        release_file_oplock(fsp);
        TALLOC_FREE(lck);
        }
        release_file_oplock(fsp);
        TALLOC_FREE(lck);
@@ -205,25 +183,24 @@ BOOL remove_oplock(files_struct *fsp)
 /*
  * Deal with a reply when a break-to-level II was sent.
  */
 /*
  * Deal with a reply when a break-to-level II was sent.
  */
-BOOL downgrade_oplock(files_struct *fsp)
+bool downgrade_oplock(files_struct *fsp)
 {
 {
-       SMB_DEV_T dev = fsp->dev;
-       SMB_INO_T inode = fsp->inode;
-       BOOL ret;
+       bool ret;
        struct share_mode_lock *lck;
 
        struct share_mode_lock *lck;
 
-       lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL);
+       lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
+                                 NULL);
        if (lck == NULL) {
                DEBUG(0,("downgrade_oplock: failed to lock share entry for "
        if (lck == NULL) {
                DEBUG(0,("downgrade_oplock: failed to lock share entry for "
-                        "file %s\n", fsp->fsp_name ));
+                        "file %s\n", fsp_str_dbg(fsp)));
                return False;
        }
        ret = downgrade_share_oplock(lck, fsp);
        if (!ret) {
                DEBUG(0,("downgrade_oplock: failed to downgrade share oplock "
                return False;
        }
        ret = downgrade_share_oplock(lck, fsp);
        if (!ret) {
                DEBUG(0,("downgrade_oplock: failed to downgrade share oplock "
-                        "for file %s fnum %d, dev = %x, inode = %.0f\n",
-                        fsp->fsp_name, fsp->fnum, (unsigned int)dev,
-                        (double)inode));
+                        "for file %s fnum %d, file_id %s\n",
+                        fsp_str_dbg(fsp), fsp->fnum,
+                        file_id_string_tos(&fsp->file_id)));
        }
 
        downgrade_file_oplock(fsp);
        }
 
        downgrade_file_oplock(fsp);
@@ -231,27 +208,23 @@ BOOL downgrade_oplock(files_struct *fsp)
        return ret;
 }
 
        return ret;
 }
 
-/****************************************************************************
- Return the fd (if any) used for receiving oplock notifications.
-****************************************************************************/
-
-int oplock_notify_fd(void)
+/*
+ * Some kernel oplock implementations handle the notification themselves.
+ */
+bool should_notify_deferred_opens()
 {
 {
-       if (koplocks) {
-               return koplocks->notification_fd;
-       }
-
-       return -1;
+       return !(koplocks &&
+               (koplocks->flags & KOPLOCKS_DEFERRED_OPEN_NOTIFICATION));
 }
 
 /****************************************************************************
  Set up an oplock break message.
 ****************************************************************************/
 
 }
 
 /****************************************************************************
  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"));
 
        if (result == NULL) {
                DEBUG(0, ("talloc failed\n"));
@@ -259,7 +232,7 @@ static char *new_break_smb_message(TALLOC_CTX *mem_ctx,
        }
 
        memset(result,'\0',smb_size);
        }
 
        memset(result,'\0',smb_size);
-       set_message(NULL,result,8,0,True);
+       srv_set_message(result,8,0,true);
        SCVAL(result,smb_com,SMBlockingX);
        SSVAL(result,smb_tid,fsp->conn->cnum);
        SSVAL(result,smb_pid,0xFFFF);
        SCVAL(result,smb_com,SMBlockingX);
        SSVAL(result,smb_tid,fsp->conn->cnum);
        SSVAL(result,smb_pid,0xFFFF);
@@ -289,13 +262,15 @@ static void wait_before_sending_break(void)
  Ensure that we have a valid oplock.
 ****************************************************************************/
 
  Ensure that we have a valid oplock.
 ****************************************************************************/
 
-static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, 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;
 
        if( DEBUGLVL( 3 ) ) {
 {
        files_struct *fsp = NULL;
 
        if( DEBUGLVL( 3 ) ) {
-               dbgtext( "initial_break_processing: called for 0x%x/%.0f/%u\n",
-                       (unsigned int)dev, (double)inode, (int)file_id);
+               dbgtext( "initial_break_processing: called for %s/%u\n",
+                        file_id_string_tos(&id), (int)file_id);
                dbgtext( "Current oplocks_open (exclusive = %d, levelII = %d)\n",
                        exclusive_oplocks_open, level_II_oplocks_open );
        }
                dbgtext( "Current oplocks_open (exclusive = %d, levelII = %d)\n",
                        exclusive_oplocks_open, level_II_oplocks_open );
        }
@@ -306,14 +281,13 @@ static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, un
         * we have an oplock on it.
         */
 
         * we have an oplock on it.
         */
 
-       fsp = file_find_dif(dev, inode, file_id);
+       fsp = file_find_dif(sconn, id, file_id);
 
        if(fsp == NULL) {
                /* The file could have been closed in the meantime - return success. */
                if( DEBUGLVL( 3 ) ) {
                        dbgtext( "initial_break_processing: cannot find open file with " );
 
        if(fsp == NULL) {
                /* The file could have been closed in the meantime - return success. */
                if( DEBUGLVL( 3 ) ) {
                        dbgtext( "initial_break_processing: cannot find open file with " );
-                       dbgtext( "dev = 0x%x, inode = %.0f file_id = %lu", (unsigned int)dev,
-                               (double)inode, file_id);
+                       dbgtext( "file_id %s gen_id = %lu", file_id_string_tos(&id), file_id);
                        dbgtext( "allowing break to succeed.\n" );
                }
                return NULL;
                        dbgtext( "allowing break to succeed.\n" );
                }
                return NULL;
@@ -331,9 +305,10 @@ static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, un
 
        if(fsp->oplock_type == NO_OPLOCK) {
                if( DEBUGLVL( 3 ) ) {
 
        if(fsp->oplock_type == NO_OPLOCK) {
                if( DEBUGLVL( 3 ) ) {
-                       dbgtext( "initial_break_processing: file %s ", fsp->fsp_name );
-                       dbgtext( "(dev = %x, inode = %.0f, file_id = %lu) has no oplock.\n",
-                               (unsigned int)dev, (double)inode, fsp->fh->file_id );
+                       dbgtext( "initial_break_processing: file %s ",
+                                fsp_str_dbg(fsp));
+                       dbgtext( "(file_id = %s gen_id = %lu) has no oplock.\n",
+                                file_id_string_tos(&id), fsp->fh->gen_id );
                        dbgtext( "Allowing break to succeed regardless.\n" );
                }
                return NULL;
                        dbgtext( "Allowing break to succeed regardless.\n" );
                }
                return NULL;
@@ -344,19 +319,15 @@ static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, un
 
 static void oplock_timeout_handler(struct event_context *ctx,
                                   struct timed_event *te,
 
 static void oplock_timeout_handler(struct event_context *ctx,
                                   struct timed_event *te,
-                                  const struct timeval *now,
+                                  struct timeval now,
                                   void *private_data)
 {
        files_struct *fsp = (files_struct *)private_data;
 
                                   void *private_data)
 {
        files_struct *fsp = (files_struct *)private_data;
 
-       /* Ensure we always remove this event. */
-       if (fsp->oplock_timeout != NULL) {
-               /* Remove the timed event handler. */
-               TALLOC_FREE(fsp->oplock_timeout);
-               fsp->oplock_timeout = NULL;
-       }
-       DEBUG(0, ("Oplock break failed for file %s -- replying anyway\n", fsp->fsp_name));
-       global_client_failed_oplock_break = True;
+       /* Remove the timed event handler. */
+       TALLOC_FREE(fsp->oplock_timeout);
+       DEBUG(0, ("Oplock break failed for file %s -- replying anyway\n",
+                 fsp_str_dbg(fsp)));
        remove_oplock(fsp);
        reply_to_oplock_break_requests(fsp);
 }
        remove_oplock(fsp);
        reply_to_oplock_break_requests(fsp);
 }
@@ -367,15 +338,23 @@ static void oplock_timeout_handler(struct event_context *ctx,
 
 static void add_oplock_timeout_handler(files_struct *fsp)
 {
 
 static void add_oplock_timeout_handler(files_struct *fsp)
 {
+       /*
+        * If kernel oplocks already notifies smbds when an oplock break times
+        * out, just return.
+        */
+       if (koplocks &&
+           (koplocks->flags & KOPLOCKS_TIMEOUT_NOTIFICATION)) {
+               return;
+       }
+
        if (fsp->oplock_timeout != NULL) {
                DEBUG(0, ("Logic problem -- have an oplock event hanging "
                          "around\n"));
        }
 
        fsp->oplock_timeout =
        if (fsp->oplock_timeout != NULL) {
                DEBUG(0, ("Logic problem -- have an oplock event hanging "
                          "around\n"));
        }
 
        fsp->oplock_timeout =
-               event_add_timed(smbd_event_context(), NULL,
+               event_add_timed(server_event_context(), fsp,
                                timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0),
                                timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0),
-                               "oplock_timeout_handler",
                                oplock_timeout_handler, fsp);
 
        if (fsp->oplock_timeout == NULL) {
                                oplock_timeout_handler, fsp);
 
        if (fsp->oplock_timeout == NULL) {
@@ -383,6 +362,65 @@ static void add_oplock_timeout_handler(files_struct *fsp)
        }
 }
 
        }
 }
 
+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)
+{
+       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
+                * it.  just ignore. */
+               DEBUG(3, ("process_oplock_async_level2_break_message: already "
+                         "broken to none, ignoring.\n"));
+               return;
+       }
+
+       if (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK) {
+               /* Don't tell the client, just downgrade. */
+               DEBUG(3, ("process_oplock_async_level2_break_message: "
+                         "downgrading fake level 2 oplock.\n"));
+               remove_oplock(fsp);
+               return;
+       }
+
+       /* Ensure we're really at level2 state. */
+       SMB_ASSERT(fsp->oplock_type == LEVEL_II_OPLOCK);
+
+       DEBUG(10,("process_oplock_async_level2_break_message: sending break "
+                 "to none message for fid %d, file %s\n", fsp->fnum,
+                 fsp_str_dbg(fsp)));
+
+       /* Now send a break to none message to our client. */
+       if (sconn->using_smb2) {
+               send_break_message_smb2(fsp, OPLOCKLEVEL_NONE);
+       } else {
+               send_break_message_smb1(fsp, OPLOCKLEVEL_NONE);
+       }
+
+       /* Async level2 request, don't send a reply, just remove the oplock. */
+       remove_oplock(fsp);
+}
+
 /*******************************************************************
  This handles the case of a write triggering a break to none
  message on a level2 oplock.
 /*******************************************************************
  This handles the case of a write triggering a break to none
  message on a level2 oplock.
@@ -391,34 +429,40 @@ static void add_oplock_timeout_handler(files_struct *fsp)
  the client for LEVEL2.
 *******************************************************************/
 
  the client for LEVEL2.
 *******************************************************************/
 
-static void process_oplock_async_level2_break_message(int msg_type, struct process_id src,
-                                                     void *buf, size_t len,
-                                                     void *private_data)
+void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx,
+                                                     void *private_data,
+                                                     uint32_t msg_type,
+                                                     struct server_id src,
+                                                     DATA_BLOB *data)
 {
 {
+       struct smbd_server_connection *sconn;
        struct share_mode_entry msg;
        files_struct *fsp;
        struct share_mode_entry msg;
        files_struct *fsp;
-       char *break_msg;
-       BOOL sign_state;
 
 
-       if (buf == NULL) {
+       if (data->data == NULL) {
                DEBUG(0, ("Got NULL buffer\n"));
                return;
        }
 
                DEBUG(0, ("Got NULL buffer\n"));
                return;
        }
 
-       if (len != MSG_SMB_SHARE_MODE_ENTRY_SIZE) {
-               DEBUG(0, ("Got invalid msg len %d\n", (int)len));
+       sconn = msg_ctx_to_sconn(msg_ctx);
+       if (sconn == NULL) {
+               DEBUG(1, ("could not find sconn\n"));
+               return;
+       }
+
+       if (data->length != MSG_SMB_SHARE_MODE_ENTRY_SIZE) {
+               DEBUG(0, ("Got invalid msg len %d\n", (int)data->length));
                return;
        }
 
        /* De-linearize incoming message. */
                return;
        }
 
        /* De-linearize incoming message. */
-       message_to_share_mode_entry(&msg, (char *)buf);
+       message_to_share_mode_entry(&msg, (char *)data->data);
 
 
-       DEBUG(10, ("Got oplock async level 2 break message from pid %d: 0x%x/%.0f/%lu\n",
-                  (int)procid_to_pid(&src), (unsigned int)msg.dev,
-                  (double)msg.inode, msg.share_file_id));
+       DEBUG(10, ("Got oplock async level 2 break message from pid %s: "
+                  "%s/%lu\n", procid_str(talloc_tos(), &src),
+                  file_id_string_tos(&msg.id), msg.share_file_id));
 
 
-       fsp = initial_break_processing(msg.dev, msg.inode,
-                                      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
 
        if (fsp == NULL) {
                /* We hit a race here. Break messages are sent, and before we
@@ -428,95 +472,59 @@ static void process_oplock_async_level2_break_message(int msg_type, struct proce
                return;
        }
 
                return;
        }
 
-       if (fsp->oplock_type == NO_OPLOCK) {
-               /* We already got a "break to none" message and we've handled it.
-                * just ignore. */
-               DEBUG(3, ("process_oplock_async_level2_break_message: already broken to none, ignoring.\n"));
-               return;
-       }
-
-       if (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK) {
-               /* Don't tell the client, just downgrade. */
-               DEBUG(3, ("process_oplock_async_level2_break_message: downgrading fake level 2 oplock.\n"));
-               remove_oplock(fsp);
-               return;
-       }
-
-       /* Ensure we're really at level2 state. */
-       SMB_ASSERT(fsp->oplock_type == LEVEL_II_OPLOCK);
-
-       /* 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");
-       }
-
-       /* Need to wait before sending a break message if we sent ourselves this message. */
-       if (procid_to_pid(&src) == sys_getpid()) {
-               wait_before_sending_break();
-       }
-
-       /* Save the server smb signing state. */
-       sign_state = srv_oplock_set_signing(False);
-
-       show_msg(break_msg);
-       if (!send_smb(smbd_server_fd(), break_msg)) {
-               exit_server_cleanly("oplock_break: send_smb failed.");
-       }
-
-       /* Restore the sign state to what it was. */
-       srv_oplock_set_signing(sign_state);
-
-       TALLOC_FREE(break_msg);
-
-       /* Async level2 request, don't send a reply, just remove the oplock. */
-       remove_oplock(fsp);
+       break_level2_to_none_async(fsp);
 }
 
 /*******************************************************************
  This handles the generic oplock break message from another smbd.
 *******************************************************************/
 
 }
 
 /*******************************************************************
  This handles the generic oplock break message from another smbd.
 *******************************************************************/
 
-static void process_oplock_break_message(int msg_type, struct process_id src,
-                                        void *buf, size_t len,
-                                        void *private_data)
+static void process_oplock_break_message(struct messaging_context *msg_ctx,
+                                        void *private_data,
+                                        uint32_t msg_type,
+                                        struct server_id src,
+                                        DATA_BLOB *data)
 {
 {
+       struct smbd_server_connection *sconn;
        struct share_mode_entry msg;
        files_struct *fsp;
        struct share_mode_entry msg;
        files_struct *fsp;
-       char *break_msg;
-       BOOL break_to_level2 = False;
-       BOOL sign_state;
+       bool break_to_level2 = False;
 
 
-       if (buf == NULL) {
+       if (data->data == NULL) {
                DEBUG(0, ("Got NULL buffer\n"));
                return;
        }
 
                DEBUG(0, ("Got NULL buffer\n"));
                return;
        }
 
-       if (len != MSG_SMB_SHARE_MODE_ENTRY_SIZE) {
-               DEBUG(0, ("Got invalid msg len %d\n", (int)len));
+       sconn = msg_ctx_to_sconn(msg_ctx);
+       if (sconn == NULL) {
+               DEBUG(1, ("could not find sconn\n"));
+               return;
+       }
+
+       if (data->length != MSG_SMB_SHARE_MODE_ENTRY_SIZE) {
+               DEBUG(0, ("Got invalid msg len %d\n", (int)data->length));
                return;
        }
 
        /* De-linearize incoming message. */
                return;
        }
 
        /* De-linearize incoming message. */
-       message_to_share_mode_entry(&msg, (char *)buf);
+       message_to_share_mode_entry(&msg, (char *)data->data);
 
 
-       DEBUG(10, ("Got oplock break message from pid %d: 0x%x/%.0f/%lu\n",
-                  (int)procid_to_pid(&src), (unsigned int)msg.dev,
-                  (double)msg.inode, msg.share_file_id));
+       DEBUG(10, ("Got oplock break message from pid %s: %s/%lu\n",
+                  procid_str(talloc_tos(), &src), file_id_string_tos(&msg.id),
+                  msg.share_file_id));
 
 
-       fsp = initial_break_processing(msg.dev, msg.inode,
-                                      msg.share_file_id);
+       fsp = initial_break_processing(sconn, msg.id, msg.share_file_id);
 
        if (fsp == NULL) {
 
        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"));
 
                /* We just send the same message back. */
                 * get to process this message, we have closed the file. Reply
                 * with 'ok, oplock broken' */
                DEBUG(3, ("Did not find fsp\n"));
 
                /* We just send the same message back. */
-               message_send_pid(src, MSG_SMB_BREAK_RESPONSE,
-                                buf, MSG_SMB_SHARE_MODE_ENTRY_SIZE, True);
+               messaging_send_buf(msg_ctx, src, MSG_SMB_BREAK_RESPONSE,
+                                  (uint8 *)data->data,
+                                  MSG_SMB_SHARE_MODE_ENTRY_SIZE);
                return;
        }
 
                return;
        }
 
@@ -532,47 +540,37 @@ static void process_oplock_break_message(int msg_type, struct process_id src,
 
        if (EXCLUSIVE_OPLOCK_TYPE(msg.op_type) &&
            !EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
 
        if (EXCLUSIVE_OPLOCK_TYPE(msg.op_type) &&
            !EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
-               DEBUG(3, ("Already downgraded oplock on 0x%x/%.0f: %s\n",
-                         (unsigned int)fsp->dev, (double)fsp->inode,
-                         fsp->fsp_name));
+               DEBUG(3, ("Already downgraded oplock on %s: %s\n",
+                         file_id_string_tos(&fsp->file_id),
+                         fsp_str_dbg(fsp)));
                /* We just send the same message back. */
                /* We just send the same message back. */
-               message_send_pid(src, MSG_SMB_BREAK_RESPONSE,
-                                buf, MSG_SMB_SHARE_MODE_ENTRY_SIZE, True);
+               messaging_send_buf(msg_ctx, src, MSG_SMB_BREAK_RESPONSE,
+                                  (uint8 *)data->data,
+                                  MSG_SMB_SHARE_MODE_ENTRY_SIZE);
                return;
        }
 
        if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) && 
            !(msg.op_type & FORCE_OPLOCK_BREAK_TO_NONE) &&
                return;
        }
 
        if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) && 
            !(msg.op_type & FORCE_OPLOCK_BREAK_TO_NONE) &&
-           !koplocks && /* NOTE: we force levelII off for kernel oplocks -
-                         * this will change when it is supported */
+           !(koplocks && !(koplocks->flags & KOPLOCKS_LEVEL2_SUPPORTED)) &&
            lp_level2_oplocks(SNUM(fsp->conn))) {
                break_to_level2 = True;
        }
 
            lp_level2_oplocks(SNUM(fsp->conn))) {
                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. */
-       if (procid_to_pid(&src) == sys_getpid()) {
+       /* Need to wait before sending a break
+          message if we sent ourselves this message. */
+       if (procid_is_me(&src)) {
                wait_before_sending_break();
        }
 
                wait_before_sending_break();
        }
 
-       /* Save the server smb signing state. */
-       sign_state = srv_oplock_set_signing(False);
-
-       show_msg(break_msg);
-       if (!send_smb(smbd_server_fd(), break_msg)) {
-               exit_server_cleanly("oplock_break: 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);
        }
 
        }
 
-       /* Restore the sign state to what it was. */
-       srv_oplock_set_signing(sign_state);
-
-       TALLOC_FREE(break_msg);
-
        fsp->sent_oplock_break = break_to_level2 ? LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT;
 
        msg.pid = src;
        fsp->sent_oplock_break = break_to_level2 ? LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT;
 
        msg.pid = src;
@@ -587,37 +585,42 @@ static void process_oplock_break_message(int msg_type, struct process_id src,
  This handles the kernel oplock break message.
 *******************************************************************/
 
  This handles the kernel oplock break message.
 *******************************************************************/
 
-static void process_kernel_oplock_break(int msg_type, struct process_id src,
-                                       void *buf, size_t len,
-                                       void *private_data)
+static void process_kernel_oplock_break(struct messaging_context *msg_ctx,
+                                       void *private_data,
+                                       uint32_t msg_type,
+                                       struct server_id src,
+                                       DATA_BLOB *data)
 {
 {
-       SMB_DEV_T dev;
-       SMB_INO_T inode;
+       struct smbd_server_connection *sconn;
+       struct file_id id;
        unsigned long file_id;
        files_struct *fsp;
        unsigned long file_id;
        files_struct *fsp;
-       char *break_msg;
-       BOOL sign_state;
 
 
-       if (buf == NULL) {
+       if (data->data == NULL) {
                DEBUG(0, ("Got NULL buffer\n"));
                return;
        }
 
                DEBUG(0, ("Got NULL buffer\n"));
                return;
        }
 
-       if (len != MSG_SMB_KERNEL_BREAK_SIZE) {
-               DEBUG(0, ("Got invalid msg len %d\n", (int)len));
+       if (data->length != MSG_SMB_KERNEL_BREAK_SIZE) {
+               DEBUG(0, ("Got invalid msg len %d\n", (int)data->length));
+               return;
+       }
+
+       sconn = msg_ctx_to_sconn(msg_ctx);
+       if (sconn == NULL) {
+               DEBUG(1, ("could not find sconn\n"));
                return;
        }
 
        /* Pull the data from the message. */
                return;
        }
 
        /* Pull the data from the message. */
-       dev = DEV_T_VAL(buf, 0);
-       inode = INO_T_VAL(buf, 8);
-       file_id = (unsigned long)IVAL(buf, 16);
+       pull_file_id_24((char *)data->data, &id);
+       file_id = (unsigned long)IVAL(data->data, 24);
 
 
-       DEBUG(10, ("Got kernel oplock break message from pid %d: 0x%x/%.0f/%u\n",
-                  (int)procid_to_pid(&src), (unsigned int)dev, (double)inode,
+       DEBUG(10, ("Got kernel oplock break message from pid %s: %s/%u\n",
+                  procid_str(talloc_tos(), &src), file_id_string_tos(&id),
                   (unsigned int)file_id));
 
                   (unsigned int)file_id));
 
-       fsp = initial_break_processing(dev, inode, file_id);
+       fsp = initial_break_processing(sconn, id, file_id);
 
        if (fsp == NULL) {
                DEBUG(3, ("Got a kernel oplock break message for a file "
 
        if (fsp == NULL) {
                DEBUG(3, ("Got a kernel oplock break message for a file "
@@ -632,24 +635,12 @@ static void process_kernel_oplock_break(int msg_type, struct process_id src,
                return;
        }
 
                return;
        }
 
-       break_msg = new_break_smb_message(NULL, fsp, OPLOCKLEVEL_NONE);
-       if (break_msg == NULL) {
-               exit_server("Could not talloc break_msg\n");
-       }
-
-       /* Save the server smb signing state. */
-       sign_state = srv_oplock_set_signing(False);
-
-       show_msg(break_msg);
-       if (!send_smb(smbd_server_fd(), break_msg)) {
-               exit_server_cleanly("oplock_break: send_smb failed.");
+       if (sconn->using_smb2) {
+               send_break_message_smb2(fsp, OPLOCKLEVEL_NONE);
+       } else {
+               send_break_message_smb1(fsp, OPLOCKLEVEL_NONE);
        }
 
        }
 
-       /* Restore the sign state to what it was. */
-       srv_oplock_set_signing(sign_state);
-
-       TALLOC_FREE(break_msg);
-
        fsp->sent_oplock_break = BREAK_TO_NONE_SENT;
 
        add_oplock_timeout_handler(fsp);
        fsp->sent_oplock_break = BREAK_TO_NONE_SENT;
 
        add_oplock_timeout_handler(fsp);
@@ -659,14 +650,25 @@ void reply_to_oplock_break_requests(files_struct *fsp)
 {
        int i;
 
 {
        int i;
 
+       /*
+        * If kernel oplocks already notifies smbds when oplocks are
+        * broken/removed, just return.
+        */
+       if (koplocks &&
+           (koplocks->flags & KOPLOCKS_OPLOCK_BROKEN_NOTIFICATION)) {
+               return;
+       }
+
        for (i=0; i<fsp->num_pending_break_messages; i++) {
                struct share_mode_entry *e = &fsp->pending_break_messages[i];
                char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
 
                share_mode_entry_to_message(msg, e);
 
        for (i=0; i<fsp->num_pending_break_messages; i++) {
                struct share_mode_entry *e = &fsp->pending_break_messages[i];
                char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
 
                share_mode_entry_to_message(msg, e);
 
-               message_send_pid(e->pid, MSG_SMB_BREAK_RESPONSE,
-                                msg, MSG_SMB_SHARE_MODE_ENTRY_SIZE, True);
+               messaging_send_buf(fsp->conn->sconn->msg_ctx, e->pid,
+                                  MSG_SMB_BREAK_RESPONSE,
+                                  (uint8 *)msg,
+                                  MSG_SMB_SHARE_MODE_ENTRY_SIZE);
        }
 
        SAFE_FREE(fsp->pending_break_messages);
        }
 
        SAFE_FREE(fsp->pending_break_messages);
@@ -679,59 +681,61 @@ void reply_to_oplock_break_requests(files_struct *fsp)
        return;
 }
 
        return;
 }
 
-static void process_oplock_break_response(int msg_type, struct process_id src,
-                                         void *buf, size_t len,
-                                         void *private_data)
+static void process_oplock_break_response(struct messaging_context *msg_ctx,
+                                         void *private_data,
+                                         uint32_t msg_type,
+                                         struct server_id src,
+                                         DATA_BLOB *data)
 {
        struct share_mode_entry msg;
 
 {
        struct share_mode_entry msg;
 
-       if (buf == NULL) {
+       if (data->data == NULL) {
                DEBUG(0, ("Got NULL buffer\n"));
                return;
        }
 
                DEBUG(0, ("Got NULL buffer\n"));
                return;
        }
 
-       if (len != MSG_SMB_SHARE_MODE_ENTRY_SIZE) {
-               DEBUG(0, ("Got invalid msg len %u\n", (unsigned int)len));
+       if (data->length != MSG_SMB_SHARE_MODE_ENTRY_SIZE) {
+               DEBUG(0, ("Got invalid msg len %u\n",
+                         (unsigned int)data->length));
                return;
        }
 
        /* De-linearize incoming message. */
                return;
        }
 
        /* De-linearize incoming message. */
-       message_to_share_mode_entry(&msg, (char *)buf);
+       message_to_share_mode_entry(&msg, (char *)data->data);
 
 
-       DEBUG(10, ("Got oplock break response from pid %d: 0x%x/%.0f/%lu mid %u\n",
-                  (int)procid_to_pid(&src), (unsigned int)msg.dev,
-                  (double)msg.inode, msg.share_file_id,
-                  (unsigned int)msg.op_mid));
+       DEBUG(10, ("Got oplock break response from pid %s: %s/%lu mid %llu\n",
+                  procid_str(talloc_tos(), &src), file_id_string_tos(&msg.id),
+                  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(msg.op_mid);
 }
 
 }
 
-static void process_open_retry_message(int msg_type, struct process_id src,
-                                      void *buf, size_t len,
-                                      void *private_data)
+static void process_open_retry_message(struct messaging_context *msg_ctx,
+                                      void *private_data,
+                                      uint32_t msg_type,
+                                      struct server_id src,
+                                      DATA_BLOB *data)
 {
        struct share_mode_entry msg;
        
 {
        struct share_mode_entry msg;
        
-       if (buf == NULL) {
+       if (data->data == NULL) {
                DEBUG(0, ("Got NULL buffer\n"));
                return;
        }
 
                DEBUG(0, ("Got NULL buffer\n"));
                return;
        }
 
-       if (len != MSG_SMB_SHARE_MODE_ENTRY_SIZE) {
-               DEBUG(0, ("Got invalid msg len %d\n", (int)len));
+       if (data->length != MSG_SMB_SHARE_MODE_ENTRY_SIZE) {
+               DEBUG(0, ("Got invalid msg len %d\n", (int)data->length));
                return;
        }
 
        /* De-linearize incoming message. */
                return;
        }
 
        /* De-linearize incoming message. */
-       message_to_share_mode_entry(&msg, (char *)buf);
+       message_to_share_mode_entry(&msg, (char *)data->data);
 
 
-       DEBUG(10, ("Got open retry msg from pid %d: 0x%x/%.0f/%lu mid %u\n",
-                  (int)procid_to_pid(&src), (unsigned int)msg.dev,
-                  (double)msg.inode, msg.share_file_id,
-                  (unsigned int)msg.op_mid));
+       DEBUG(10, ("Got open retry msg from pid %s: %s mid %llu\n",
+                  procid_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(msg.op_mid);
 }
 
 /****************************************************************************
 }
 
 /****************************************************************************
@@ -740,7 +744,8 @@ static void process_open_retry_message(int msg_type, struct process_id src,
  none.
 ****************************************************************************/
 
  none.
 ****************************************************************************/
 
-void release_level_2_oplocks_on_change(files_struct *fsp)
+static void contend_level2_oplocks_begin_default(files_struct *fsp,
+                                             enum level2_contention_type type)
 {
        int i;
        struct share_mode_lock *lck;
 {
        int i;
        struct share_mode_lock *lck;
@@ -756,10 +761,11 @@ void release_level_2_oplocks_on_change(files_struct *fsp)
        if (!LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
                return;
 
        if (!LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
                return;
 
-       lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL);
+       lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
+                                 NULL);
        if (lck == NULL) {
                DEBUG(0,("release_level_2_oplocks_on_change: failed to lock "
        if (lck == NULL) {
                DEBUG(0,("release_level_2_oplocks_on_change: failed to lock "
-                        "share mode entry for file %s.\n", fsp->fsp_name ));
+                        "share mode entry for file %s.\n", fsp_str_dbg(fsp)));
                return;
        }
 
                return;
        }
 
@@ -804,8 +810,37 @@ void release_level_2_oplocks_on_change(files_struct *fsp)
 
                share_mode_entry_to_message(msg, share_entry);
 
 
                share_mode_entry_to_message(msg, share_entry);
 
-               message_send_pid(share_entry->pid, MSG_SMB_ASYNC_LEVEL2_BREAK,
-                                msg, MSG_SMB_SHARE_MODE_ENTRY_SIZE, True);
+               /*
+                * Deal with a race condition when breaking level2
+                * oplocks. Don't send all the messages and release
+                * the lock, this allows someone else to come in and
+                * get a level2 lock before any of the messages are
+                * processed, and thus miss getting a break message.
+                * Ensure at least one entry (the one we're breaking)
+                * is processed immediately under the lock and becomes
+                * set as NO_OPLOCK to stop any waiter getting a level2.
+                * Bugid #5980.
+                */
+
+               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();
+                       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(fsp->conn->sconn->msg_ctx,
+                                       share_entry->pid,
+                                       MSG_SMB_ASYNC_LEVEL2_BREAK,
+                                       (uint8 *)msg,
+                                       MSG_SMB_SHARE_MODE_ENTRY_SIZE);
+               }
        }
 
        /* We let the message receivers handle removing the oplock state
        }
 
        /* We let the message receivers handle removing the oplock state
@@ -814,25 +849,46 @@ void release_level_2_oplocks_on_change(files_struct *fsp)
        TALLOC_FREE(lck);
 }
 
        TALLOC_FREE(lck);
 }
 
+void contend_level2_oplocks_begin(files_struct *fsp,
+                                 enum level2_contention_type type)
+{
+       if (koplocks && koplocks->ops->contend_level2_oplocks_begin) {
+               koplocks->ops->contend_level2_oplocks_begin(fsp, type);
+               return;
+       }
+
+       contend_level2_oplocks_begin_default(fsp, type);
+}
+
+void contend_level2_oplocks_end(files_struct *fsp,
+                               enum level2_contention_type type)
+{
+       /* Only kernel oplocks implement this so far */
+       if (koplocks && koplocks->ops->contend_level2_oplocks_end) {
+               koplocks->ops->contend_level2_oplocks_end(fsp, type);
+       }
+}
+
 /****************************************************************************
  Linearize a share mode entry struct to an internal oplock break message.
 ****************************************************************************/
 
 /****************************************************************************
  Linearize a share mode entry struct to an internal oplock break message.
 ****************************************************************************/
 
-void share_mode_entry_to_message(char *msg, struct share_mode_entry *e)
+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);
-       SDEV_T_VAL(msg,28,e->dev);
-       SINO_T_VAL(msg,36,e->inode);
-       SIVAL(msg,44,e->share_file_id);
-       SIVAL(msg,48,e->uid);
-       SSVAL(msg,52,e->flags);
+       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);
 }
 
 /****************************************************************************
 }
 
 /****************************************************************************
@@ -841,50 +897,49 @@ void share_mode_entry_to_message(char *msg, struct share_mode_entry *e)
 
 void message_to_share_mode_entry(struct share_mode_entry *e, char *msg)
 {
 
 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);
-       e->dev = DEV_T_VAL(msg,28);
-       e->inode = INO_T_VAL(msg,36);
-       e->share_file_id = (unsigned long)IVAL(msg,44);
-       e->uid = (uint32)IVAL(msg,48);
-       e->flags = (uint16)SVAL(msg,52);
+       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.
 ****************************************************************************/
 
 }
 
 /****************************************************************************
  Setup oplocks for this process.
 ****************************************************************************/
 
-BOOL init_oplocks(void)
+bool init_oplocks(struct messaging_context *msg_ctx)
 {
        DEBUG(3,("init_oplocks: initializing messages.\n"));
 
 {
        DEBUG(3,("init_oplocks: initializing messages.\n"));
 
-       message_register(MSG_SMB_BREAK_REQUEST,
-                        process_oplock_break_message,
-                        NULL);
-       message_register(MSG_SMB_ASYNC_LEVEL2_BREAK,
-                        process_oplock_async_level2_break_message,
-                        NULL);
-       message_register(MSG_SMB_BREAK_RESPONSE,
-                        process_oplock_break_response,
-                        NULL);
-       message_register(MSG_SMB_KERNEL_BREAK,
-                        process_kernel_oplock_break,
-                        NULL);
-       message_register(MSG_SMB_OPEN_RETRY,
-                        process_open_retry_message,
-                        NULL);
+       messaging_register(msg_ctx, NULL, MSG_SMB_BREAK_REQUEST,
+                          process_oplock_break_message);
+       messaging_register(msg_ctx, NULL, MSG_SMB_ASYNC_LEVEL2_BREAK,
+                          process_oplock_async_level2_break_message);
+       messaging_register(msg_ctx, NULL, MSG_SMB_BREAK_RESPONSE,
+                          process_oplock_break_response);
+       messaging_register(msg_ctx, NULL, MSG_SMB_KERNEL_BREAK,
+                          process_kernel_oplock_break);
+       messaging_register(msg_ctx, NULL, MSG_SMB_OPEN_RETRY,
+                          process_open_retry_message);
 
        if (lp_kernel_oplocks()) {
 #if HAVE_KERNEL_OPLOCKS_IRIX
 
        if (lp_kernel_oplocks()) {
 #if HAVE_KERNEL_OPLOCKS_IRIX
-               koplocks = irix_init_kernel_oplocks();
+               koplocks = irix_init_kernel_oplocks(NULL);
 #elif HAVE_KERNEL_OPLOCKS_LINUX
 #elif HAVE_KERNEL_OPLOCKS_LINUX
-               koplocks = linux_init_kernel_oplocks();
+               koplocks = linux_init_kernel_oplocks(NULL);
+#elif HAVE_ONEFS
+#error Isilon, please check if the NULL context is okay here. Thanks!
+               koplocks = onefs_init_kernel_oplocks(NULL);
 #endif
        }
 
 #endif
        }