From 52cb05678a9b08b5aa7dbe13ae6b54ff9ee4ecac Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 10 Jun 2000 13:38:07 +0000 Subject: 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) --- source3/include/proto.h | 13 +- source3/include/smb.h | 14 +- source3/lib/system.c | 2 + source3/param/loadparm.c | 32 +-- source3/smbd/oplock.c | 499 +++++++++++---------------------------------- source3/smbd/oplock_irix.c | 282 +++++++++++++++++++++++++ source3/smbd/server.c | 23 +-- 7 files changed, 436 insertions(+), 429 deletions(-) create mode 100644 source3/smbd/oplock_irix.c 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) @@ -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. 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 @@ -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; - - /* 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(); -- cgit