r6586: get rid of a few more compiler warnings
[tprouty/samba.git] / source / smbd / oplock_linux.c
index d9465783807e830d1eff32ca46806824ec8f5c5f..6d1bc64ce102d974055425f8d35370e5184cdcf9 100644 (file)
 
 #if HAVE_KERNEL_OPLOCKS_LINUX
 
-static VOLATILE sig_atomic_t signals_received;
-static VOLATILE sig_atomic_t signals_processed;
-static VOLATILE sig_atomic_t fd_pending; /* the fd of the current pending signal */
+/* these can be removed when they are in glibc headers */
+struct  cap_user_header {
+       uint32 version;
+       int pid;
+} header;
+struct cap_user_data {
+       uint32 effective;
+       uint32 permitted;
+       uint32 inheritable;
+} data;
+
+extern int capget(struct cap_user_header * hdrp,
+                 struct cap_user_data * datap);
+extern int capset(struct cap_user_header * hdrp,
+                 const struct cap_user_data * datap);
+
+static SIG_ATOMIC_T signals_received;
+#define FD_PENDING_SIZE 100
+static SIG_ATOMIC_T fd_pending_array[FD_PENDING_SIZE];
 
 #ifndef F_SETLEASE
 #define F_SETLEASE     1024
@@ -39,7 +55,7 @@ static VOLATILE sig_atomic_t fd_pending; /* the fd of the current pending signal
 #endif
 
 #ifndef RT_SIGNAL_LEASE
-#define RT_SIGNAL_LEASE 33
+#define RT_SIGNAL_LEASE (SIGRTMIN+1)
 #endif
 
 #ifndef F_SETSIG
@@ -52,9 +68,10 @@ static VOLATILE sig_atomic_t fd_pending; /* the fd of the current pending signal
 
 static void signal_handler(int sig, siginfo_t *info, void *unused)
 {
-       BlockSignals(True, sig);
-       fd_pending = (sig_atomic_t)info->si_fd;
-       signals_received++;
+       if (signals_received < FD_PENDING_SIZE - 1) {
+               fd_pending_array[signals_received] = (SIG_ATOMIC_T)info->si_fd;
+               signals_received++;
+       } /* Else signal is lost. */
        sys_select_signal();
 }
 
@@ -67,17 +84,6 @@ static void set_capability(unsigned capability)
 #ifndef _LINUX_CAPABILITY_VERSION
 #define _LINUX_CAPABILITY_VERSION 0x19980330
 #endif
-       /* these can be removed when they are in glibc headers */
-       struct  {
-               uint32 version;
-               int pid;
-       } header;
-       struct {
-               uint32 effective;
-               uint32 permitted;
-               uint32 inheritable;
-       } data;
-
        header.version = _LINUX_CAPABILITY_VERSION;
        header.pid = 0;
 
@@ -124,20 +130,29 @@ static int linux_setlease(int fd, int leasetype)
 
 static BOOL linux_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len)
 {
-       BOOL ret = True;
+       int fd;
        struct files_struct *fsp;
 
-       if (signals_received == signals_processed)
-               return False;
+       BlockSignals(True, RT_SIGNAL_LEASE);
+       fd = fd_pending_array[0];
+       fsp = file_find_fd(fd);
+       fd_pending_array[0] = (SIG_ATOMIC_T)-1;
+       if (signals_received > 1)
+                memmove(CONST_DISCARD(void *, &fd_pending_array[0]),
+                        CONST_DISCARD(void *, &fd_pending_array[1]),
+                       sizeof(SIG_ATOMIC_T)*(signals_received-1));
+       signals_received--;
+       /* now we can receive more signals */
+       BlockSignals(False, RT_SIGNAL_LEASE);
 
-       if ((fsp = file_find_fd(fd_pending)) == NULL) {
-               DEBUG(0,("Invalid file descriptor %d in kernel oplock break!\n", (int)fd_pending));
-               ret = False;
-               goto out;
+       if (fsp == NULL) {
+               DEBUG(0,("Invalid file descriptor %d in kernel oplock break!\n", (int)fd));
+               return False;
        }
 
-       DEBUG(3,("receive_local_message: kernel oplock break request received for \
-dev = %x, inode = %.0f\n", (unsigned int)fsp->dev, (double)fsp->inode ));
+       DEBUG(3,("linux_oplock_receive_message: kernel oplock break request received for \
+dev = %x, inode = %.0f fd = %d, fileid = %lu \n", (unsigned int)fsp->dev, (double)fsp->inode,
+                       fd, fsp->file_id));
      
        /*
         * Create a kernel oplock break message.
@@ -155,13 +170,7 @@ dev = %x, inode = %.0f\n", (unsigned int)fsp->dev, (double)fsp->inode ));
        memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&fsp->inode, sizeof(fsp->inode));     
        memcpy(buffer + KERNEL_OPLOCK_BREAK_FILEID_OFFSET, (char *)&fsp->file_id, sizeof(fsp->file_id));        
 
- out:
-       /* now we can receive more signals */
-       fd_pending = (sig_atomic_t)-1;
-       signals_processed++;
-       BlockSignals(False, RT_SIGNAL_LEASE);
-     
-       return ret;
+       return True;
 }
 
 /****************************************************************************
@@ -171,14 +180,14 @@ dev = %x, inode = %.0f\n", (unsigned int)fsp->dev, (double)fsp->inode ));
 static BOOL linux_set_kernel_oplock(files_struct *fsp, int oplock_type)
 {
        if (linux_setlease(fsp->fd, F_WRLCK) == -1) {
-               DEBUG(3,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
+               DEBUG(3,("linux_set_kernel_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
 inode = %.0f. (%s)\n",
                         fsp->fsp_name, fsp->fd, 
                         (unsigned int)fsp->dev, (double)fsp->inode, strerror(errno)));
                return False;
        }
        
-       DEBUG(3,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %lu\n",
+       DEBUG(3,("linux_set_kernel_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %lu\n",
                  fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id));
 
        return True;
@@ -196,7 +205,7 @@ static void linux_release_kernel_oplock(files_struct *fsp)
                 * oplock state of this file.
                 */
                int state = fcntl(fsp->fd, F_GETLEASE, 0);
-               dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %lu has kernel \
+               dbgtext("linux_release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %lu has kernel \
 oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
                         (double)fsp->inode, fsp->file_id, state );
        }
@@ -206,7 +215,7 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
         */
        if (linux_setlease(fsp->fd, F_UNLCK) == -1) {
                if (DEBUGLVL(0)) {
-                       dbgtext("release_kernel_oplock: Error when removing kernel oplock on file " );
+                       dbgtext("linux_release_kernel_oplock: Error when removing kernel oplock on file " );
                        dbgtext("%s, dev = %x, inode = %.0f, file_id = %lu. Error was %s\n",
                                fsp->fsp_name, (unsigned int)fsp->dev, 
                                (double)fsp->inode, fsp->file_id, strerror(errno) );
@@ -223,8 +232,8 @@ static BOOL linux_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *i
 {
        /* Ensure that the msg length is correct. */
        if (msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN) {
-               DEBUG(0,("incorrect length for KERNEL_OPLOCK_BREAK_CMD (was %d, should be %d).\n", 
-                        msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN));
+               DEBUG(0,("incorrect length for KERNEL_OPLOCK_BREAK_CMD (was %d, should be %lu).\n", 
+                        msg_len, (unsigned long)KERNEL_OPLOCK_BREAK_MSG_LEN));
                return False;
        }
 
@@ -244,7 +253,7 @@ static BOOL linux_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *i
 
 static BOOL linux_oplock_msg_waiting(fd_set *fds)
 {
-       return signals_processed != signals_received;
+       return signals_received != 0;
 }
 
 /****************************************************************************
@@ -276,9 +285,12 @@ struct kernel_oplocks *linux_init_kernel_oplocks(void)
                return NULL;
        }
 
+       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"));
                return NULL;
@@ -291,10 +303,15 @@ struct kernel_oplocks *linux_init_kernel_oplocks(void)
        koplocks.msg_waiting = linux_oplock_msg_waiting;
        koplocks.notification_fd = -1;
 
+       /* the signal can start off blocked due to a bug in bash */
+       BlockSignals(False, RT_SIGNAL_LEASE);
+
        DEBUG(3,("Linux kernel oplocks enabled\n"));
 
        return &koplocks;
 }
 #else
+ void oplock_linux_dummy(void);
+
  void oplock_linux_dummy(void) {}
 #endif /* HAVE_KERNEL_OPLOCKS_LINUX */