s3:smbd: make kernel oplocks event driven
authorStefan Metzmacher <metze@samba.org>
Fri, 23 Jan 2009 09:08:44 +0000 (10:08 +0100)
committerStefan Metzmacher <metze@samba.org>
Tue, 27 Jan 2009 14:28:10 +0000 (15:28 +0100)
And use signal events for Linux oplocks.

metze

source3/include/proto.h
source3/include/smb.h
source3/smbd/globals.c
source3/smbd/globals.h
source3/smbd/oplock.c
source3/smbd/oplock_irix.c
source3/smbd/oplock_linux.c
source3/smbd/process.c

index 1713760666703aecb58e0db2a18a5d98467285f8..ae4929053985a0865c20382583935d92e0817eb9 100644 (file)
@@ -7018,13 +7018,11 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn,
 /* The following definitions come from smbd/oplock.c  */
 
 int32 get_number_of_exclusive_open_oplocks(void);
-bool oplock_message_waiting(void);
-void process_kernel_oplocks(struct messaging_context *msg_ctx);
+void break_kernel_oplock(struct messaging_context *msg_ctx, files_struct *fsp);
 bool set_file_oplock(files_struct *fsp, int oplock_type);
 void release_file_oplock(files_struct *fsp);
 bool remove_oplock(files_struct *fsp);
 bool downgrade_oplock(files_struct *fsp);
-int oplock_notify_fd(void);
 void reply_to_oplock_break_requests(files_struct *fsp);
 void release_level_2_oplocks_on_change(files_struct *fsp);
 void share_mode_entry_to_message(char *msg, const struct share_mode_entry *e);
index aa2db693a33eb3351b23afd2333a5b3ef26b31d5..3f71cde3955c30e975e50bbdd3ff6f981698ac78 100644 (file)
@@ -1680,12 +1680,10 @@ struct kernel_oplocks {
 /* if a kernel does support oplocks then a structure of the following
    typee is used to describe how to interact with the kernel */
 struct kernel_oplocks_ops {
-       files_struct * (*receive_message)(struct kernel_oplocks *ctx);
        bool (*set_oplock)(struct kernel_oplocks *ctx,
                           files_struct *fsp, int oplock_type);
        void (*release_oplock)(struct kernel_oplocks *ctx,
                               files_struct *fsp);
-       bool (*msg_waiting)(struct kernel_oplocks *ctx);
 };
 
 #include "smb_macros.h"
index 28b5a709bde1a5174b3425935aa34cb2ef815c7f..3f8cb411e562b289014583392719b5db67bd84da 100644 (file)
@@ -169,11 +169,6 @@ struct vfs_init_function_entry *backends = NULL;
 char *sparse_buf = NULL;
 char *LastDir = NULL;
 
-#if HAVE_KERNEL_OPLOCKS_LINUX
-SIG_ATOMIC_T oplock_signals_received = 0;
-SIG_ATOMIC_T fd_pending_array[FD_PENDING_SIZE];
-#endif
-
 /* Current number of oplocks we have outstanding. */
 int32_t exclusive_oplocks_open = 0;
 int32_t level_II_oplocks_open = 0;
@@ -201,8 +196,4 @@ void smbd_init_globals(void)
        ZERO_STRUCT(conn_ctx_stack);
 
        ZERO_STRUCT(sec_ctx_stack);
-
-#if HAVE_KERNEL_OPLOCKS_LINUX
-       ZERO_STRUCT(fd_pending_array);
-#endif
 }
index 283425caf738d69735ef6d2c1194c6ecb906cb07..6ac92ed3ddbf82c2413149dfca5bc9f88c84ef98 100644 (file)
@@ -181,12 +181,6 @@ extern struct vfs_init_function_entry *backends;
 extern char *sparse_buf;
 extern char *LastDir;
 
-#if HAVE_KERNEL_OPLOCKS_LINUX
-extern SIG_ATOMIC_T oplock_signals_received;
-#define FD_PENDING_SIZE 100
-extern SIG_ATOMIC_T fd_pending_array[FD_PENDING_SIZE];
-#endif
-
 /* Current number of oplocks we have outstanding. */
 extern int32_t exclusive_oplocks_open;
 extern int32_t level_II_oplocks_open;
index e4b50165383c99e5bfae46f7b447745386ca034f..788d2f7238cbf88a87ec9244d07dd84736f4b520 100644 (file)
@@ -32,61 +32,23 @@ int32 get_number_of_exclusive_open_oplocks(void)
   return exclusive_oplocks_open;
 }
 
-/****************************************************************************
- Return True if an oplock message is pending.
-****************************************************************************/
-
-bool oplock_message_waiting(void)
-{
-       if (koplocks && koplocks->ops->msg_waiting(koplocks)) {
-               return True;
-       }
-
-       return False;
-}
-
-/****************************************************************************
- 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.
-****************************************************************************/
-
-void process_kernel_oplocks(struct messaging_context *msg_ctx)
+/*
+ * 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)
 {
-       /*
-        * 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;
-       }
+       uint8_t msg[MSG_SMB_KERNEL_BREAK_SIZE];
 
-       while (koplocks->ops->msg_waiting(koplocks)) {
-               files_struct *fsp;
-               char msg[MSG_SMB_KERNEL_BREAK_SIZE];
+       /* Put the kernel break info into the message. */
+       push_file_id_16((char *)msg, &fsp->file_id);
+       SIVAL(msg,16,fsp->fh->gen_id);
 
-               fsp = koplocks->ops->receive_message(koplocks);
+       /* Don't need to be root here as we're only ever
+          sending to ourselves. */
 
-               if (fsp == NULL) {
-                       DEBUG(3, ("Kernel oplock message announced, but none "
-                                 "received\n"));
-                       return;
-               }
-
-               /* Put the kernel break info into the message. */
-               push_file_id_16(msg, &fsp->file_id);
-               SIVAL(msg,16,fsp->fh->gen_id);
-
-               /* Don't need to be root here as we're only ever
-                  sending to ourselves. */
-
-               messaging_send_buf(msg_ctx, procid_self(),
-                                  MSG_SMB_KERNEL_BREAK,
-                                  (uint8 *)&msg, MSG_SMB_KERNEL_BREAK_SIZE);
-       }
+       messaging_send_buf(msg_ctx, procid_self(),
+                          MSG_SMB_KERNEL_BREAK,
+                          msg, MSG_SMB_KERNEL_BREAK_SIZE);
 }
 
 /****************************************************************************
index 0cfa9604255a957d0a5155d8f53a2124983660ee..d7f45e67de492f0744f518c2173226097a8c4240 100644 (file)
@@ -252,13 +252,6 @@ static void irix_release_kernel_oplock(struct kernel_oplocks *_ctx,
        }
 }
 
-static bool irix_oplock_msg_waiting(struct kernel_oplocks *_ctx)
-{
-       struct irix_oplocks_context *ctx = talloc_get_type(_ctx->private_data,
-                                          struct irix_oplocks_context);
-       return ctx->pending;
-}
-
 static void irix_oplocks_read_fde_handler(struct event_context *ev,
                                          struct fd_event *fde,
                                          uint16_t flags,
@@ -266,10 +259,10 @@ static void irix_oplocks_read_fde_handler(struct event_context *ev,
 {
        struct irix_oplocks_context *ctx = talloc_get_type(private_data,
                                           struct irix_oplocks_context);
+       files_struct *fsp;
 
-       ctx->pending = true;
-       process_kernel_oplocks(smbd_messaging_context());
-       ctx->pending = false;
+       fsp = irix_oplock_receive_message(ctx->ctx);
+       break_kernel_oplock(smbd_messaging_context(), fsp);
 }
 
 /****************************************************************************
@@ -277,10 +270,8 @@ static void irix_oplocks_read_fde_handler(struct event_context *ev,
 ****************************************************************************/
 
 static const struct kernel_oplocks_ops irix_koplocks = {
-       .receive_message        = irix_oplock_receive_message,
        .set_oplock             = irix_set_kernel_oplock,
        .release_oplock         = irix_release_kernel_oplock,
-       .msg_waiting            = irix_oplock_msg_waiting
 };
 
 struct kernel_oplocks *irix_init_kernel_oplocks(TALLOC_CTX *mem_ctx)
index 8087167ff44a5d568004cc696f4973486541b390..51cce0ed48aa60600eaeed7751368519e4ba88b7 100644 (file)
 #define F_SETSIG 10
 #endif
 
-/****************************************************************************
- Handle a LEASE signal, incrementing the signals_received and blocking the signal.
-****************************************************************************/
-
-static void signal_handler(int sig, siginfo_t *info, void *unused)
-{
-       if (oplock_signals_received < FD_PENDING_SIZE - 1) {
-               fd_pending_array[oplock_signals_received] = (SIG_ATOMIC_T)info->si_fd;
-               oplock_signals_received++;
-       } /* Else signal is lost. */
-       sys_select_signal(RT_SIGNAL_LEASE);
-}
-
 /*
  * public function to get linux lease capability. Needed by some VFS modules (eg. gpfs.c)
  */
@@ -101,24 +88,17 @@ int linux_setlease(int fd, int leasetype)
  * oplock break protocol.
 ****************************************************************************/
 
-static files_struct *linux_oplock_receive_message(struct kernel_oplocks *ctx)
+static void linux_oplock_signal_handler(struct tevent_context *ev_ctx,
+                                       struct tevent_signal *se,
+                                       int signum, int count,
+                                       void *_info, void *private_data)
 {
-       int fd;
+       siginfo_t *info = (siginfo_t *)_info;
+       int fd = info->si_fd;
        files_struct *fsp;
 
-       BlockSignals(True, RT_SIGNAL_LEASE);
-       fd = fd_pending_array[0];
        fsp = file_find_fd(fd);
-       fd_pending_array[0] = (SIG_ATOMIC_T)-1;
-       if (oplock_signals_received > 1)
-                memmove(CONST_DISCARD(void *, &fd_pending_array[0]),
-                        CONST_DISCARD(void *, &fd_pending_array[1]),
-                       sizeof(SIG_ATOMIC_T)*(oplock_signals_received-1));
-       oplock_signals_received--;
-       /* now we can receive more signals */
-       BlockSignals(False, RT_SIGNAL_LEASE);
-
-       return fsp;
+       break_kernel_oplock(smbd_messaging_context(), fsp);
 }
 
 /****************************************************************************
@@ -179,15 +159,6 @@ static void linux_release_kernel_oplock(struct kernel_oplocks *ctx,
        }
 }
 
-/****************************************************************************
- See if a oplock message is waiting.
-****************************************************************************/
-
-static bool linux_oplock_msg_waiting(struct kernel_oplocks *ctx)
-{
-       return oplock_signals_received != 0;
-}
-
 /****************************************************************************
  See if the kernel supports oplocks.
 ****************************************************************************/
@@ -208,16 +179,14 @@ static bool linux_oplocks_available(void)
 ****************************************************************************/
 
 static const struct kernel_oplocks_ops linux_koplocks = {
-       .receive_message        = linux_oplock_receive_message,
        .set_oplock             = linux_set_kernel_oplock,
        .release_oplock         = linux_release_kernel_oplock,
-       .msg_waiting            = linux_oplock_msg_waiting
 };
 
 struct kernel_oplocks *linux_init_kernel_oplocks(TALLOC_CTX *mem_ctx)
 {
-        struct sigaction act;
        struct kernel_oplocks *ctx;
+       struct tevent_signal *se;
 
        if (!linux_oplocks_available()) {
                DEBUG(3,("Linux kernel oplocks not available\n"));
@@ -232,19 +201,18 @@ struct kernel_oplocks *linux_init_kernel_oplocks(TALLOC_CTX *mem_ctx)
 
        ctx->ops = &linux_koplocks;
 
-       ZERO_STRUCT(act);
-
-       act.sa_handler = NULL;
-       act.sa_sigaction = signal_handler;
-       act.sa_flags = SA_SIGINFO;
-       sigemptyset( &act.sa_mask );
-       if (sigaction(RT_SIGNAL_LEASE, &act, NULL) != 0) {
-               DEBUG(0,("Failed to setup RT_SIGNAL_LEASE handler\n"));
+       se = tevent_add_signal(smbd_event_context(),
+                              ctx,
+                              RT_SIGNAL_LEASE, SA_SIGINFO,
+                              linux_oplock_signal_handler,
+                              ctx);
+       if (!se) {
+               DEBUG(0,("Failed to setup RT_SIGNAL_LEASE handler"));
+               TALLOC_FREE(ctx);
                return NULL;
        }
 
-       /* the signal can start off blocked due to a bug in bash */
-       BlockSignals(False, RT_SIGNAL_LEASE);
+       ctx->private_data = se;
 
        DEBUG(3,("Linux kernel oplocks enabled\n"));
 
index 9527d948252ea7ebfb9d1e9d78875f5ead21ec76..d617ef19157e864b695eded741136a977dd6fa5d 100644 (file)
@@ -742,46 +742,6 @@ void smbd_setup_sig_hup_handler(void)
        }
 }
 
-/****************************************************************************
- Do all async processing in here. This includes kernel oplock messages, change
- notify events etc.
-****************************************************************************/
-
-static void async_processing(void)
-{
-       DEBUG(10,("async_processing: Doing async processing.\n"));
-
-       process_aio_queue();
-
-       process_kernel_oplocks(smbd_messaging_context());
-
-       /* Do the aio check again after receive_local_message as it does a
-          select and may have eaten our signal. */
-       /* Is this till true? -- vl */
-       process_aio_queue();
-}
-
-/****************************************************************************
-  Do a select on an two fd's - with timeout. 
-
-  If a local udp message has been pushed onto the
-  queue (this can only happen during oplock break
-  processing) call async_processing()
-
-  If a pending smb message has been pushed onto the
-  queue (this can only happen during oplock break
-  processing) return this next.
-
-  If the first smbfd is ready then read an smb from it.
-  if the second (loopback UDP) fd is ready then read a message
-  from it and setup the buffer header to identify the length
-  and from address.
-  Returns False on timeout or error.
-  Else returns True.
-
-The timeout is in milliseconds
-****************************************************************************/
-
 static NTSTATUS smbd_server_connection_loop_once(struct smbd_server_connection *conn)
 {
        fd_set r_fds, w_fds;
@@ -799,26 +759,6 @@ static NTSTATUS smbd_server_connection_loop_once(struct smbd_server_connection *
        FD_ZERO(&r_fds);
        FD_ZERO(&w_fds);
 
-       /*
-        * Ensure we process oplock break messages by preference.
-        * We have to do this before the select, after the select
-        * and if the select returns EINTR. This is due to the fact
-        * that the selects called from async_processing can eat an EINTR
-        * caused by a signal (we can't take the break message there).
-        * This is hideously complex - *MUST* be simplified for 3.0 ! JRA.
-        */
-
-       if (oplock_message_waiting()) {
-               DEBUG(10,("receive_message_or_smb: oplock_message is waiting.\n"));
-               async_processing();
-               /*
-                * After async processing we must go and do the select again, as
-                * the state of the flag in fds for the server file descriptor is
-                * indeterminate - we may have done I/O on it in the oplock processing. JRA.
-                */
-               return NT_STATUS_RETRY;
-       }
-
        /*
         * Are there any timed events waiting ? If so, ensure we don't
         * select for longer than it would take to wait for them.
@@ -852,20 +792,6 @@ static NTSTATUS smbd_server_connection_loop_once(struct smbd_server_connection *
                return NT_STATUS_RETRY;
        }
 
-       /* if we get EINTR then maybe we have received an oplock
-          signal - treat this as select returning 1. This is ugly, but
-          is the best we can do until the oplock code knows more about
-          signals */
-       if (selrtn == -1 && errno == EINTR) {
-               async_processing();
-               /*
-                * After async processing we must go and do the select again, as
-                * the state of the flag in fds for the server file descriptor is
-                * indeterminate - we may have done I/O on it in the oplock processing. JRA.
-                */
-               return NT_STATUS_RETRY;
-       }
-
        /* Check if error */
        if (selrtn == -1) {
                /* something is wrong. Maybe the socket is dead? */