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