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