diff options
author | Andrew Tridgell <tridge@samba.org> | 2000-06-11 05:57:58 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2000-06-11 05:57:58 +0000 |
commit | 8843a6379d7c1cf59f0f3673cbc567b09994b7d2 (patch) | |
tree | 63f645769adeecd6cfd999a8f2d873f1c5a626b6 /source3/smbd/oplock_linux.c | |
parent | 4ec7597d1154c60f0f55feab93f2dc9c776d56f8 (diff) | |
download | samba-8843a6379d7c1cf59f0f3673cbc567b09994b7d2.tar.gz samba-8843a6379d7c1cf59f0f3673cbc567b09994b7d2.tar.xz samba-8843a6379d7c1cf59f0f3673cbc567b09994b7d2.zip |
Linux kernel oplocks now seem to work, but need a _lot_ of testing
I had to modify sys_select() to not loop on EINTR. I added a wrapper
called sys_select_intr() which gives the old behaviour.
(This used to be commit b28cc4163bc2faaa80c5782fc02c8f03c410cdeb)
Diffstat (limited to 'source3/smbd/oplock_linux.c')
-rw-r--r-- | source3/smbd/oplock_linux.c | 63 |
1 files changed, 57 insertions, 6 deletions
diff --git a/source3/smbd/oplock_linux.c b/source3/smbd/oplock_linux.c index d8496ca9ca3..73a14b3e88f 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 + |