diff options
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/oplock.c | 9 | ||||
-rw-r--r-- | source3/smbd/oplock_irix.c | 4 | ||||
-rw-r--r-- | source3/smbd/oplock_linux.c | 63 | ||||
-rw-r--r-- | source3/smbd/process.c | 107 | ||||
-rw-r--r-- | source3/smbd/server.c | 2 |
5 files changed, 125 insertions, 60 deletions
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c index 44a8e9b071..5e63b4d4ff 100644 --- a/source3/smbd/oplock.c +++ b/source3/smbd/oplock.c @@ -84,6 +84,13 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou selrtn = sys_select(maxfd+1,fds,&to); + if (selrtn == -1 && errno == EINTR) { + /* could be a kernel oplock interrupt */ + if (koplocks && koplocks->msg_waiting(fds)) { + return koplocks->receive_message(fds, buffer, buffer_len); + } + } + /* Check if error */ if(selrtn == -1) { /* something is wrong. Maybe the socket is dead? */ @@ -1120,6 +1127,8 @@ address %lx. Error was %s\n", (long)htonl(INADDR_LOOPBACK), strerror(errno))); if (lp_kernel_oplocks()) { #if HAVE_KERNEL_OPLOCKS_IRIX koplocks = irix_init_kernel_oplocks(); +#elif HAVE_KERNEL_OPLOCKS_LINUX + koplocks = linux_init_kernel_oplocks(); #endif } diff --git a/source3/smbd/oplock_irix.c b/source3/smbd/oplock_irix.c index 6eb8ff9191..8d55a3d4a0 100644 --- a/source3/smbd/oplock_irix.c +++ b/source3/smbd/oplock_irix.c @@ -1,5 +1,4 @@ #define OLD_NTDOMAIN 1 -#if HAVE_KERNEL_OPLOCKS_IRIX /* Unix SMB/Netbios implementation. @@ -24,6 +23,7 @@ #include "includes.h" +#if HAVE_KERNEL_OPLOCKS_IRIX extern int DEBUGLEVEL; @@ -227,7 +227,7 @@ should be %d).\n", msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN)); memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev)); DEBUG(5,("process_local_message: kernel oplock break request for \ -file dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode)); +file dev = %x, inode = %.0f\n", (unsigned int)*dev, (double)*inode)); return True; } diff --git a/source3/smbd/oplock_linux.c b/source3/smbd/oplock_linux.c index d8496ca9ca..73a14b3e88 100644 --- a/source3/smbd/oplock_linux.c +++ b/source3/smbd/oplock_linux.c @@ -1,5 +1,4 @@ #define OLD_NTDOMAIN 1 -#if HAVE_KERNEL_OPLOCKS_LINUX /* Unix SMB/Netbios implementation. @@ -24,12 +23,27 @@ #include "includes.h" +#if HAVE_KERNEL_OPLOCKS_LINUX + extern int DEBUGLEVEL; static unsigned signals_received; static unsigned signals_processed; static int fd_pending; /* the fd of the current pending SIGIO */ +/* these can be removed when they are in libc */ +typedef struct __user_cap_header_struct { + uint32 version; + int pid; +} *cap_user_header_t; + +typedef struct __user_cap_data_struct { + uint32 effective; + uint32 permitted; + uint32 inheritable; +} *cap_user_data_t; + + /**************************************************************************** handle a SIGIO, incrementing the signals_received and blocking SIGIO ****************************************************************************/ @@ -41,6 +55,41 @@ static void sigio_handler(int signal, siginfo_t *info, void *unused) } /**************************************************************************** +try to gain the CAP_LEASE capability +****************************************************************************/ +static void set_lease_capability(void) +{ + cap_user_header_t header; + cap_user_data_t data; + if (capget(header, data) == -1) { + DEBUG(3,("Unable to get kernel capabilities\n")); + return; + } + data->effective |= (1<<CAP_LEASE); + if (capset(header, data) == -1) { + DEBUG(3,("Unable to set CAP_LEASE capability\n")); + } +} + + +/**************************************************************************** +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; + ret = fcntl(fd, F_SETLEASE, leasetype); + if (ret == -1 && errno == EACCES) { + set_lease_capability(); + ret = fcntl(fd, F_SETLEASE, leasetype); + } + + return ret; +} + + +/**************************************************************************** * Deal with the Linux kernel <--> smbd * oplock break protocol. ****************************************************************************/ @@ -95,10 +144,11 @@ dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode )); ****************************************************************************/ static BOOL linux_set_kernel_oplock(files_struct *fsp, int oplock_type) { - if (fcntl(fsp->fd, F_SETLEASE, F_WRLCK) == -1) { + if (linux_setlease(fsp->fd, F_WRLCK) == -1) { DEBUG(5,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \ -inode = %.0f.\n", - fsp->fsp_name, fsp->fd, (unsigned int)fsp->dev, (double)fsp->inode)); +inode = %.0f. (%s)\n", + fsp->fsp_name, fsp->fd, + (unsigned int)fsp->dev, (double)fsp->inode, strerror(errno))); return False; } @@ -128,7 +178,7 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev, /* * Remove the kernel oplock on this file. */ - if (fcntl(fsp->fd, F_SETLEASE, F_UNLCK) == -1) { + 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", @@ -155,7 +205,7 @@ should be %d).\n", msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN)); memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev)); DEBUG(5,("process_local_message: kernel oplock break request for \ -file dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode)); +file dev = %x, inode = %.0f\n", (unsigned int)*dev, (double)*inode)); return True; } @@ -203,3 +253,4 @@ struct kernel_oplocks *linux_init_kernel_oplocks(void) #endif /* HAVE_KERNEL_OPLOCKS_LINUX */ #undef OLD_NTDOMAIN + diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 82e61a138e..30d03747d8 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -134,69 +134,74 @@ The timeout is in milli seconds static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout, BOOL *got_smb) { - fd_set fds; - int selrtn; - struct timeval to; - int maxfd; + fd_set fds; + int selrtn; + struct timeval to; + int maxfd; - smb_read_error = 0; + smb_read_error = 0; - *got_smb = False; + *got_smb = False; - /* - * Check to see if we already have a message on the smb queue. - * If so - copy and return it. - */ + /* + * Check to see if we already have a message on the smb queue. + * If so - copy and return it. + */ - if(ubi_slCount(&smb_oplock_queue) != 0) - { - pending_message_list *msg = (pending_message_list *)ubi_slRemHead(&smb_oplock_queue); - memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len)); + if(ubi_slCount(&smb_oplock_queue) != 0) { + pending_message_list *msg = (pending_message_list *)ubi_slRemHead(&smb_oplock_queue); + memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len)); - /* Free the message we just copied. */ - free((char *)msg->msg_buf); - free((char *)msg); - *got_smb = True; + /* Free the message we just copied. */ + free((char *)msg->msg_buf); + free((char *)msg); + *got_smb = True; + + DEBUG(5,("receive_message_or_smb: returning queued smb message.\n")); + return True; + } - DEBUG(5,("receive_message_or_smb: returning queued smb message.\n")); - return True; - } + /* + * Setup the select read fd set. + */ - /* - * Setup the select read fd set. - */ + FD_ZERO(&fds); + FD_SET(smbd_server_fd(),&fds); + maxfd = setup_oplock_select_set(&fds); - FD_ZERO(&fds); - FD_SET(smbd_server_fd(),&fds); - maxfd = setup_oplock_select_set(&fds); + to.tv_sec = timeout / 1000; + to.tv_usec = (timeout % 1000) * 1000; - to.tv_sec = timeout / 1000; - to.tv_usec = (timeout % 1000) * 1000; + selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,timeout>0?&to:NULL); - selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,timeout>0?&to:NULL); + /* 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) { + FD_ZERO(&fds); + selrtn = 1; + } - /* Check if error */ - if(selrtn == -1) { - /* something is wrong. Maybe the socket is dead? */ - smb_read_error = READ_ERROR; - return False; - } + /* Check if error */ + if(selrtn == -1 && errno != EINTR) { + /* something is wrong. Maybe the socket is dead? */ + smb_read_error = READ_ERROR; + return False; + } - /* Did we timeout ? */ - if (selrtn == 0) { - smb_read_error = READ_TIMEOUT; - return False; - } - - if (FD_ISSET(smbd_server_fd(),&fds)) - { - *got_smb = True; - return receive_smb(smbd_server_fd(), buffer, 0); - } - else - { - return receive_local_message(&fds, buffer, buffer_len, 0); - } + /* Did we timeout ? */ + if (selrtn == 0) { + smb_read_error = READ_TIMEOUT; + return False; + } + + if (FD_ISSET(smbd_server_fd(),&fds)) { + *got_smb = True; + return receive_smb(smbd_server_fd(), buffer, 0); + } else { + return receive_local_message(&fds, buffer, buffer_len, 0); + } } /**************************************************************************** diff --git a/source3/smbd/server.c b/source3/smbd/server.c index ecf1deb05a..a5da156250 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -203,7 +203,7 @@ max can be %d\n", memcpy((char *)&lfds, (char *)&listen_set, sizeof(listen_set)); - num = sys_select(FD_SETSIZE,&lfds,NULL); + num = sys_select_intr(FD_SETSIZE,&lfds,NULL); if (num == -1 && errno == EINTR) continue; |