Try to fix the build on irix.
[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                 set_smb_read_error(get_srv_read_error(), SMB_READ_ERROR);
125                 return NULL;
126         }
127
128         /*
129          * Do a query to get the
130          * device and inode of the file that has the break
131          * request outstanding.
132          */
133
134         if(sys_fcntl_ptr(oplock_pipe_read, F_OPLKSTAT, &os) < 0) {
135                 DEBUG(0,("irix_oplock_receive_message: fcntl of kernel "
136                          "notification failed. Error was %s.\n",
137                          strerror(errno) ));
138                 if(errno == EAGAIN) {
139                         /*
140                          * Duplicate kernel break message - ignore.
141                          */
142                         return NULL;
143                 }
144                 set_smb_read_error(get_srv_read_error(), SMB_READ_ERROR);
145                 return NULL;
146         }
147
148         /*
149          * We only have device and inode info here - we have to guess that this
150          * is the first fsp open with this dev,ino pair.
151          *
152          * NOTE: this doesn't work if any VFS modules overloads
153          *       the file_id_create() hook!
154          */
155
156         fileid = file_id_create_dev((SMB_DEV_T)os.os_dev,
157                                     (SMB_INO_T)os.os_ino);
158         if ((fsp = file_find_di_first(fileid)) == NULL) {
159                 DEBUG(0,("irix_oplock_receive_message: unable to find open "
160                          "file with dev = %x, inode = %.0f\n",
161                          (unsigned int)os.os_dev, (double)os.os_ino ));
162                 return NULL;
163         }
164      
165         DEBUG(5,("irix_oplock_receive_message: kernel oplock break request "
166                  "received for file_id %s gen_id = %ul",
167                  file_id_string_tos(&fsp->file_id),
168                  fsp->fh->gen_id ));
169
170         return fsp;
171 }
172
173 /****************************************************************************
174  Attempt to set an kernel oplock on a file.
175 ****************************************************************************/
176
177 static bool irix_set_kernel_oplock(files_struct *fsp, int oplock_type)
178 {
179         if (sys_fcntl_long(fsp->fh->fd, F_OPLKREG, oplock_pipe_write) == -1) {
180                 if(errno != EAGAIN) {
181                         DEBUG(0,("irix_set_kernel_oplock: Unable to get "
182                                  "kernel oplock on file %s, file_id %s "
183                                  "gen_id = %ul. Error was %s\n", 
184                                  fsp->fsp_name, file_id_string_tos(&fsp->file_id), 
185                                  fsp->fh->gen_id,
186                                  strerror(errno) ));
187                 } else {
188                         DEBUG(5,("irix_set_kernel_oplock: Refused oplock on "
189                                  "file %s, fd = %d, file_id = 5s, "
190                                  "gen_id = %ul. Another process had the file "
191                                  "open.\n",
192                                  fsp->fsp_name, fsp->fh->fd,
193                                  file_id_string_tos(&fsp->file_id),
194                                  fsp->fh->gen_id ));
195                 }
196                 return False;
197         }
198         
199         DEBUG(10,("irix_set_kernel_oplock: got kernel oplock on file %s, file_id = %s "
200                   "gen_id = %ul\n",
201                   fsp->fsp_name, file_id_string_tos(&fsp->file_id),
202                   fsp->fh->gen_id));
203
204         return True;
205 }
206
207 /****************************************************************************
208  Release a kernel oplock on a file.
209 ****************************************************************************/
210
211 static void irix_release_kernel_oplock(files_struct *fsp)
212 {
213         if (DEBUGLVL(10)) {
214                 /*
215                  * Check and print out the current kernel
216                  * oplock state of this file.
217                  */
218                 int state = sys_fcntl_long(fsp->fh->fd, F_OPLKACK, -1);
219                 dbgtext("irix_release_kernel_oplock: file %s, file_id = %s"
220                         "gen_id = %ul, has kernel oplock state "
221                         "of %x.\n", fsp->fsp_name, file_id_string_tos(&fsp->file_id),
222                         fsp->fh->gen_id, state );
223         }
224
225         /*
226          * Remove the kernel oplock on this file.
227          */
228         if(sys_fcntl_long(fsp->fh->fd, F_OPLKACK, OP_REVOKE) < 0) {
229                 if( DEBUGLVL( 0 )) {
230                         dbgtext("irix_release_kernel_oplock: Error when "
231                                 "removing kernel oplock on file " );
232                         dbgtext("%s, file_id = %s gen_id = %ul. "
233                                 "Error was %s\n",
234                                 fsp->fsp_name, file_id_string_tos(&fsp->file_id),
235                                 fsp->fh->gen_id,
236                                 strerror(errno) );
237                 }
238         }
239 }
240
241 /****************************************************************************
242  See if there is a message waiting in this fd set.
243  Note that fds MAY BE NULL ! If so we must do our own select.
244 ****************************************************************************/
245
246 static bool irix_oplock_msg_waiting(fd_set *fds)
247 {
248         int selrtn;
249         fd_set myfds;
250         struct timeval to;
251
252         if (oplock_pipe_read == -1)
253                 return False;
254
255         if (fds) {
256                 return FD_ISSET(oplock_pipe_read, fds);
257         }
258
259         /* Do a zero-time select. We just need to find out if there
260          * are any outstanding messages. We use sys_select_intr as
261          * we need to ignore any signals. */
262
263         FD_ZERO(&myfds);
264         FD_SET(oplock_pipe_read, &myfds);
265
266         to = timeval_set(0, 0);
267         selrtn = sys_select_intr(oplock_pipe_read+1,&myfds,NULL,NULL,&to);
268         return (selrtn == 1) ? True : False;
269 }
270
271 /****************************************************************************
272  Setup kernel oplocks.
273 ****************************************************************************/
274
275 struct kernel_oplocks *irix_init_kernel_oplocks(void) 
276 {
277         int pfd[2];
278         static struct kernel_oplocks koplocks;
279
280         if (!irix_oplocks_available())
281                 return NULL;
282
283         if(pipe(pfd) != 0) {
284                 DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. "
285                          "Error was %s\n", strerror(errno) ));
286                 return False;
287         }
288
289         oplock_pipe_read = pfd[0];
290         oplock_pipe_write = pfd[1];
291
292         koplocks.receive_message = irix_oplock_receive_message;
293         koplocks.set_oplock = irix_set_kernel_oplock;
294         koplocks.release_oplock = irix_release_kernel_oplock;
295         koplocks.msg_waiting = irix_oplock_msg_waiting;
296         koplocks.notification_fd = oplock_pipe_read;
297
298         return &koplocks;
299 }
300 #else
301  void oplock_irix_dummy(void);
302  void oplock_irix_dummy(void) {}
303 #endif /* HAVE_KERNEL_OPLOCKS_IRIX */