ctdbd_conn: Pass "ev" through ctdb connection callbacks
[vlendec/samba-autobuild/.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 #include "system/filesys.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25
26 #if HAVE_KERNEL_OPLOCKS_IRIX
27
28 struct irix_oplocks_context {
29         struct kernel_oplocks *ctx;
30         struct smbd_server_connection *sconn;
31         int write_fd;
32         int read_fd;
33         struct tevent_fd *read_fde;
34         bool pending;
35 };
36
37 /****************************************************************************
38  Test to see if IRIX kernel oplocks work.
39 ****************************************************************************/
40
41 static bool irix_oplocks_available(void)
42 {
43         int fd;
44         int pfd[2];
45         TALLOC_CTX *ctx = talloc_stackframe();
46         char *tmpname = NULL;
47
48         set_effective_capability(KERNEL_OPLOCK_CAPABILITY);
49
50         tmpname = talloc_asprintf(ctx,
51                                 "%s/koplock.%d",
52                                 lp_lock_directory(),
53                                 (int)getpid());
54         if (!tmpname) {
55                 TALLOC_FREE(ctx);
56                 return False;
57         }
58
59         if(pipe(pfd) != 0) {
60                 DEBUG(0,("check_kernel_oplocks: Unable to create pipe. Error "
61                          "was %s\n",
62                          strerror(errno) ));
63                 TALLOC_FREE(ctx);
64                 return False;
65         }
66
67         if((fd = open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600)) < 0) {
68                 DEBUG(0,("check_kernel_oplocks: Unable to open temp test file "
69                          "%s. Error was %s\n",
70                          tmpname, strerror(errno) ));
71                 unlink( tmpname );
72                 close(pfd[0]);
73                 close(pfd[1]);
74                 TALLOC_FREE(ctx);
75                 return False;
76         }
77
78         unlink(tmpname);
79
80         TALLOC_FREE(ctx);
81
82         if(sys_fcntl_long(fd, F_OPLKREG, pfd[1]) == -1) {
83                 DEBUG(0,("check_kernel_oplocks: Kernel oplocks are not "
84                          "available on this machine. Disabling kernel oplock "
85                          "support.\n" ));
86                 close(pfd[0]);
87                 close(pfd[1]);
88                 close(fd);
89                 return False;
90         }
91
92         if(sys_fcntl_long(fd, F_OPLKACK, OP_REVOKE) < 0 ) {
93                 DEBUG(0,("check_kernel_oplocks: Error when removing kernel "
94                          "oplock. Error was %s. Disabling kernel oplock "
95                          "support.\n", strerror(errno) ));
96                 close(pfd[0]);
97                 close(pfd[1]);
98                 close(fd);
99                 return False;
100         }
101
102         close(pfd[0]);
103         close(pfd[1]);
104         close(fd);
105
106         return True;
107 }
108
109 /*
110  * This is bad because the file_id should always be created through the vfs
111  * layer!  Unfortunately, a conn struct isn't available here.
112  */
113 static struct file_id file_id_create_dev(SMB_DEV_T dev, SMB_INO_T inode)
114 {
115         struct file_id key;
116
117         /* the ZERO_STRUCT ensures padding doesn't break using the key as a
118          * blob */
119         ZERO_STRUCT(key);
120
121         key.devid = dev;
122         key.inode = inode;
123
124         return key;
125 }
126
127 /****************************************************************************
128  * Deal with the IRIX kernel <--> smbd
129  * oplock break protocol.
130 ****************************************************************************/
131
132 static files_struct *irix_oplock_receive_message(struct kernel_oplocks *_ctx)
133 {
134         struct irix_oplocks_context *ctx = talloc_get_type(_ctx->private_data,
135                                            struct irix_oplocks_context);
136         oplock_stat_t os;
137         char dummy;
138         struct file_id fileid;
139         files_struct *fsp;
140
141         /*
142          * TODO: is it correct to assume we only get one
143          * oplock break, for each byte we read from the pipe?
144          */
145         ctx->pending = false;
146
147         /*
148          * Read one byte of zero to clear the
149          * kernel break notify message.
150          */
151
152         if(read(ctx->read_fd, &dummy, 1) != 1) {
153                 DEBUG(0,("irix_oplock_receive_message: read of kernel "
154                          "notification failed. Error was %s.\n",
155                          strerror(errno) ));
156                 return NULL;
157         }
158
159         /*
160          * Do a query to get the
161          * device and inode of the file that has the break
162          * request outstanding.
163          */
164
165         if(sys_fcntl_ptr(ctx->read_fd, F_OPLKSTAT, &os) < 0) {
166                 DEBUG(0,("irix_oplock_receive_message: fcntl of kernel "
167                          "notification failed. Error was %s.\n",
168                          strerror(errno) ));
169                 if(errno == EAGAIN) {
170                         /*
171                          * Duplicate kernel break message - ignore.
172                          */
173                         return NULL;
174                 }
175                 return NULL;
176         }
177
178         /*
179          * We only have device and inode info here - we have to guess that this
180          * is the first fsp open with this dev,ino pair.
181          *
182          * NOTE: this doesn't work if any VFS modules overloads
183          *       the file_id_create() hook!
184          */
185
186         fileid = file_id_create_dev((SMB_DEV_T)os.os_dev,
187                                     (SMB_INO_T)os.os_ino);
188         if ((fsp = file_find_di_first(ctx->sconn, fileid)) == NULL) {
189                 DEBUG(0,("irix_oplock_receive_message: unable to find open "
190                          "file with dev = %x, inode = %.0f\n",
191                          (unsigned int)os.os_dev, (double)os.os_ino ));
192                 return NULL;
193         }
194      
195         DEBUG(5,("irix_oplock_receive_message: kernel oplock break request "
196                  "received for file_id %s gen_id = %ul",
197                  file_id_string_tos(&fsp->file_id),
198                  fsp->fh->gen_id ));
199
200         return fsp;
201 }
202
203 /****************************************************************************
204  Attempt to set an kernel oplock on a file.
205 ****************************************************************************/
206
207 static bool irix_set_kernel_oplock(struct kernel_oplocks *_ctx,
208                                    files_struct *fsp, int oplock_type)
209 {
210         struct irix_oplocks_context *ctx = talloc_get_type(_ctx->private_data,
211                                            struct irix_oplocks_context);
212
213         if (sys_fcntl_long(fsp->fh->fd, F_OPLKREG, ctx->write_fd) == -1) {
214                 if(errno != EAGAIN) {
215                         DEBUG(0,("irix_set_kernel_oplock: Unable to get "
216                                  "kernel oplock on file %s, file_id %s "
217                                  "gen_id = %ul. Error was %s\n", 
218                                  fsp_str_dbg(fsp),
219                                  file_id_string_tos(&fsp->file_id),
220                                  fsp->fh->gen_id,
221                                  strerror(errno) ));
222                 } else {
223                         DEBUG(5,("irix_set_kernel_oplock: Refused oplock on "
224                                  "file %s, fd = %d, file_id = %s, "
225                                  "gen_id = %ul. Another process had the file "
226                                  "open.\n",
227                                  fsp_str_dbg(fsp), fsp->fh->fd,
228                                  file_id_string_tos(&fsp->file_id),
229                                  fsp->fh->gen_id ));
230                 }
231                 return False;
232         }
233         
234         DEBUG(10,("irix_set_kernel_oplock: got kernel oplock on file %s, file_id = %s "
235                   "gen_id = %ul\n",
236                   fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id),
237                   fsp->fh->gen_id));
238
239         return True;
240 }
241
242 /****************************************************************************
243  Release a kernel oplock on a file.
244 ****************************************************************************/
245
246 static void irix_release_kernel_oplock(struct kernel_oplocks *_ctx,
247                                        files_struct *fsp, int oplock_type)
248 {
249         if (DEBUGLVL(10)) {
250                 /*
251                  * Check and print out the current kernel
252                  * oplock state of this file.
253                  */
254                 int state = sys_fcntl_long(fsp->fh->fd, F_OPLKACK, -1);
255                 dbgtext("irix_release_kernel_oplock: file %s, file_id = %s"
256                         "gen_id = %ul, has kernel oplock state "
257                         "of %x.\n", fsp_str_dbg(fsp),
258                         file_id_string_tos(&fsp->file_id),
259                         fsp->fh->gen_id, state );
260         }
261
262         /*
263          * Remove the kernel oplock on this file.
264          */
265         if(sys_fcntl_long(fsp->fh->fd, F_OPLKACK, OP_REVOKE) < 0) {
266                 if( DEBUGLVL( 0 )) {
267                         dbgtext("irix_release_kernel_oplock: Error when "
268                                 "removing kernel oplock on file " );
269                         dbgtext("%s, file_id = %s gen_id = %ul. "
270                                 "Error was %s\n",
271                                 fsp_str_dbg(fsp),
272                                 file_id_string_tos(&fsp->file_id),
273                                 fsp->fh->gen_id,
274                                 strerror(errno) );
275                 }
276         }
277 }
278
279 static void irix_oplocks_read_fde_handler(struct tevent_context *ev,
280                                           struct tevent_fd *fde,
281                                           uint16_t flags,
282                                           void *private_data)
283 {
284         struct irix_oplocks_context *ctx = talloc_get_type(private_data,
285                                            struct irix_oplocks_context);
286         files_struct *fsp;
287
288         fsp = irix_oplock_receive_message(ctx->ctx);
289         break_kernel_oplock(ctx->sconn->msg_ctx, fsp);
290 }
291
292 /****************************************************************************
293  Setup kernel oplocks.
294 ****************************************************************************/
295
296 static const struct kernel_oplocks_ops irix_koplocks = {
297         .set_oplock                     = irix_set_kernel_oplock,
298         .release_oplock                 = irix_release_kernel_oplock,
299         .contend_level2_oplocks_begin   = NULL,
300         .contend_level2_oplocks_end     = NULL,
301 };
302
303 struct kernel_oplocks *irix_init_kernel_oplocks(struct smbd_server_connection *sconn)
304 {
305         struct kernel_oplocks *_ctx;
306         struct irix_oplocks_context *ctx;
307         int pfd[2];
308
309         if (!irix_oplocks_available())
310                 return NULL;
311
312         _ctx = talloc_zero(sconn, struct kernel_oplocks);
313         if (!_ctx) {
314                 return NULL;
315         }
316
317         ctx = talloc_zero(_ctx, struct irix_oplocks_context);
318         if (!ctx) {
319                 talloc_free(_ctx);
320                 return NULL;
321         }
322         _ctx->ops = &irix_koplocks;
323         _ctx->private_data = ctx;
324         ctx->ctx = _ctx;
325         ctx->sconn = sconn;
326
327         if(pipe(pfd) != 0) {
328                 talloc_free(_ctx);
329                 DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. "
330                          "Error was %s\n", strerror(errno) ));
331                 return False;
332         }
333
334         ctx->read_fd = pfd[0];
335         ctx->write_fd = pfd[1];
336
337         ctx->read_fde = tevent_add_fd(sconn->ev_ctx,
338                                      ctx,
339                                      ctx->read_fd,
340                                      TEVENT_FD_READ,
341                                      irix_oplocks_read_fde_handler,
342                                      ctx);
343         return _ctx;
344 }
345 #else
346  void oplock_irix_dummy(void);
347  void oplock_irix_dummy(void) {}
348 #endif /* HAVE_KERNEL_OPLOCKS_IRIX */