Remove a direct inbuf reference (should have been removed with 8987641d...)
[jra/samba/.git] / source3 / smbd / oplock_irix.c
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 3 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, see <http://www.gnu.org/licenses/>.
18 */
19
20 #define DBGC_CLASS DBGC_LOCKING
21 #include "includes.h"
22
23 #if HAVE_KERNEL_OPLOCKS_IRIX
24
25 static int oplock_pipe_write = -1;
26 static int oplock_pipe_read = -1;
27
28 /****************************************************************************
29  Test to see if IRIX kernel oplocks work.
30 ****************************************************************************/
31
32 static bool irix_oplocks_available(void)
33 {
34         int fd;
35         int pfd[2];
36         TALLOC_CTX *ctx = talloc_stackframe();
37         char *tmpname = NULL;
38
39         set_effective_capability(KERNEL_OPLOCK_CAPABILITY);
40
41         tmpname = talloc_asprintf(ctx,
42                                 "%s/koplock.%d",
43                                 lp_lockdir(),
44                                 (int)sys_getpid());
45         if (!tmpname) {
46                 TALLOC_FREE(ctx);
47                 return False;
48         }
49
50         if(pipe(pfd) != 0) {
51                 DEBUG(0,("check_kernel_oplocks: Unable to create pipe. Error "
52                          "was %s\n",
53                          strerror(errno) ));
54                 TALLOC_FREE(ctx);
55                 return False;
56         }
57
58         if((fd = sys_open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600)) < 0) {
59                 DEBUG(0,("check_kernel_oplocks: Unable to open temp test file "
60                          "%s. Error was %s\n",
61                          tmpname, strerror(errno) ));
62                 unlink( tmpname );
63                 close(pfd[0]);
64                 close(pfd[1]);
65                 TALLOC_FREE(ctx);
66                 return False;
67         }
68
69         unlink(tmpname);
70
71         TALLOC_FREE(ctx);
72
73         if(sys_fcntl_long(fd, F_OPLKREG, pfd[1]) == -1) {
74                 DEBUG(0,("check_kernel_oplocks: Kernel oplocks are not "
75                          "available on this machine. Disabling kernel oplock "
76                          "support.\n" ));
77                 close(pfd[0]);
78                 close(pfd[1]);
79                 close(fd);
80                 return False;
81         }
82
83         if(sys_fcntl_long(fd, F_OPLKACK, OP_REVOKE) < 0 ) {
84                 DEBUG(0,("check_kernel_oplocks: Error when removing kernel "
85                          "oplock. Error was %s. Disabling kernel oplock "
86                          "support.\n", strerror(errno) ));
87                 close(pfd[0]);
88                 close(pfd[1]);
89                 close(fd);
90                 return False;
91         }
92
93         close(pfd[0]);
94         close(pfd[1]);
95         close(fd);
96
97         return True;
98 }
99
100 /****************************************************************************
101  * Deal with the IRIX kernel <--> smbd
102  * oplock break protocol.
103 ****************************************************************************/
104
105 static files_struct *irix_oplock_receive_message(fd_set *fds)
106 {
107         oplock_stat_t os;
108         char dummy;
109         struct file_id fileid;
110         files_struct *fsp;
111
112         /* Ensure we only get one call per select fd set. */
113         FD_CLR(oplock_pipe_read, fds);
114
115         /*
116          * Read one byte of zero to clear the
117          * kernel break notify message.
118          */
119
120         if(read(oplock_pipe_read, &dummy, 1) != 1) {
121                 DEBUG(0,("irix_oplock_receive_message: read of kernel "
122                          "notification failed. Error was %s.\n",
123                          strerror(errno) ));
124                 return NULL;
125         }
126
127         /*
128          * Do a query to get the
129          * device and inode of the file that has the break
130          * request outstanding.
131          */
132
133         if(sys_fcntl_ptr(oplock_pipe_read, F_OPLKSTAT, &os) < 0) {
134                 DEBUG(0,("irix_oplock_receive_message: fcntl of kernel "
135                          "notification failed. Error was %s.\n",
136                          strerror(errno) ));
137                 if(errno == EAGAIN) {
138                         /*
139                          * Duplicate kernel break message - ignore.
140                          */
141                         return NULL;
142                 }
143                 return NULL;
144         }
145
146         /*
147          * We only have device and inode info here - we have to guess that this
148          * is the first fsp open with this dev,ino pair.
149          *
150          * NOTE: this doesn't work if any VFS modules overloads
151          *       the file_id_create() hook!
152          */
153
154         fileid = file_id_create_dev((SMB_DEV_T)os.os_dev,
155                                     (SMB_INO_T)os.os_ino);
156         if ((fsp = file_find_di_first(fileid)) == NULL) {
157                 DEBUG(0,("irix_oplock_receive_message: unable to find open "
158                          "file with dev = %x, inode = %.0f\n",
159                          (unsigned int)os.os_dev, (double)os.os_ino ));
160                 return NULL;
161         }
162      
163         DEBUG(5,("irix_oplock_receive_message: kernel oplock break request "
164                  "received for file_id %s gen_id = %ul",
165                  file_id_string_tos(&fsp->file_id),
166                  fsp->fh->gen_id ));
167
168         return fsp;
169 }
170
171 /****************************************************************************
172  Attempt to set an kernel oplock on a file.
173 ****************************************************************************/
174
175 static bool irix_set_kernel_oplock(files_struct *fsp, int oplock_type)
176 {
177         if (sys_fcntl_long(fsp->fh->fd, F_OPLKREG, oplock_pipe_write) == -1) {
178                 if(errno != EAGAIN) {
179                         DEBUG(0,("irix_set_kernel_oplock: Unable to get "
180                                  "kernel oplock on file %s, file_id %s "
181                                  "gen_id = %ul. Error was %s\n", 
182                                  fsp->fsp_name, file_id_string_tos(&fsp->file_id), 
183                                  fsp->fh->gen_id,
184                                  strerror(errno) ));
185                 } else {
186                         DEBUG(5,("irix_set_kernel_oplock: Refused oplock on "
187                                  "file %s, fd = %d, file_id = %s, "
188                                  "gen_id = %ul. Another process had the file "
189                                  "open.\n",
190                                  fsp->fsp_name, fsp->fh->fd,
191                                  file_id_string_tos(&fsp->file_id),
192                                  fsp->fh->gen_id ));
193                 }
194                 return False;
195         }
196         
197         DEBUG(10,("irix_set_kernel_oplock: got kernel oplock on file %s, file_id = %s "
198                   "gen_id = %ul\n",
199                   fsp->fsp_name, file_id_string_tos(&fsp->file_id),
200                   fsp->fh->gen_id));
201
202         return True;
203 }
204
205 /****************************************************************************
206  Release a kernel oplock on a file.
207 ****************************************************************************/
208
209 static void irix_release_kernel_oplock(files_struct *fsp)
210 {
211         if (DEBUGLVL(10)) {
212                 /*
213                  * Check and print out the current kernel
214                  * oplock state of this file.
215                  */
216                 int state = sys_fcntl_long(fsp->fh->fd, F_OPLKACK, -1);
217                 dbgtext("irix_release_kernel_oplock: file %s, file_id = %s"
218                         "gen_id = %ul, has kernel oplock state "
219                         "of %x.\n", fsp->fsp_name, file_id_string_tos(&fsp->file_id),
220                         fsp->fh->gen_id, state );
221         }
222
223         /*
224          * Remove the kernel oplock on this file.
225          */
226         if(sys_fcntl_long(fsp->fh->fd, F_OPLKACK, OP_REVOKE) < 0) {
227                 if( DEBUGLVL( 0 )) {
228                         dbgtext("irix_release_kernel_oplock: Error when "
229                                 "removing kernel oplock on file " );
230                         dbgtext("%s, file_id = %s gen_id = %ul. "
231                                 "Error was %s\n",
232                                 fsp->fsp_name, file_id_string_tos(&fsp->file_id),
233                                 fsp->fh->gen_id,
234                                 strerror(errno) );
235                 }
236         }
237 }
238
239 /****************************************************************************
240  See if there is a message waiting in this fd set.
241  Note that fds MAY BE NULL ! If so we must do our own select.
242 ****************************************************************************/
243
244 static bool irix_oplock_msg_waiting(fd_set *fds)
245 {
246         int selrtn;
247         fd_set myfds;
248         struct timeval to;
249
250         if (oplock_pipe_read == -1)
251                 return False;
252
253         if (fds) {
254                 return FD_ISSET(oplock_pipe_read, fds);
255         }
256
257         /* Do a zero-time select. We just need to find out if there
258          * are any outstanding messages. We use sys_select_intr as
259          * we need to ignore any signals. */
260
261         FD_ZERO(&myfds);
262         FD_SET(oplock_pipe_read, &myfds);
263
264         to = timeval_set(0, 0);
265         selrtn = sys_select_intr(oplock_pipe_read+1,&myfds,NULL,NULL,&to);
266         return (selrtn == 1) ? True : False;
267 }
268
269 /****************************************************************************
270  Setup kernel oplocks.
271 ****************************************************************************/
272
273 struct kernel_oplocks *irix_init_kernel_oplocks(void) 
274 {
275         int pfd[2];
276         static struct kernel_oplocks koplocks;
277
278         if (!irix_oplocks_available())
279                 return NULL;
280
281         if(pipe(pfd) != 0) {
282                 DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. "
283                          "Error was %s\n", strerror(errno) ));
284                 return False;
285         }
286
287         oplock_pipe_read = pfd[0];
288         oplock_pipe_write = pfd[1];
289
290         koplocks.receive_message = irix_oplock_receive_message;
291         koplocks.set_oplock = irix_set_kernel_oplock;
292         koplocks.release_oplock = irix_release_kernel_oplock;
293         koplocks.msg_waiting = irix_oplock_msg_waiting;
294         koplocks.notification_fd = oplock_pipe_read;
295
296         return &koplocks;
297 }
298 #else
299  void oplock_irix_dummy(void);
300  void oplock_irix_dummy(void) {}
301 #endif /* HAVE_KERNEL_OPLOCKS_IRIX */