s3:smbd: FSCTL_PIPE_TRANSCEIVE on a none IPC$ share should give NOT_SUPPORTED
[ira/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->fsp_name, file_id_string_tos(&fsp->file_id), 
216                                  fsp->fh->gen_id,
217                                  strerror(errno) ));
218                 } else {
219                         DEBUG(5,("irix_set_kernel_oplock: Refused oplock on "
220                                  "file %s, fd = %d, file_id = %s, "
221                                  "gen_id = %ul. Another process had the file "
222                                  "open.\n",
223                                  fsp->fsp_name, fsp->fh->fd,
224                                  file_id_string_tos(&fsp->file_id),
225                                  fsp->fh->gen_id ));
226                 }
227                 return False;
228         }
229         
230         DEBUG(10,("irix_set_kernel_oplock: got kernel oplock on file %s, file_id = %s "
231                   "gen_id = %ul\n",
232                   fsp->fsp_name, file_id_string_tos(&fsp->file_id),
233                   fsp->fh->gen_id));
234
235         return True;
236 }
237
238 /****************************************************************************
239  Release a kernel oplock on a file.
240 ****************************************************************************/
241
242 static void irix_release_kernel_oplock(struct kernel_oplocks *_ctx,
243                                        files_struct *fsp, int oplock_type)
244 {
245         if (DEBUGLVL(10)) {
246                 /*
247                  * Check and print out the current kernel
248                  * oplock state of this file.
249                  */
250                 int state = sys_fcntl_long(fsp->fh->fd, F_OPLKACK, -1);
251                 dbgtext("irix_release_kernel_oplock: file %s, file_id = %s"
252                         "gen_id = %ul, has kernel oplock state "
253                         "of %x.\n", fsp->fsp_name, file_id_string_tos(&fsp->file_id),
254                         fsp->fh->gen_id, state );
255         }
256
257         /*
258          * Remove the kernel oplock on this file.
259          */
260         if(sys_fcntl_long(fsp->fh->fd, F_OPLKACK, OP_REVOKE) < 0) {
261                 if( DEBUGLVL( 0 )) {
262                         dbgtext("irix_release_kernel_oplock: Error when "
263                                 "removing kernel oplock on file " );
264                         dbgtext("%s, file_id = %s gen_id = %ul. "
265                                 "Error was %s\n",
266                                 fsp->fsp_name, file_id_string_tos(&fsp->file_id),
267                                 fsp->fh->gen_id,
268                                 strerror(errno) );
269                 }
270         }
271 }
272
273 static void irix_oplocks_read_fde_handler(struct event_context *ev,
274                                           struct fd_event *fde,
275                                           uint16_t flags,
276                                           void *private_data)
277 {
278         struct irix_oplocks_context *ctx = talloc_get_type(private_data,
279                                            struct irix_oplocks_context);
280         files_struct *fsp;
281
282         fsp = irix_oplock_receive_message(ctx->ctx);
283         break_kernel_oplock(smbd_messaging_context(), fsp);
284 }
285
286 /****************************************************************************
287  Setup kernel oplocks.
288 ****************************************************************************/
289
290 static const struct kernel_oplocks_ops irix_koplocks = {
291         .set_oplock                     = irix_set_kernel_oplock,
292         .release_oplock                 = irix_release_kernel_oplock,
293         .contend_level2_oplocks_begin   = NULL,
294         .contend_level2_oplocks_end     = NULL,
295 };
296
297 struct kernel_oplocks *irix_init_kernel_oplocks(TALLOC_CTX *mem_ctx)
298 {
299         struct kernel_oplocks *_ctx;
300         struct irix_oplocks_context *ctx;
301         int pfd[2];
302
303         if (!irix_oplocks_available())
304                 return NULL;
305
306         _ctx = talloc_zero(mem_ctx, struct kernel_oplocks);
307         if (!_ctx) {
308                 return NULL;
309         }
310
311         ctx = talloc_zero(_ctx, struct irix_oplocks_context);
312         if (!ctx) {
313                 talloc_free(_ctx);
314                 return NULL;
315         }
316         _ctx->ops = &irix_koplocks;
317         _ctx->private_data = ctx;
318         ctx->ctx = _ctx;
319
320         if(pipe(pfd) != 0) {
321                 talloc_free(_ctx);
322                 DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. "
323                          "Error was %s\n", strerror(errno) ));
324                 return False;
325         }
326
327         ctx->read_fd = pfd[0];
328         ctx->write_fd = pfd[1];
329
330         ctx->read_fde = event_add_fd(smbd_event_context(),
331                                      ctx,
332                                      ctx->read_fd,
333                                      EVENT_FD_READ,
334                                      irix_oplocks_read_fde_handler,
335                                      ctx);
336         return _ctx;
337 }
338 #else
339  void oplock_irix_dummy(void);
340  void oplock_irix_dummy(void) {}
341 #endif /* HAVE_KERNEL_OPLOCKS_IRIX */