1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-27 22:50:26 +03:00

continued the split of the kernel level oplocks code into a more

modular form. In this pass I added oplock_irix.c and added a "struct
kernel_oplocks" that describes a kernel oplock implementation.
(This used to be commit b5ceab810292602ea9a81696c20a781c16b706c2)
This commit is contained in:
Andrew Tridgell 2000-06-10 13:38:07 +00:00
parent a9a512192d
commit 52cb05678a
7 changed files with 432 additions and 425 deletions

View File

@ -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 */

View File

@ -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"

View File

@ -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

View File

@ -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)
@ -3438,37 +3439,6 @@ void lp_set_name_resolve_order(char *new_order)
Globals.szNameResolveOrder = 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.

View File

@ -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
@ -336,43 +141,13 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou
return True;
}
/****************************************************************************
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;
@ -389,47 +164,13 @@ BOOL set_file_oplock(files_struct *fsp, int oplock_type)
return True;
}
/****************************************************************************
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;
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;
}
/* 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) {
if (fsp->sent_oplock_break == EXCLUSIVE_BREAK_SENT) {
/*
* Deal with a reply when a break-to-none was 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;
}
ret = False;
}
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, \
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;
}
ret = False;
}
downgrade_file_oplock(fsp);
}
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);
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);
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;
struct sockaddr_in sock_name;
int len = sizeof(sock_name);
/*
* We only do this check once on startup.
*/
if(done) return;
done = True;
lp_set_kernel_oplocks(False);
DEBUG(3,("open_oplock_ipc: opening loopback UDP socket.\n"));
#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" ));
/* 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);
}
#endif /* HAVE_KERNEL_OPLOCKS_IRIX */
/* 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 (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

282
source3/smbd/oplock_irix.c Normal file
View File

@ -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

View File

@ -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();