Merge of new 2.2 code into HEAD (Gerald I hate you :-) :-). Allows new SAMR
[samba.git] / source3 / 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 extern int DEBUGLEVEL;
26
27 static int oplock_pipe_write = -1;
28 static int oplock_pipe_read = -1;
29
30 /****************************************************************************
31 test to see if IRIX kernel oplocks work
32 ****************************************************************************/
33 static BOOL irix_oplocks_available(void)
34 {
35         int fd;
36         int pfd[2];
37         pstring tmpname;
38
39         oplock_set_capability(True, False);
40
41         slprintf(tmpname,sizeof(tmpname)-1, "%s/koplock.%d", lp_lockdir(), (int)sys_getpid());
42
43         if(pipe(pfd) != 0) {
44                 DEBUG(0,("check_kernel_oplocks: Unable to create pipe. Error was %s\n",
45                          strerror(errno) ));
46                 return False;
47         }
48
49         if((fd = sys_open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600)) < 0) {
50                 DEBUG(0,("check_kernel_oplocks: Unable to open temp test file %s. Error was %s\n",
51                          tmpname, strerror(errno) ));
52                 unlink( tmpname );
53                 close(pfd[0]);
54                 close(pfd[1]);
55                 return False;
56         }
57
58         unlink(tmpname);
59
60         if(fcntl(fd, F_OPLKREG, pfd[1]) == -1) {
61                 DEBUG(0,("check_kernel_oplocks: Kernel oplocks are not available on this machine. \
62 Disabling kernel oplock support.\n" ));
63                 close(pfd[0]);
64                 close(pfd[1]);
65                 close(fd);
66                 return False;
67         }
68
69         if(fcntl(fd, F_OPLKACK, OP_REVOKE) < 0 ) {
70                 DEBUG(0,("check_kernel_oplocks: Error when removing kernel oplock. Error was %s. \
71 Disabling kernel oplock support.\n", strerror(errno) ));
72                 close(pfd[0]);
73                 close(pfd[1]);
74                 close(fd);
75                 return False;
76         }
77
78         close(pfd[0]);
79         close(pfd[1]);
80         close(fd);
81
82         return True;
83 }
84
85
86
87 /****************************************************************************
88  * Deal with the IRIX kernel <--> smbd
89  * oplock break protocol.
90 ****************************************************************************/
91 static BOOL irix_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len)
92 {
93         extern int smb_read_error;
94      oplock_stat_t os;
95      SMB_DEV_T dev;
96      SMB_INO_T inode;
97      char dummy;
98
99      /*
100       * Read one byte of zero to clear the
101       * kernel break notify message.
102       */
103
104      if(read(oplock_pipe_read, &dummy, 1) != 1) {
105              DEBUG(0,("receive_local_message: read of kernel notification failed. \
106 Error was %s.\n", strerror(errno) ));
107              smb_read_error = READ_ERROR;
108              return False;
109      }
110
111      /*
112       * Do a query to get the
113       * device and inode of the file that has the break
114       * request outstanding.
115       */
116
117      if(fcntl(oplock_pipe_read, F_OPLKSTAT, &os) < 0) {
118              DEBUG(0,("receive_local_message: fcntl of kernel notification failed. \
119 Error was %s.\n", strerror(errno) ));
120              if(errno == EAGAIN) {
121                      /*
122                       * Duplicate kernel break message - ignore.
123                       */
124                      memset(buffer, '\0', KERNEL_OPLOCK_BREAK_MSG_LEN);
125                      return True;
126              }
127              smb_read_error = READ_ERROR;
128              return False;
129      }
130
131      dev = (SMB_DEV_T)os.os_dev;
132      inode = (SMB_INO_T)os.os_ino;
133      
134      DEBUG(5,("receive_local_message: kernel oplock break request received for \
135 dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ));
136      
137      /*
138       * Create a kernel oplock break message.
139       */
140      
141      /* Setup the message header */
142      SIVAL(buffer,OPBRK_CMD_LEN_OFFSET,KERNEL_OPLOCK_BREAK_MSG_LEN);
143      SSVAL(buffer,OPBRK_CMD_PORT_OFFSET,0);
144      
145      buffer += OPBRK_CMD_HEADER_LEN;
146      
147      SSVAL(buffer,OPBRK_MESSAGE_CMD_OFFSET,KERNEL_OPLOCK_BREAK_CMD);
148      
149      memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&dev, sizeof(dev));
150      memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&inode, sizeof(inode));  
151      
152      return True;
153 }
154
155
156 /****************************************************************************
157  Attempt to set an kernel oplock on a file.
158 ****************************************************************************/
159 static BOOL irix_set_kernel_oplock(files_struct *fsp, int oplock_type)
160 {
161         if (fcntl(fsp->fd, F_OPLKREG, oplock_pipe_write) == -1) {
162                 if(errno != EAGAIN) {
163                         DEBUG(0,("set_file_oplock: Unable to get kernel oplock on file %s, dev = %x, \
164 inode = %.0f. Error was %s\n", 
165                                  fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode,
166                                  strerror(errno) ));
167                 } else {
168                         DEBUG(5,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
169 inode = %.0f. Another process had the file open.\n",
170                                  fsp->fsp_name, fsp->fd, (unsigned int)fsp->dev, (double)fsp->inode ));
171                 }
172                 return False;
173         }
174         
175         DEBUG(10,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f\n",
176                   fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode));
177
178         return True;
179 }
180
181
182 /****************************************************************************
183  Release a kernel oplock on a file.
184 ****************************************************************************/
185 static void irix_release_kernel_oplock(files_struct *fsp)
186 {
187         if (DEBUGLVL(10)) {
188                 /*
189                  * Check and print out the current kernel
190                  * oplock state of this file.
191                  */
192                 int state = fcntl(fsp->fd, F_OPLKACK, -1);
193                 dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f has kernel \
194 oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
195                         (double)fsp->inode, state );
196         }
197
198         /*
199          * Remove the kernel oplock on this file.
200          */
201         if(fcntl(fsp->fd, F_OPLKACK, OP_REVOKE) < 0) {
202                 if( DEBUGLVL( 0 )) {
203                         dbgtext("release_kernel_oplock: Error when removing kernel oplock on file " );
204                         dbgtext("%s, dev = %x, inode = %.0f. Error was %s\n",
205                                 fsp->fsp_name, (unsigned int)fsp->dev, 
206                                 (double)fsp->inode, strerror(errno) );
207                 }
208         }
209 }
210
211
212 /****************************************************************************
213 parse a kernel oplock message
214 ****************************************************************************/
215 static BOOL irix_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *inode, SMB_DEV_T *dev)
216 {
217         /* Ensure that the msg length is correct. */
218         if(msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN) {
219                 DEBUG(0,("incorrect length for KERNEL_OPLOCK_BREAK_CMD (was %d, should be %d).\n", 
220                          msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN));
221                 return False;
222         }
223
224         memcpy((char *)inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(*inode));
225         memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev));
226
227         DEBUG(5,("kernel oplock break request for file dev = %x, inode = %.0f\n", 
228                  (unsigned int)*dev, (double)*inode));
229
230         return True;
231 }
232
233
234 /****************************************************************************
235 set *maxfd to include oplock read pipe
236 ****************************************************************************/
237 static BOOL irix_oplock_msg_waiting(fd_set *fds)
238 {
239         if (oplock_pipe_read == -1) return False;
240
241         return FD_ISSET(oplock_pipe_read,fds);
242 }
243
244
245 /****************************************************************************
246 setup kernel oplocks
247 ****************************************************************************/
248 struct kernel_oplocks *irix_init_kernel_oplocks(void) 
249 {
250         int pfd[2];
251         static struct kernel_oplocks koplocks;
252
253         if (!irix_oplocks_available()) return NULL;
254
255         if(pipe(pfd) != 0) {
256                 DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. Error was %s\n",
257                          strerror(errno) ));
258                 return False;
259         }
260
261         oplock_pipe_read = pfd[0];
262         oplock_pipe_write = pfd[1];
263
264         koplocks.receive_message = irix_oplock_receive_message;
265         koplocks.set_oplock = irix_set_kernel_oplock;
266         koplocks.release_oplock = irix_release_kernel_oplock;
267         koplocks.parse_message = irix_kernel_oplock_parse;
268         koplocks.msg_waiting = irix_oplock_msg_waiting;
269         koplocks.notification_fd = oplock_pipe_read;
270
271         return &koplocks;
272 }
273
274
275
276 #else
277  void oplock_irix_dummy(void) {}
278 #endif /* HAVE_KERNEL_OPLOCKS_IRIX */