bbc9132a08f8e628888de920f49ce8f9a13fad13
[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 #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  * Deal with the IRIX kernel <--> smbd
108  * oplock break protocol.
109 ****************************************************************************/
110
111 static files_struct *irix_oplock_receive_message(struct kernel_oplocks *_ctx)
112 {
113         struct irix_oplocks_context *ctx = talloc_get_type(_ctx->private_data,
114                                            struct irix_oplocks_context);
115         oplock_stat_t os;
116         char dummy;
117         struct file_id fileid;
118         files_struct *fsp;
119
120         /*
121          * TODO: is it correct to assume we only get one
122          * oplock break, for each byte we read from the pipe?
123          */
124         ctx->pending = false;
125
126         /*
127          * Read one byte of zero to clear the
128          * kernel break notify message.
129          */
130
131         if(read(ctx->read_fd, &dummy, 1) != 1) {
132                 DEBUG(0,("irix_oplock_receive_message: read of kernel "
133                          "notification failed. Error was %s.\n",
134                          strerror(errno) ));
135                 return NULL;
136         }
137
138         /*
139          * Do a query to get the
140          * device and inode of the file that has the break
141          * request outstanding.
142          */
143
144         if(sys_fcntl_ptr(ctx->read_fd, F_OPLKSTAT, &os) < 0) {
145                 DEBUG(0,("irix_oplock_receive_message: fcntl of kernel "
146                          "notification failed. Error was %s.\n",
147                          strerror(errno) ));
148                 if(errno == EAGAIN) {
149                         /*
150                          * Duplicate kernel break message - ignore.
151                          */
152                         return NULL;
153                 }
154                 return NULL;
155         }
156
157         /*
158          * We only have device and inode info here - we have to guess that this
159          * is the first fsp open with this dev,ino pair.
160          *
161          * NOTE: this doesn't work if any VFS modules overloads
162          *       the file_id_create() hook!
163          */
164
165         fileid = file_id_create_dev((SMB_DEV_T)os.os_dev,
166                                     (SMB_INO_T)os.os_ino);
167         if ((fsp = file_find_di_first(fileid)) == NULL) {
168                 DEBUG(0,("irix_oplock_receive_message: unable to find open "
169                          "file with dev = %x, inode = %.0f\n",
170                          (unsigned int)os.os_dev, (double)os.os_ino ));
171                 return NULL;
172         }
173      
174         DEBUG(5,("irix_oplock_receive_message: kernel oplock break request "
175                  "received for file_id %s gen_id = %ul",
176                  file_id_string_tos(&fsp->file_id),
177                  fsp->fh->gen_id ));
178
179         return fsp;
180 }
181
182 /****************************************************************************
183  Attempt to set an kernel oplock on a file.
184 ****************************************************************************/
185
186 static bool irix_set_kernel_oplock(struct kernel_oplocks *_ctx,
187                                    files_struct *fsp, int oplock_type)
188 {
189         struct irix_oplocks_context *ctx = talloc_get_type(_ctx->private_data,
190                                            struct irix_oplocks_context);
191
192         if (sys_fcntl_long(fsp->fh->fd, F_OPLKREG, ctx->write_fd) == -1) {
193                 if(errno != EAGAIN) {
194                         DEBUG(0,("irix_set_kernel_oplock: Unable to get "
195                                  "kernel oplock on file %s, file_id %s "
196                                  "gen_id = %ul. Error was %s\n", 
197                                  fsp->fsp_name, file_id_string_tos(&fsp->file_id), 
198                                  fsp->fh->gen_id,
199                                  strerror(errno) ));
200                 } else {
201                         DEBUG(5,("irix_set_kernel_oplock: Refused oplock on "
202                                  "file %s, fd = %d, file_id = %s, "
203                                  "gen_id = %ul. Another process had the file "
204                                  "open.\n",
205                                  fsp->fsp_name, fsp->fh->fd,
206                                  file_id_string_tos(&fsp->file_id),
207                                  fsp->fh->gen_id ));
208                 }
209                 return False;
210         }
211         
212         DEBUG(10,("irix_set_kernel_oplock: got kernel oplock on file %s, file_id = %s "
213                   "gen_id = %ul\n",
214                   fsp->fsp_name, file_id_string_tos(&fsp->file_id),
215                   fsp->fh->gen_id));
216
217         return True;
218 }
219
220 /****************************************************************************
221  Release a kernel oplock on a file.
222 ****************************************************************************/
223
224 static void irix_release_kernel_oplock(struct kernel_oplocks *_ctx,
225                                        files_struct *fsp, int oplock_type)
226 {
227         if (DEBUGLVL(10)) {
228                 /*
229                  * Check and print out the current kernel
230                  * oplock state of this file.
231                  */
232                 int state = sys_fcntl_long(fsp->fh->fd, F_OPLKACK, -1);
233                 dbgtext("irix_release_kernel_oplock: file %s, file_id = %s"
234                         "gen_id = %ul, has kernel oplock state "
235                         "of %x.\n", fsp->fsp_name, file_id_string_tos(&fsp->file_id),
236                         fsp->fh->gen_id, state );
237         }
238
239         /*
240          * Remove the kernel oplock on this file.
241          */
242         if(sys_fcntl_long(fsp->fh->fd, F_OPLKACK, OP_REVOKE) < 0) {
243                 if( DEBUGLVL( 0 )) {
244                         dbgtext("irix_release_kernel_oplock: Error when "
245                                 "removing kernel oplock on file " );
246                         dbgtext("%s, file_id = %s gen_id = %ul. "
247                                 "Error was %s\n",
248                                 fsp->fsp_name, file_id_string_tos(&fsp->file_id),
249                                 fsp->fh->gen_id,
250                                 strerror(errno) );
251                 }
252         }
253 }
254
255 static void irix_oplocks_read_fde_handler(struct event_context *ev,
256                                           struct fd_event *fde,
257                                           uint16_t flags,
258                                           void *private_data)
259 {
260         struct irix_oplocks_context *ctx = talloc_get_type(private_data,
261                                            struct irix_oplocks_context);
262         files_struct *fsp;
263
264         fsp = irix_oplock_receive_message(ctx->ctx);
265         break_kernel_oplock(smbd_messaging_context(), fsp);
266 }
267
268 /****************************************************************************
269  Setup kernel oplocks.
270 ****************************************************************************/
271
272 static const struct kernel_oplocks_ops irix_koplocks = {
273         .set_oplock                     = irix_set_kernel_oplock,
274         .release_oplock                 = irix_release_kernel_oplock,
275         .contend_level2_oplocks_begin   = NULL,
276         .contend_level2_oplocks_end     = NULL,
277 };
278
279 struct kernel_oplocks *irix_init_kernel_oplocks(TALLOC_CTX *mem_ctx)
280 {
281         struct kernel_oplocks *_ctx;
282         struct irix_oplocks_context *ctx;
283         int pfd[2];
284
285         if (!irix_oplocks_available())
286                 return NULL;
287
288         _ctx = talloc_zero(mem_ctx, struct kernel_oplocks);
289         if (!_ctx) {
290                 return NULL;
291         }
292
293         ctx = talloc_zero(_ctx, struct irix_oplocks_context);
294         if (!ctx) {
295                 talloc_free(_ctx);
296                 return NULL;
297         }
298         _ctx->ops = &irix_koplocks;
299         _ctx->private_data = ctx;
300         ctx->ctx = _ctx;
301
302         if(pipe(pfd) != 0) {
303                 talloc_free(_ctx);
304                 DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. "
305                          "Error was %s\n", strerror(errno) ));
306                 return False;
307         }
308
309         ctx->read_fd = pfd[0];
310         ctx->write_fd = pfd[1];
311
312         ctx->read_fde = event_add_fd(smbd_event_context(),
313                                      ctx,
314                                      ctx->read_fd,
315                                      EVENT_FD_READ,
316                                      irix_oplocks_read_fde_handler,
317                                      ctx);
318         return _ctx;
319 }
320 #else
321  void oplock_irix_dummy(void);
322  void oplock_irix_dummy(void) {}
323 #endif /* HAVE_KERNEL_OPLOCKS_IRIX */