summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/proto.h13
-rw-r--r--source3/include/smb.h14
-rw-r--r--source3/lib/system.c2
-rw-r--r--source3/param/loadparm.c32
-rw-r--r--source3/smbd/oplock.c499
-rw-r--r--source3/smbd/oplock_irix.c282
-rw-r--r--source3/smbd/server.c23
7 files changed, 436 insertions, 429 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 9563b432fd..4d57740877 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -1339,6 +1339,7 @@ BOOL lp_stat_cache(void);
BOOL lp_allow_trusted_domains(void);
BOOL lp_restrict_anonymous(void);
BOOL lp_host_msdfs(void);
+BOOL lp_kernel_oplocks(void);
int lp_os_level(void);
int lp_max_ttl(void);
int lp_max_wins_ttl(void);
@@ -1491,8 +1492,6 @@ int lp_default_server_announce(void);
int lp_major_announce_version(void);
int lp_minor_announce_version(void);
void lp_set_name_resolve_order(char *new_order);
-void lp_set_kernel_oplocks(BOOL val);
-BOOL lp_kernel_oplocks(void);
int lp_security_mask(int snum);
int lp_force_security_mode(int snum);
int lp_dir_security_mask(int snum);
@@ -3277,8 +3276,6 @@ BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op);
#if OLD_NTDOMAIN
int32 get_number_of_exclusive_open_oplocks(void);
-BOOL setup_kernel_oplock_pipe(void);
-BOOL open_oplock_ipc(void);
BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeout);
BOOL set_file_oplock(files_struct *fsp, int oplock_type);
void release_file_oplock(files_struct *fsp);
@@ -3289,7 +3286,13 @@ BOOL oplock_break_level2(files_struct *fsp, BOOL local_request, int token);
BOOL request_oplock_break(share_mode_entry *share_entry,
SMB_DEV_T dev, SMB_INO_T inode);
BOOL attempt_close_oplocked_file(files_struct *fsp);
-void check_kernel_oplocks(void);
+BOOL init_oplocks(void);
+#endif
+
+/*The following definitions come from smbd/oplock_irix.c */
+
+#if OLD_NTDOMAIN
+struct kernel_oplocks *irix_init_kernel_oplocks(void) ;
#endif
/*The following definitions come from smbd/password.c */
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 91f0e04b48..d2c79e3b53 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -1598,6 +1598,7 @@ extern int chain_size;
#define OPLOCK_BREAK_INODE_OFFSET (OPLOCK_BREAK_DEV_OFFSET + sizeof(SMB_DEV_T))
#define OPLOCK_BREAK_MSG_LEN (OPLOCK_BREAK_INODE_OFFSET + sizeof(SMB_INO_T))
+#define KERNEL_OPLOCK_BREAK_CMD 0x2
#define LEVEL_II_OPLOCK_BREAK_CMD 0x3
/*
@@ -1618,13 +1619,24 @@ extern int chain_size;
* +----+--------+--------+
*/
-#define KERNEL_OPLOCK_BREAK_CMD 0x2
#define KERNEL_OPLOCK_BREAK_DEV_OFFSET 2
#define KERNEL_OPLOCK_BREAK_INODE_OFFSET (KERNEL_OPLOCK_BREAK_DEV_OFFSET + sizeof(SMB_DEV_T))
#define KERNEL_OPLOCK_BREAK_MSG_LEN (KERNEL_OPLOCK_BREAK_INODE_OFFSET + sizeof(SMB_INO_T))
#endif /* HAVE_KERNEL_OPLOCKS_IRIX */
+/* if a kernel does support oplocks then a structure of the following
+ typee is used to describe how to interact with the kernel */
+struct kernel_oplocks {
+ BOOL (*receive_message)(fd_set *fds, char *buffer, int buffer_len);
+ BOOL (*set_oplock)(files_struct *fsp, int oplock_type);
+ void (*release_oplock)(files_struct *fsp);
+ BOOL (*parse_message)(char *msg_start, int msg_len, SMB_INO_T *inode, SMB_DEV_T *dev);
+ BOOL (*msg_waiting)(fd_set *fds);
+ int notification_fd;
+};
+
+
#define CMD_REPLY 0x8000
#include "smb_macros.h"
diff --git a/source3/lib/system.c b/source3/lib/system.c
index 3a9cca6a72..2a99ae779e 100644
--- a/source3/lib/system.c
+++ b/source3/lib/system.c
@@ -391,6 +391,8 @@ int sys_chroot(const char *dname)
DEBUG(1,("WARNING: no chroot!\n"));
done=1;
}
+ errno = ENOSYS;
+ return -1;
#else
return(chroot(dname));
#endif
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 8f23d20796..ef62fc82ca 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -1429,6 +1429,7 @@ FN_GLOBAL_BOOL(lp_stat_cache, &Globals.bStatCache)
FN_GLOBAL_BOOL(lp_allow_trusted_domains, &Globals.bAllowTrustedDomains)
FN_GLOBAL_BOOL(lp_restrict_anonymous, &Globals.bRestrictAnonymous)
FN_GLOBAL_BOOL(lp_host_msdfs, &Globals.bHostMSDfs)
+FN_GLOBAL_BOOL(lp_kernel_oplocks, &Globals.bKernelOplocks)
FN_GLOBAL_INTEGER(lp_os_level, &Globals.os_level)
FN_GLOBAL_INTEGER(lp_max_ttl, &Globals.max_ttl)
FN_GLOBAL_INTEGER(lp_max_wins_ttl, &Globals.max_wins_ttl)
@@ -3439,37 +3440,6 @@ void lp_set_name_resolve_order(char *new_order)
}
/***********************************************************
- Set the flag that says if kernel oplocks are available
- (called by smbd).
-************************************************************/
-
-static BOOL kernel_oplocks_available = False;
-
-void lp_set_kernel_oplocks(BOOL val)
-{
- /*
- * Only set this to True if kerenl
- * oplocks are really available and were
- * turned on in the smb.conf file.
- */
-
- if (Globals.bKernelOplocks && val)
- kernel_oplocks_available = True;
- else
- kernel_oplocks_available = False;
-}
-
-/***********************************************************
- Return True if kernel oplocks are available and were turned
- on in smb.conf.
-************************************************************/
-
-BOOL lp_kernel_oplocks(void)
-{
- return kernel_oplocks_available;
-}
-
-/***********************************************************
Functions to return the current security masks/modes. If
set to -1 then return the create mask/mode instead.
************************************************************/
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index af48b06ab0..33d82f3dde 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -28,11 +28,6 @@ extern int DEBUGLEVEL;
/* Oplock ipc UDP socket. */
static int oplock_sock = -1;
uint16 global_oplock_port = 0;
-static int oplock_pipe_read = -1;
-
-#if defined(HAVE_KERNEL_OPLOCKS_IRIX)
-static int oplock_pipe_write = -1;
-#endif
/* Current number of oplocks we have outstanding. */
static int32 exclusive_oplocks_open = 0;
@@ -42,6 +37,8 @@ BOOL global_oplock_break = False;
extern int smb_read_error;
+static struct kernel_oplocks *koplocks;
+
static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, BOOL local);
/****************************************************************************
@@ -54,200 +51,9 @@ int32 get_number_of_exclusive_open_oplocks(void)
}
-#if HAVE_KERNEL_OPLOCKS_IRIX
-/****************************************************************************
-test to see if IRIX kernel oplocks work
-****************************************************************************/
-static BOOL irix_oplocks_available(void)
-{
- int fd;
- int pfd[2];
- pstring tmpname;
-
- oplock_set_capability(True, True);
-
- slprintf(tmpname,sizeof(tmpname)-1, "%s/koplock.%d", lp_lockdir(), (int)sys_getpid());
-
- if(pipe(pfd) != 0) {
- DEBUG(0,("check_kernel_oplocks: Unable to create pipe. Error was %s\n",
- strerror(errno) ));
- return False;
- }
-
- if((fd = sys_open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600)) < 0) {
- DEBUG(0,("check_kernel_oplocks: Unable to open temp test file %s. Error was %s\n",
- tmpname, strerror(errno) ));
- unlink( tmpname );
- close(pfd[0]);
- close(pfd[1]);
- return False;
- }
-
- unlink( tmpname );
-
- if(fcntl(fd, F_OPLKREG, pfd[1]) == -1) {
- DEBUG(0,("check_kernel_oplocks: Kernel oplocks are not available on this machine. \
-Disabling kernel oplock support.\n" ));
- close(pfd[0]);
- close(pfd[1]);
- close(fd);
- return False;
- }
-
- if(fcntl(fd, F_OPLKACK, OP_REVOKE) < 0 ) {
- DEBUG(0,("check_kernel_oplocks: Error when removing kernel oplock. Error was %s. \
-Disabling kernel oplock support.\n", strerror(errno) ));
- close(pfd[0]);
- close(pfd[1]);
- close(fd);
- return False;
- }
-
- close(pfd[0]);
- close(pfd[1]);
- close(fd);
-
- return True;
-}
-#endif
-
-/****************************************************************************
- Setup the kernel level oplock backchannel for this process.
-****************************************************************************/
-BOOL setup_kernel_oplock_pipe(void)
-{
-#if defined(HAVE_KERNEL_OPLOCKS_IRIX)
- if(lp_kernel_oplocks()) {
- int pfd[2];
-
- if(pipe(pfd) != 0) {
- DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. Error was %s\n",
- strerror(errno) ));
- return False;
- }
-
- oplock_pipe_read = pfd[0];
- oplock_pipe_write = pfd[1];
- }
-#endif /* HAVE_KERNEL_OPLOCKS_IRIX */
- return True;
-}
-
-/****************************************************************************
- Open the oplock IPC socket communication.
-****************************************************************************/
-
-BOOL open_oplock_ipc(void)
-{
- struct sockaddr_in sock_name;
- int len = sizeof(sock_name);
-
- DEBUG(3,("open_oplock_ipc: opening loopback UDP socket.\n"));
-
- /* Open a lookback UDP socket on a random port. */
- oplock_sock = open_socket_in(SOCK_DGRAM, 0, 0, htonl(INADDR_LOOPBACK),False);
- if (oplock_sock == -1)
- {
- DEBUG(0,("open_oplock_ipc: Failed to get local UDP socket for \
-address %lx. Error was %s\n", (long)htonl(INADDR_LOOPBACK), strerror(errno)));
- global_oplock_port = 0;
- return(False);
- }
-
- /* Find out the transient UDP port we have been allocated. */
- if(getsockname(oplock_sock, (struct sockaddr *)&sock_name, &len)<0)
- {
- DEBUG(0,("open_oplock_ipc: Failed to get local UDP port. Error was %s\n",
- strerror(errno)));
- close(oplock_sock);
- oplock_sock = -1;
- global_oplock_port = 0;
- return False;
- }
- global_oplock_port = ntohs(sock_name.sin_port);
-
- if(!setup_kernel_oplock_pipe())
- return False;
-
- DEBUG(3,("open_oplock ipc: pid = %d, global_oplock_port = %u\n",
- (int)sys_getpid(), global_oplock_port));
-
- return True;
-}
-
-#if defined(HAVE_KERNEL_OPLOCKS_IRIX)
-/****************************************************************************
- * Deal with the IRIX kernel <--> smbd
- * oplock break protocol.
-****************************************************************************/
-static BOOL irix_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len, int timeout)
-{
- oplock_stat_t os;
- SMB_DEV_T dev;
- SMB_INO_T inode;
- char dummy;
-
- /*
- * Read one byte of zero to clear the
- * kernel break notify message.
- */
-
- if(read(oplock_pipe_read, &dummy, 1) != 1) {
- DEBUG(0,("receive_local_message: read of kernel notification failed. \
-Error was %s.\n", strerror(errno) ));
- smb_read_error = READ_ERROR;
- return False;
- }
-
- /*
- * Do a query to get the
- * device and inode of the file that has the break
- * request outstanding.
- */
-
- if(fcntl(oplock_pipe_read, F_OPLKSTAT, &os) < 0) {
- DEBUG(0,("receive_local_message: fcntl of kernel notification failed. \
-Error was %s.\n", strerror(errno) ));
- if(errno == EAGAIN) {
- /*
- * Duplicate kernel break message - ignore.
- */
- memset(buffer, '\0', KERNEL_OPLOCK_BREAK_MSG_LEN);
- return True;
- }
- smb_read_error = READ_ERROR;
- return False;
- }
-
- dev = (SMB_DEV_T)os.os_dev;
- inode = (SMB_INO_T)os.os_ino;
-
- DEBUG(5,("receive_local_message: kernel oplock break request received for \
-dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ));
-
- /*
- * Create a kernel oplock break message.
- */
-
- /* Setup the message header */
- SIVAL(buffer,OPBRK_CMD_LEN_OFFSET,KERNEL_OPLOCK_BREAK_MSG_LEN);
- SSVAL(buffer,OPBRK_CMD_PORT_OFFSET,0);
-
- buffer += OPBRK_CMD_HEADER_LEN;
-
- 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));
-
- return True;
-}
-#endif /* HAVE_KERNEL_OPLOCKS_IRIX */
-
-
/****************************************************************************
Read an oplock break message from either the oplock UDP fd or the
- kernel oplock pipe fd (if kernel oplocks are supported).
+ kernel (if kernel oplocks are supported).
If timeout is zero then *fds contains the file descriptors that
are ready to be read and acted upon. If timeout is non-zero then
@@ -269,8 +75,9 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou
int selrtn;
int maxfd = oplock_sock;
- if(lp_kernel_oplocks() && (oplock_pipe_read != -1))
- maxfd = MAX(maxfd, oplock_pipe_read);
+ if (koplocks && koplocks->notification_fd != -1) {
+ FD_SET(koplocks->notification_fd, fds);
+ }
to.tv_sec = timeout / 1000;
to.tv_usec = (timeout % 1000) * 1000;
@@ -291,11 +98,9 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou
}
}
-#if HAVE_KERNEL_OPLOCKS_IRIX
- if (FD_ISSET(oplock_pipe_read,fds)) {
- return irix_receive_message(fds, buffer, buffer_len, timeout);
+ if (koplocks && koplocks->msg_waiting(fds)) {
+ return koplocks->receive_message(fds, buffer, buffer_len);
}
-#endif
/*
* From here down we deal with the smbd <--> smbd
@@ -337,42 +142,12 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou
}
/****************************************************************************
- Attempt to set an kernel oplock on a file. Always returns True if kernel
- oplocks not available.
-****************************************************************************/
-static BOOL set_kernel_oplock(files_struct *fsp, int oplock_type)
-{
- if(!lp_kernel_oplocks()) return True;
-
-#if defined(HAVE_KERNEL_OPLOCKS_IRIX)
- if (fcntl(fsp->fd, F_OPLKREG, oplock_pipe_write) < 0 ) {
- if(errno != EAGAIN) {
- DEBUG(0,("set_file_oplock: Unable to get kernel oplock on file %s, dev = %x, \
-inode = %.0f. Error was %s\n",
- fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode,
- strerror(errno) ));
- } else {
- DEBUG(5,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
-inode = %.0f. Another process had the file open.\n",
- fsp->fsp_name, fsp->fd, (unsigned int)fsp->dev, (double)fsp->inode ));
- }
- return False;
- }
-
- DEBUG(10,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f\n",
- fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode));
-#endif /* HAVE_KERNEL_OPLOCKS_IRIX */
-
- return True;
-}
-
-/****************************************************************************
Attempt to set an oplock on a file. Always succeeds if kernel oplocks are
disabled (just sets flags). Returns True if oplock set.
****************************************************************************/
BOOL set_file_oplock(files_struct *fsp, int oplock_type)
{
- if (!set_kernel_oplock(fsp, oplock_type))
+ if (koplocks && !koplocks->set_oplock(fsp, oplock_type))
return False;
fsp->oplock_type = oplock_type;
@@ -390,46 +165,12 @@ BOOL set_file_oplock(files_struct *fsp, int oplock_type)
}
/****************************************************************************
- Release a kernel oplock on a file.
-****************************************************************************/
-static void release_kernel_oplock(files_struct *fsp)
-{
- if (!lp_kernel_oplocks()) return;
-
-#if defined(HAVE_KERNEL_OPLOCKS_IRIX)
- if (DEBUGLVL(10)) {
- /*
- * Check and print out the current kernel
- * oplock state of this file.
- */
- int state = fcntl(fsp->fd, F_OPLKACK, -1);
- dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f has kernel \
-oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
- (double)fsp->inode, state );
- }
-
- /*
- * Remove the kernel oplock on this file.
- */
- if(fcntl(fsp->fd, F_OPLKACK, OP_REVOKE) < 0) {
- if( DEBUGLVL( 0 )) {
- dbgtext("release_kernel_oplock: Error when removing kernel oplock on file " );
- dbgtext("%s, dev = %x, inode = %.0f. Error was %s\n",
- fsp->fsp_name, (unsigned int)fsp->dev,
- (double)fsp->inode, strerror(errno) );
- }
- }
-#endif /* HAVE_KERNEL_OPLOCKS_IRIX */
-}
-
-
-/****************************************************************************
Attempt to release an oplock on a file. Decrements oplock count.
****************************************************************************/
void release_file_oplock(files_struct *fsp)
{
- release_kernel_oplock(fsp);
+ if (koplocks) koplocks->release_oplock(fsp);
if (fsp->oplock_type == LEVEL_II_OPLOCK)
level_II_oplocks_open--;
@@ -448,11 +189,11 @@ void release_file_oplock(files_struct *fsp)
static void downgrade_file_oplock(files_struct *fsp)
{
- release_kernel_oplock(fsp);
- fsp->oplock_type = LEVEL_II_OPLOCK;
- exclusive_oplocks_open--;
- level_II_oplocks_open++;
- fsp->sent_oplock_break = NO_BREAK_SENT;
+ if (koplocks) koplocks->release_oplock(fsp);
+ fsp->oplock_type = LEVEL_II_OPLOCK;
+ exclusive_oplocks_open--;
+ level_II_oplocks_open++;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
}
/****************************************************************************
@@ -462,48 +203,44 @@ static void downgrade_file_oplock(files_struct *fsp)
BOOL remove_oplock(files_struct *fsp)
{
- SMB_DEV_T dev = fsp->dev;
- SMB_INO_T inode = fsp->inode;
- BOOL ret = True;
-
- /* Remove the oplock flag from the sharemode. */
- if (lock_share_entry_fsp(fsp) == False) {
- DEBUG(0,("remove_oplock: failed to lock share entry for file %s\n",
- fsp->fsp_name ));
- ret = False;
- }
-
- if (fsp->sent_oplock_break == EXCLUSIVE_BREAK_SENT) {
+ SMB_DEV_T dev = fsp->dev;
+ SMB_INO_T inode = fsp->inode;
+ BOOL ret = True;
+
+ /* Remove the oplock flag from the sharemode. */
+ if (lock_share_entry_fsp(fsp) == False) {
+ DEBUG(0,("remove_oplock: failed to lock share entry for file %s\n",
+ fsp->fsp_name ));
+ ret = False;
+ }
- /*
- * Deal with a reply when a break-to-none was sent.
- */
+ if (fsp->sent_oplock_break == EXCLUSIVE_BREAK_SENT) {
+ /*
+ * Deal with a reply when a break-to-none was sent.
+ */
- if(remove_share_oplock(fsp)==False) {
- DEBUG(0,("remove_oplock: failed to remove share oplock for file %s fnum %d, \
+ if(remove_share_oplock(fsp)==False) {
+ DEBUG(0,("remove_oplock: failed to remove share oplock for file %s fnum %d, \
dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)inode));
- ret = False;
- }
-
- release_file_oplock(fsp);
-
- } else {
-
- /*
- * Deal with a reply when a break-to-level II was sent.
- */
+ ret = False;
+ }
- if(downgrade_share_oplock(fsp)==False) {
- DEBUG(0,("remove_oplock: failed to downgrade share oplock for file %s fnum %d, \
+ release_file_oplock(fsp);
+ } else {
+ /*
+ * Deal with a reply when a break-to-level II was sent.
+ */
+ if(downgrade_share_oplock(fsp)==False) {
+ DEBUG(0,("remove_oplock: failed to downgrade share oplock for file %s fnum %d, \
dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)inode));
- ret = False;
- }
-
- downgrade_file_oplock(fsp);
- }
+ ret = False;
+ }
+
+ downgrade_file_oplock(fsp);
+ }
- unlock_share_entry_fsp(fsp);
- return ret;
+ unlock_share_entry_fsp(fsp);
+ return ret;
}
/****************************************************************************
@@ -514,26 +251,25 @@ dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)
int setup_oplock_select_set( fd_set *fds)
{
- int maxfd = oplock_sock;
+ int maxfd = oplock_sock;
- if(oplock_sock == -1)
- return 0;
+ if(oplock_sock == -1)
+ return 0;
- FD_SET(oplock_sock,fds);
+ FD_SET(oplock_sock,fds);
- if(lp_kernel_oplocks() && (oplock_pipe_read != -1)) {
- FD_SET(oplock_pipe_read,fds);
- maxfd = MAX(maxfd,oplock_pipe_read);
- }
+ if (koplocks && koplocks->notification_fd != -1) {
+ FD_SET(koplocks->notification_fd, fds);
+ maxfd = MAX(maxfd, koplocks->notification_fd);
+ }
- return maxfd;
+ return maxfd;
}
/****************************************************************************
Process an oplock break message - whether it came from the UDP socket
or from the kernel.
****************************************************************************/
-
BOOL process_local_message(char *buffer, int buf_size)
{
int32 msg_len;
@@ -562,26 +298,15 @@ BOOL process_local_message(char *buffer, int buf_size)
switch(break_cmd_type)
{
-#if defined(HAVE_KERNEL_OPLOCKS_IRIX)
case KERNEL_OPLOCK_BREAK_CMD:
- /* Ensure that the msg length is correct. */
- if(msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN)
- {
- DEBUG(0,("process_local_message: incorrect length for KERNEL_OPLOCK_BREAK_CMD (was %d, \
-should be %d).\n", msg_len, 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));
-
- ptval = NULL;
-
- DEBUG(5,("process_local_message: kernel oplock break request for \
-file dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode));
- }
- break;
-#endif /* HAVE_KERNEL_OPLOCKS_IRIX */
+ if (!koplocks) {
+ DEBUG(0,("unexpected kernel oplock break!\n"));
+ break;
+ }
+ if (!koplocks->parse_message(msg_start, msg_len, &inode, &dev)) {
+ DEBUG(0,("kernel oplock break parse failure!\n"));
+ }
+ break;
case OPLOCK_BREAK_CMD:
case LEVEL_II_OPLOCK_BREAK_CMD:
@@ -708,18 +433,18 @@ pid %d, port %d, for file dev = %x, inode = %.0f\n",
static void prepare_break_message(char *outbuf, files_struct *fsp, BOOL level2)
{
- memset(outbuf,'\0',smb_size);
- set_message(outbuf,8,0,True);
-
- SCVAL(outbuf,smb_com,SMBlockingX);
- SSVAL(outbuf,smb_tid,fsp->conn->cnum);
- SSVAL(outbuf,smb_pid,0xFFFF);
- SSVAL(outbuf,smb_uid,0);
- SSVAL(outbuf,smb_mid,0xFFFF);
- SCVAL(outbuf,smb_vwv0,0xFF);
- SSVAL(outbuf,smb_vwv2,fsp->fnum);
- SCVAL(outbuf,smb_vwv3,LOCKING_ANDX_OPLOCK_RELEASE);
- SCVAL(outbuf,smb_vwv3+1,level2 ? OPLOCKLEVEL_II : OPLOCKLEVEL_NONE);
+ memset(outbuf,'\0',smb_size);
+ set_message(outbuf,8,0,True);
+
+ SCVAL(outbuf,smb_com,SMBlockingX);
+ SSVAL(outbuf,smb_tid,fsp->conn->cnum);
+ SSVAL(outbuf,smb_pid,0xFFFF);
+ SSVAL(outbuf,smb_uid,0);
+ SSVAL(outbuf,smb_mid,0xFFFF);
+ SCVAL(outbuf,smb_vwv0,0xFF);
+ SSVAL(outbuf,smb_vwv2,fsp->fnum);
+ SCVAL(outbuf,smb_vwv3,LOCKING_ANDX_OPLOCK_RELEASE);
+ SCVAL(outbuf,smb_vwv3+1,level2 ? OPLOCKLEVEL_II : OPLOCKLEVEL_NONE);
}
/****************************************************************************
@@ -749,7 +474,6 @@ static void wait_before_sending_break(BOOL local_request)
/****************************************************************************
Ensure that we have a valid oplock.
****************************************************************************/
-
static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
{
files_struct *fsp = NULL;
@@ -966,7 +690,10 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, B
/* Prepare the SMBlockingX message. */
- if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) && !lp_kernel_oplocks() && lp_level2_oplocks(SNUM(fsp->conn))) {
+ if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) &&
+ !koplocks && /* NOTE: we force levelII off for kernel oplocks -
+ this will change when it is supported */
+ lp_level2_oplocks(SNUM(fsp->conn))) {
using_levelII = True;
} else {
using_levelII = False;
@@ -1244,8 +971,10 @@ should be %d\n", (int)pid, share_entry->op_port, global_oplock_port));
FD_ZERO(&fds);
FD_SET(oplock_sock,&fds);
- if(lp_kernel_oplocks() && (oplock_pipe_read != -1))
- FD_SET(oplock_pipe_read,&fds);
+
+ if (koplocks && koplocks->notification_fd != -1) {
+ FD_SET(koplocks->notification_fd, &fds);
+ }
if(receive_local_message(&fds, op_break_reply, sizeof(op_break_reply),
time_left ? time_left * 1000 : 1) == False)
@@ -1292,7 +1021,7 @@ should be %d\n", (int)pid, share_entry->op_port, global_oplock_port));
reply_msg_start = &op_break_reply[OPBRK_CMD_HEADER_LEN];
-#if defined(HAVE_KERNEL_OPLOCKS_IRIX)
+#if HAVE_KERNEL_OPLOCKS_IRIX
if((reply_msg_len != OPLOCK_BREAK_MSG_LEN) && (reply_msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN))
#else
if(reply_msg_len != OPLOCK_BREAK_MSG_LEN)
@@ -1354,7 +1083,6 @@ should be %d\n", (int)pid, share_entry->op_port, global_oplock_port));
Used as a last ditch attempt to free a space in the
file table when we have run out.
****************************************************************************/
-
BOOL attempt_close_oplocked_file(files_struct *fsp)
{
@@ -1371,30 +1099,47 @@ BOOL attempt_close_oplocked_file(files_struct *fsp)
return False;
}
+
/****************************************************************************
- Init function to check if kernel level oplocks are available.
+setup oplocks for this process
****************************************************************************/
-
-void check_kernel_oplocks(void)
+BOOL init_oplocks(void)
{
- static BOOL done;
-
- /*
- * We only do this check once on startup.
- */
- if(done) return;
-
- done = True;
- lp_set_kernel_oplocks(False);
-
-#if defined(HAVE_KERNEL_OPLOCKS_IRIX)
- if (irix_oplocks_available()) {
- lp_set_kernel_oplocks(True);
-
- DEBUG(0,("check_kernel_oplocks: Kernel oplocks available and set to %s.\n",
- lp_kernel_oplocks() ? "True" : "False" ));
+ struct sockaddr_in sock_name;
+ int len = sizeof(sock_name);
+
+ DEBUG(3,("open_oplock_ipc: opening loopback UDP socket.\n"));
+
+ /* Open a lookback UDP socket on a random port. */
+ oplock_sock = open_socket_in(SOCK_DGRAM, 0, 0, htonl(INADDR_LOOPBACK),False);
+ if (oplock_sock == -1) {
+ DEBUG(0,("open_oplock_ipc: Failed to get local UDP socket for \
+address %lx. Error was %s\n", (long)htonl(INADDR_LOOPBACK), strerror(errno)));
+ global_oplock_port = 0;
+ return(False);
+ }
+
+ /* Find out the transient UDP port we have been allocated. */
+ if(getsockname(oplock_sock, (struct sockaddr *)&sock_name, &len)<0) {
+ DEBUG(0,("open_oplock_ipc: Failed to get local UDP port. Error was %s\n",
+ strerror(errno)));
+ close(oplock_sock);
+ oplock_sock = -1;
+ global_oplock_port = 0;
+ return False;
}
-#endif /* HAVE_KERNEL_OPLOCKS_IRIX */
+ global_oplock_port = ntohs(sock_name.sin_port);
+
+ if (lp_kernel_oplocks()) {
+#if HAVE_KERNEL_OPLOCKS_IRIX
+ koplocks = irix_init_kernel_oplocks();
+#endif
+ }
+
+ DEBUG(3,("open_oplock ipc: pid = %d, global_oplock_port = %u\n",
+ (int)sys_getpid(), global_oplock_port));
+
+ return True;
}
#undef OLD_NTDOMAIN
diff --git a/source3/smbd/oplock_irix.c b/source3/smbd/oplock_irix.c
new file mode 100644
index 0000000000..0820c4048d
--- /dev/null
+++ b/source3/smbd/oplock_irix.c
@@ -0,0 +1,282 @@
+#define OLD_NTDOMAIN 1
+#if HAVE_KERNEL_OPLOCKS_IRIX
+
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ oplock processing
+ Copyright (C) Andrew Tridgell 1992-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+
+static int oplock_pipe_write = -1;
+static int oplock_pipe_read = -1;
+
+/****************************************************************************
+test to see if IRIX kernel oplocks work
+****************************************************************************/
+static BOOL irix_oplocks_available(void)
+{
+ int fd;
+ int pfd[2];
+ pstring tmpname;
+
+ oplock_set_capability(True, False);
+
+ slprintf(tmpname,sizeof(tmpname)-1, "%s/koplock.%d", lp_lockdir(), (int)sys_getpid());
+
+ if(pipe(pfd) != 0) {
+ DEBUG(0,("check_kernel_oplocks: Unable to create pipe. Error was %s\n",
+ strerror(errno) ));
+ return False;
+ }
+
+ if((fd = sys_open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600)) < 0) {
+ DEBUG(0,("check_kernel_oplocks: Unable to open temp test file %s. Error was %s\n",
+ tmpname, strerror(errno) ));
+ unlink( tmpname );
+ close(pfd[0]);
+ close(pfd[1]);
+ return False;
+ }
+
+ unlink(tmpname);
+
+ if(fcntl(fd, F_OPLKREG, pfd[1]) == -1) {
+ DEBUG(0,("check_kernel_oplocks: Kernel oplocks are not available on this machine. \
+Disabling kernel oplock support.\n" ));
+ close(pfd[0]);
+ close(pfd[1]);
+ close(fd);
+ return False;
+ }
+
+ if(fcntl(fd, F_OPLKACK, OP_REVOKE) < 0 ) {
+ DEBUG(0,("check_kernel_oplocks: Error when removing kernel oplock. Error was %s. \
+Disabling kernel oplock support.\n", strerror(errno) ));
+ close(pfd[0]);
+ close(pfd[1]);
+ close(fd);
+ return False;
+ }
+
+ close(pfd[0]);
+ close(pfd[1]);
+ close(fd);
+
+ return True;
+}
+
+
+
+/****************************************************************************
+ * Deal with the IRIX kernel <--> smbd
+ * oplock break protocol.
+****************************************************************************/
+static BOOL irix_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len)
+{
+ oplock_stat_t os;
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+ char dummy;
+
+ /*
+ * Read one byte of zero to clear the
+ * kernel break notify message.
+ */
+
+ if(read(oplock_pipe_read, &dummy, 1) != 1) {
+ DEBUG(0,("receive_local_message: read of kernel notification failed. \
+Error was %s.\n", strerror(errno) ));
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+
+ /*
+ * Do a query to get the
+ * device and inode of the file that has the break
+ * request outstanding.
+ */
+
+ if(fcntl(oplock_pipe_read, F_OPLKSTAT, &os) < 0) {
+ DEBUG(0,("receive_local_message: fcntl of kernel notification failed. \
+Error was %s.\n", strerror(errno) ));
+ if(errno == EAGAIN) {
+ /*
+ * Duplicate kernel break message - ignore.
+ */
+ memset(buffer, '\0', KERNEL_OPLOCK_BREAK_MSG_LEN);
+ return True;
+ }
+ smb_read_error = READ_ERROR;
+ return False;
+ }
+
+ dev = (SMB_DEV_T)os.os_dev;
+ inode = (SMB_INO_T)os.os_ino;
+
+ DEBUG(5,("receive_local_message: kernel oplock break request received for \
+dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ));
+
+ /*
+ * Create a kernel oplock break message.
+ */
+
+ /* Setup the message header */
+ SIVAL(buffer,OPBRK_CMD_LEN_OFFSET,KERNEL_OPLOCK_BREAK_MSG_LEN);
+ SSVAL(buffer,OPBRK_CMD_PORT_OFFSET,0);
+
+ buffer += OPBRK_CMD_HEADER_LEN;
+
+ 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));
+
+ return True;
+}
+
+
+/****************************************************************************
+ Attempt to set an kernel oplock on a file.
+****************************************************************************/
+static BOOL irix_set_kernel_oplock(files_struct *fsp, int oplock_type)
+{
+ if (fcntl(fsp->fd, F_OPLKREG, oplock_pipe_write) == -1) {
+ if(errno != EAGAIN) {
+ DEBUG(0,("set_file_oplock: Unable to get kernel oplock on file %s, dev = %x, \
+inode = %.0f. Error was %s\n",
+ fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode,
+ strerror(errno) ));
+ } else {
+ DEBUG(5,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
+inode = %.0f. Another process had the file open.\n",
+ fsp->fsp_name, fsp->fd, (unsigned int)fsp->dev, (double)fsp->inode ));
+ }
+ return False;
+ }
+
+ DEBUG(10,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f\n",
+ fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode));
+
+ return True;
+}
+
+
+/****************************************************************************
+ Release a kernel oplock on a file.
+****************************************************************************/
+static void irix_release_kernel_oplock(files_struct *fsp)
+{
+ if (DEBUGLVL(10)) {
+ /*
+ * Check and print out the current kernel
+ * oplock state of this file.
+ */
+ int state = fcntl(fsp->fd, F_OPLKACK, -1);
+ dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f has kernel \
+oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
+ (double)fsp->inode, state );
+ }
+
+ /*
+ * Remove the kernel oplock on this file.
+ */
+ if(fcntl(fsp->fd, F_OPLKACK, OP_REVOKE) < 0) {
+ if( DEBUGLVL( 0 )) {
+ dbgtext("release_kernel_oplock: Error when removing kernel oplock on file " );
+ dbgtext("%s, dev = %x, inode = %.0f. Error was %s\n",
+ fsp->fsp_name, (unsigned int)fsp->dev,
+ (double)fsp->inode, strerror(errno) );
+ }
+ }
+}
+
+
+/****************************************************************************
+parse a kernel oplock message
+****************************************************************************/
+static BOOL irix_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *inode, SMB_DEV_T *dev)
+{
+ /* Ensure that the msg length is correct. */
+ if(msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN) {
+ DEBUG(0,("process_local_message: incorrect length for KERNEL_OPLOCK_BREAK_CMD (was %d, \
+should be %d).\n", msg_len, 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));
+
+ DEBUG(5,("process_local_message: kernel oplock break request for \
+file dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode));
+
+ return True;
+}
+
+
+/****************************************************************************
+set *maxfd to include oplock read pipe
+****************************************************************************/
+static BOOL irix_oplock_msg_waiting(fd_set *fds)
+{
+ if (oplock_pipe_read == -1) return False;
+
+ return FD_ISSET(oplock_pipe_read,fds);
+}
+
+
+/****************************************************************************
+setup kernel oplocks
+****************************************************************************/
+struct kernel_oplocks *irix_init_kernel_oplocks(void)
+{
+ int pfd[2];
+ static struct kernel_oplocks koplocks;
+
+ if (!irix_oplocks_available()) return NULL;
+
+ if(pipe(pfd) != 0) {
+ DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. Error was %s\n",
+ strerror(errno) ));
+ return False;
+ }
+
+ oplock_pipe_read = pfd[0];
+ oplock_pipe_write = pfd[1];
+
+ koplocks.receive_message = irix_oplock_receive_message;
+ koplocks.set_oplock = irix_set_kernel_oplock;
+ koplocks.release_oplock = irix_release_kernel_oplock;
+ koplocks.parse_message = irix_kernel_oplock_parse;
+ koplocks.msg_waiting = irix_oplock_msg_waiting;
+ koplocks.notification_fd = oplock_pipe_read;
+
+ return &koplocks;
+}
+
+
+
+#else
+ void oplock_irix_dummy(void) {}
+#endif /* HAVE_KERNEL_OPLOCKS_IRIX */
+
+#undef OLD_NTDOMAIN
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 72c0cb105d..ecf1deb05a 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -259,12 +259,6 @@ max can be %d\n",
done correctly in the process. */
reset_globals_after_fork();
- /*
- * Ensure this child has kernel oplock
- * capabilities, but not it's children.
- */
- oplock_set_capability(True, False);
-
return True;
}
/* The parent doesn't need this socket */
@@ -723,8 +717,6 @@ static void usage(char *pname)
mkdir(lp_lockdir(), 0755);
}
- check_kernel_oplocks();
-
if (is_daemon) {
pidfile_create("smbd");
}
@@ -733,20 +725,20 @@ static void usage(char *pname)
exit(1);
/*
- * Note that this call should be done after the fork() call
- * in open_sockets(), as some versions of the locking shared
- * memory code register openers in a flat file.
+ * everything after this point is run after the fork()
*/
- if (!locking_init(0))
+ if (!locking_init(0)) {
exit(1);
+ }
if (!print_backend_init()) {
exit(1);
}
- if(!initialize_password_db())
+ if(!initialize_password_db()) {
exit(1);
+ }
/* possibly reload the services file. */
reload_services(True);
@@ -761,9 +753,10 @@ static void usage(char *pname)
DEBUG(2,("Changed root to %s\n", lp_rootdir()));
}
- /* Setup the oplock IPC socket. */
- if( !open_oplock_ipc() )
+ /* Setup oplocks */
+ if (!init_oplocks()) {
exit(1);
+ }
smbd_process();