r6586: get rid of a few more compiler warnings
[vlendec/samba-autobuild/.git] / source3 / smbd / oplock_linux.c
index d97378ac5df08206a55a40e521b129bffe648cf5..6d1bc64ce102d974055425f8d35370e5184cdcf9 100644 (file)
@@ -1,8 +1,5 @@
-#define OLD_NTDOMAIN 1
-
 /* 
-   Unix SMB/Netbios implementation.
-   Version 3.0
+   Unix SMB/CIFS implementation.
    kernel oplock processing for Linux
    Copyright (C) Andrew Tridgell 2000
    
 
 #if HAVE_KERNEL_OPLOCKS_LINUX
 
-extern int DEBUGLEVEL;
-
-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
@@ -44,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,34 +63,27 @@ static VOLATILE SIG_ATOMIC_T fd_pending; /* the fd of the current pending signal
 #endif
 
 /****************************************************************************
-handle a LEASE signal, incrementing the signals_received and blocking the signal
+ Handle a LEASE signal, incrementing the signals_received and blocking the signal.
 ****************************************************************************/
-static void signal_handler(int signal, siginfo_t *info, void *unused)
+
+static void signal_handler(int sig, siginfo_t *info, void *unused)
 {
-       BlockSignals(True, signal);
-       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();
 }
 
 /****************************************************************************
-try to gain a linux capability
-****************************************************************************/static void set_capability(unsigned capability)
+ Try to gain a linux capability.
+****************************************************************************/
+
+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;
 
@@ -96,11 +100,11 @@ try to gain a linux capability
        }
 }
 
-
 /****************************************************************************
-call SETLEASE. If we get EACCES then we try setting up the right capability and
-try again
+ Call SETLEASE. If we get EACCES then we try setting up the right capability and
+ try again
 ****************************************************************************/
+
 static int linux_setlease(int fd, int leasetype)
 {
        int ret;
@@ -119,31 +123,36 @@ static int linux_setlease(int fd, int leasetype)
        return ret;
 }
 
-
 /****************************************************************************
  * Deal with the Linux kernel <--> smbd
  * oplock break protocol.
 ****************************************************************************/
+
 static BOOL linux_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len)
 {
-       SMB_DEV_T dev;
-       SMB_INO_T inode;
-       SMB_STRUCT_STAT sbuf;
-       BOOL ret;
-
-       if (signals_received == signals_processed) return False;
+       int fd;
+       struct 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 (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 (sys_fstat((int)fd_pending,&sbuf) == -1) {
-               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;
        }
 
-       dev = sbuf.st_dev;
-       inode = sbuf.st_ino;
-     
-       DEBUG(3,("receive_local_message: kernel oplock break request received for \
-dev = %x, inode = %.0f\n", (unsigned int)dev, (double)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.
@@ -157,42 +166,37 @@ dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ));
      
        SSVAL(buffer,OPBRK_MESSAGE_CMD_OFFSET,KERNEL_OPLOCK_BREAK_CMD);
      
-       memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&dev, sizeof(dev));
-       memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&inode, sizeof(inode));       
+       memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&fsp->dev, sizeof(fsp->dev));
+       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 True;
 }
 
-
 /****************************************************************************
  Attempt to set an kernel oplock on a file.
 ****************************************************************************/
+
 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\n",
-                 fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode));
+       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;
 }
 
-
 /****************************************************************************
  Release a kernel oplock on a file.
 ****************************************************************************/
+
 static void linux_release_kernel_oplock(files_struct *fsp)
 {
        if (DEBUGLVL(10)) {
@@ -201,9 +205,9 @@ 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 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, state );
+                        (double)fsp->inode, fsp->file_id, state );
        }
 
        /*
@@ -211,62 +215,66 @@ 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("%s, dev = %x, inode = %.0f. Error was %s\n",
+                       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, strerror(errno) );
+                               (double)fsp->inode, fsp->file_id, strerror(errno) );
                }
        }
 }
 
-
 /****************************************************************************
-parse a kernel oplock message
+ Parse a kernel oplock message.
 ****************************************************************************/
-static BOOL linux_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *inode, SMB_DEV_T *dev)
+
+static BOOL linux_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *inode,
+               SMB_DEV_T *dev, unsigned long *file_id)
 {
        /* 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;
        }
 
-        memcpy((char *)inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(*inode));
-        memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev));
+       memcpy((char *)inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(*inode));
+       memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev));
+       memcpy((char *)file_id, msg_start+KERNEL_OPLOCK_BREAK_FILEID_OFFSET, sizeof(*file_id));
 
-        DEBUG(3,("kernel oplock break request for file dev = %x, inode = %.0f\n", 
-                (unsigned int)*dev, (double)*inode));
+       DEBUG(3,("kernel oplock break request for file dev = %x, inode = %.0f, file_id = %lu\n", 
+               (unsigned int)*dev, (double)*inode, *file_id));
 
        return True;
 }
 
-
 /****************************************************************************
-see if a oplock message is waiting
+ See if a oplock message is waiting.
 ****************************************************************************/
+
 static BOOL linux_oplock_msg_waiting(fd_set *fds)
 {
-       return signals_processed != signals_received;
+       return signals_received != 0;
 }
 
 /****************************************************************************
-see if the kernel supports oplocks
+ See if the kernel supports oplocks.
 ****************************************************************************/
+
 static BOOL linux_oplocks_available(void)
 {
        int fd, ret;
        fd = open("/dev/null", O_RDONLY);
-       if (fd == -1) return False; /* uggh! */
+       if (fd == -1)
+               return False; /* uggh! */
        ret = fcntl(fd, F_GETLEASE, 0);
        close(fd);
        return ret == F_UNLCK;
 }
 
-
 /****************************************************************************
-setup kernel oplocks
+ Setup kernel oplocks.
 ****************************************************************************/
+
 struct kernel_oplocks *linux_init_kernel_oplocks(void) 
 {
        static struct kernel_oplocks koplocks;
@@ -277,13 +285,16 @@ struct kernel_oplocks *linux_init_kernel_oplocks(void)
                return NULL;
        }
 
-        act.sa_handler = NULL;
-        act.sa_sigaction = signal_handler;
-        act.sa_flags = SA_SIGINFO;
-        if (sigaction(RT_SIGNAL_LEASE, &act, NULL) != 0) {
+       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;
-        }
+       }
 
        koplocks.receive_message = linux_oplock_receive_message;
        koplocks.set_oplock = linux_set_kernel_oplock;
@@ -292,16 +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 */
-
-#undef OLD_NTDOMAIN
-