summaryrefslogtreecommitdiff
path: root/source3/smbd/oplock_linux.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2000-06-11 05:57:58 +0000
committerAndrew Tridgell <tridge@samba.org>2000-06-11 05:57:58 +0000
commit8843a6379d7c1cf59f0f3673cbc567b09994b7d2 (patch)
tree63f645769adeecd6cfd999a8f2d873f1c5a626b6 /source3/smbd/oplock_linux.c
parent4ec7597d1154c60f0f55feab93f2dc9c776d56f8 (diff)
downloadsamba-8843a6379d7c1cf59f0f3673cbc567b09994b7d2.tar.gz
samba-8843a6379d7c1cf59f0f3673cbc567b09994b7d2.tar.bz2
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.c63
1 files changed, 57 insertions, 6 deletions
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
+