1/* 2 Unix SMB/CIFS implementation. 3 IRIX kernel oplock processing 4 Copyright (C) Andrew Tridgell 1992-1998 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21#include "includes.h" 22 23#if HAVE_KERNEL_OPLOCKS_IRIX 24 25static int oplock_pipe_write = -1; 26static int oplock_pipe_read = -1; 27 28/**************************************************************************** 29 Test to see if IRIX kernel oplocks work. 30****************************************************************************/ 31 32static BOOL irix_oplocks_available(void) 33{ 34 int fd; 35 int pfd[2]; 36 pstring tmpname; 37 38 oplock_set_capability(True, False); 39 40 slprintf(tmpname,sizeof(tmpname)-1, "%s/koplock.%d", lp_lockdir(), (int)sys_getpid()); 41 42 if(pipe(pfd) != 0) { 43 DEBUG(0,("check_kernel_oplocks: Unable to create pipe. Error was %s\n", 44 strerror(errno) )); 45 return False; 46 } 47 48 if((fd = sys_open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600)) < 0) { 49 DEBUG(0,("check_kernel_oplocks: Unable to open temp test file %s. Error was %s\n", 50 tmpname, strerror(errno) )); 51 unlink( tmpname ); 52 close(pfd[0]); 53 close(pfd[1]); 54 return False; 55 } 56 57 unlink(tmpname); 58 59 if(sys_fcntl_long(fd, F_OPLKREG, pfd[1]) == -1) { 60 DEBUG(0,("check_kernel_oplocks: Kernel oplocks are not available on this machine. \ 61Disabling kernel oplock support.\n" )); 62 close(pfd[0]); 63 close(pfd[1]); 64 close(fd); 65 return False; 66 } 67 68 if(sys_fcntl_long(fd, F_OPLKACK, OP_REVOKE) < 0 ) { 69 DEBUG(0,("check_kernel_oplocks: Error when removing kernel oplock. Error was %s. \ 70Disabling kernel oplock support.\n", strerror(errno) )); 71 close(pfd[0]); 72 close(pfd[1]); 73 close(fd); 74 return False; 75 } 76 77 close(pfd[0]); 78 close(pfd[1]); 79 close(fd); 80 81 return True; 82} 83 84/**************************************************************************** 85 * Deal with the IRIX kernel <--> smbd 86 * oplock break protocol. 87****************************************************************************/ 88 89static BOOL irix_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len) 90{ 91 extern int smb_read_error; 92 oplock_stat_t os; 93 char dummy; 94 files_struct *fsp; 95 96 /* 97 * Read one byte of zero to clear the 98 * kernel break notify message. 99 */ 100 101 if(read(oplock_pipe_read, &dummy, 1) != 1) { 102 DEBUG(0,("irix_oplock_receive_message: read of kernel notification failed. \ 103Error was %s.\n", strerror(errno) )); 104 smb_read_error = READ_ERROR; 105 return False; 106 } 107 108 /* 109 * Do a query to get the 110 * device and inode of the file that has the break 111 * request outstanding. 112 */ 113 114 if(sys_fcntl_ptr(oplock_pipe_read, F_OPLKSTAT, &os) < 0) { 115 DEBUG(0,("irix_oplock_receive_message: fcntl of kernel notification failed. \ 116Error was %s.\n", strerror(errno) )); 117 if(errno == EAGAIN) { 118 /* 119 * Duplicate kernel break message - ignore. 120 */ 121 memset(buffer, '\0', KERNEL_OPLOCK_BREAK_MSG_LEN); 122 return True; 123 } 124 smb_read_error = READ_ERROR; 125 return False; 126 } 127 128 /* 129 * We only have device and inode info here - we have to guess that this 130 * is the first fsp open with this dev,ino pair. 131 */ 132 133 if ((fsp = file_find_di_first((SMB_DEV_T)os.os_dev, (SMB_INO_T)os.os_ino)) == NULL) { 134 DEBUG(0,("irix_oplock_receive_message: unable to find open file with dev = %x, inode = %.0f\n", 135 (unsigned int)os.os_dev, (double)os.os_ino )); 136 return False; 137 } 138 139 DEBUG(5,("irix_oplock_receive_message: kernel oplock break request received for \ 140dev = %x, inode = %.0f\n, file_id = %ul", (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id )); 141 142 /* 143 * Create a kernel oplock break message. 144 */ 145 146 /* Setup the message header */ 147 SIVAL(buffer,OPBRK_CMD_LEN_OFFSET,KERNEL_OPLOCK_BREAK_MSG_LEN); 148 SSVAL(buffer,OPBRK_CMD_PORT_OFFSET,0); 149 150 buffer += OPBRK_CMD_HEADER_LEN; 151 152 SSVAL(buffer,OPBRK_MESSAGE_CMD_OFFSET,KERNEL_OPLOCK_BREAK_CMD); 153 154 memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&fsp->dev, sizeof(fsp->dev)); 155 memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&fsp->inode, sizeof(fsp->inode)); 156 memcpy(buffer + KERNEL_OPLOCK_BREAK_FILEID_OFFSET, (char *)&fsp->file_id, sizeof(fsp->file_id)); 157 158 return True; 159} 160 161/**************************************************************************** 162 Attempt to set an kernel oplock on a file. 163****************************************************************************/ 164 165static BOOL irix_set_kernel_oplock(files_struct *fsp, int oplock_type) 166{ 167 if (sys_fcntl_long(fsp->fd, F_OPLKREG, oplock_pipe_write) == -1) { 168 if(errno != EAGAIN) { 169 DEBUG(0,("irix_set_kernel_oplock: Unable to get kernel oplock on file %s, dev = %x, \ 170inode = %.0f, file_id = %ul. Error was %s\n", 171 fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id, 172 strerror(errno) )); 173 } else { 174 DEBUG(5,("irix_set_kernel_oplock: Refused oplock on file %s, fd = %d, dev = %x, \ 175inode = %.0f, file_id = %ul. Another process had the file open.\n", 176 fsp->fsp_name, fsp->fd, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id )); 177 } 178 return False; 179 } 180 181 DEBUG(10,("irix_set_kernel_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f, file_id = %ul\n", 182 fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, fsp->file_id)); 183 184 return True; 185} 186 187/**************************************************************************** 188 Release a kernel oplock on a file. 189****************************************************************************/ 190 191static void irix_release_kernel_oplock(files_struct *fsp) 192{ 193 if (DEBUGLVL(10)) { 194 /* 195 * Check and print out the current kernel 196 * oplock state of this file. 197 */ 198 int state = sys_fcntl_long(fsp->fd, F_OPLKACK, -1); 199 dbgtext("irix_release_kernel_oplock: file %s, dev = %x, inode = %.0f file_id = %ul, has kernel \ 200oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev, 201 (double)fsp->inode, fsp->file_id, state ); 202 } 203 204 /* 205 * Remove the kernel oplock on this file. 206 */ 207 if(sys_fcntl_long(fsp->fd, F_OPLKACK, OP_REVOKE) < 0) { 208 if( DEBUGLVL( 0 )) { 209 dbgtext("irix_release_kernel_oplock: Error when removing kernel oplock on file " ); 210 dbgtext("%s, dev = %x, inode = %.0f, file_id = %ul. Error was %s\n", 211 fsp->fsp_name, (unsigned int)fsp->dev, 212 (double)fsp->inode, fsp->file_id, strerror(errno) ); 213 } 214 } 215} 216 217/**************************************************************************** 218 Parse a kernel oplock message. 219****************************************************************************/ 220 221static BOOL irix_kernel_oplock_parse(char *msg_start, int msg_len, 222 SMB_INO_T *inode, SMB_DEV_T *dev, unsigned long *file_id) 223{ 224 /* Ensure that the msg length is correct. */ 225 if(msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN) { 226 DEBUG(0,("incorrect length for KERNEL_OPLOCK_BREAK_CMD (was %d, should be %d).\n", 227 msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN)); 228 return False; 229 } 230 231 memcpy((char *)inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(*inode)); 232 memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev)); 233 memcpy((char *)file_id, msg_start+KERNEL_OPLOCK_BREAK_FILEID_OFFSET, sizeof(*file_id)); 234 235 DEBUG(5,("kernel oplock break request for file dev = %x, inode = %.0f, file_id = %ul\n", 236 (unsigned int)*dev, (double)*inode, *file_id)); 237 238 return True; 239} 240 241/**************************************************************************** 242 Set *maxfd to include oplock read pipe. 243****************************************************************************/ 244 245static BOOL irix_oplock_msg_waiting(fd_set *fds) 246{ 247 if (oplock_pipe_read == -1) 248 return False; 249 250 return FD_ISSET(oplock_pipe_read,fds); 251} 252 253/**************************************************************************** 254 Setup kernel oplocks. 255****************************************************************************/ 256 257struct kernel_oplocks *irix_init_kernel_oplocks(void) 258{ 259 int pfd[2]; 260 static struct kernel_oplocks koplocks; 261 262 if (!irix_oplocks_available()) 263 return NULL; 264 265 if(pipe(pfd) != 0) { 266 DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. Error was %s\n", 267 strerror(errno) )); 268 return False; 269 } 270 271 oplock_pipe_read = pfd[0]; 272 oplock_pipe_write = pfd[1]; 273 274 koplocks.receive_message = irix_oplock_receive_message; 275 koplocks.set_oplock = irix_set_kernel_oplock; 276 koplocks.release_oplock = irix_release_kernel_oplock; 277 koplocks.parse_message = irix_kernel_oplock_parse; 278 koplocks.msg_waiting = irix_oplock_msg_waiting; 279 koplocks.notification_fd = oplock_pipe_read; 280 281 return &koplocks; 282} 283#else 284 void oplock_irix_dummy(void) {} 285#endif /* HAVE_KERNEL_OPLOCKS_IRIX */ 286