s4:drsuapi: make sure we never return the same highwatermark twice in a replication...
[Samba/id10ts.git] / source3 / smbd / oplock_irix.c
blobaa987fccbb84f0651a05902434feef49ae0a3756
1 /*
2 Unix SMB/CIFS implementation.
3 IRIX kernel oplock processing
4 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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/>.
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"
26 #if HAVE_KERNEL_OPLOCKS_IRIX
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 fd_event *read_fde;
34 bool pending;
37 /****************************************************************************
38 Test to see if IRIX kernel oplocks work.
39 ****************************************************************************/
41 static bool irix_oplocks_available(void)
43 int fd;
44 int pfd[2];
45 TALLOC_CTX *ctx = talloc_stackframe();
46 char *tmpname = NULL;
48 set_effective_capability(KERNEL_OPLOCK_CAPABILITY);
50 tmpname = talloc_asprintf(ctx,
51 "%s/koplock.%d",
52 lp_lockdir(),
53 (int)getpid());
54 if (!tmpname) {
55 TALLOC_FREE(ctx);
56 return False;
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;
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;
78 unlink(tmpname);
80 TALLOC_FREE(ctx);
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;
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;
102 close(pfd[0]);
103 close(pfd[1]);
104 close(fd);
106 return True;
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.
113 static struct file_id file_id_create_dev(SMB_DEV_T dev, SMB_INO_T inode)
115 struct file_id key;
117 /* the ZERO_STRUCT ensures padding doesn't break using the key as a
118 * blob */
119 ZERO_STRUCT(key);
121 key.devid = dev;
122 key.inode = inode;
124 return key;
127 /****************************************************************************
128 * Deal with the IRIX kernel <--> smbd
129 * oplock break protocol.
130 ****************************************************************************/
132 static files_struct *irix_oplock_receive_message(struct kernel_oplocks *_ctx)
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;
142 * TODO: is it correct to assume we only get one
143 * oplock break, for each byte we read from the pipe?
145 ctx->pending = false;
148 * Read one byte of zero to clear the
149 * kernel break notify message.
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;
160 * Do a query to get the
161 * device and inode of the file that has the break
162 * request outstanding.
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) {
171 * Duplicate kernel break message - ignore.
173 return NULL;
175 return NULL;
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.
182 * NOTE: this doesn't work if any VFS modules overloads
183 * the file_id_create() hook!
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;
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 ));
200 return fsp;
203 /****************************************************************************
204 Attempt to set an kernel oplock on a file.
205 ****************************************************************************/
207 static bool irix_set_kernel_oplock(struct kernel_oplocks *_ctx,
208 files_struct *fsp, int oplock_type)
210 struct irix_oplocks_context *ctx = talloc_get_type(_ctx->private_data,
211 struct irix_oplocks_context);
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 ));
231 return False;
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));
239 return True;
242 /****************************************************************************
243 Release a kernel oplock on a file.
244 ****************************************************************************/
246 static void irix_release_kernel_oplock(struct kernel_oplocks *_ctx,
247 files_struct *fsp, int oplock_type)
249 if (DEBUGLVL(10)) {
251 * Check and print out the current kernel
252 * oplock state of this file.
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 );
263 * Remove the kernel oplock on this file.
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) );
279 static void irix_oplocks_read_fde_handler(struct event_context *ev,
280 struct fd_event *fde,
281 uint16_t flags,
282 void *private_data)
284 struct irix_oplocks_context *ctx = talloc_get_type(private_data,
285 struct irix_oplocks_context);
286 files_struct *fsp;
288 fsp = irix_oplock_receive_message(ctx->ctx);
289 break_kernel_oplock(ctx->sconn->msg_ctx, fsp);
292 /****************************************************************************
293 Setup kernel oplocks.
294 ****************************************************************************/
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,
303 struct kernel_oplocks *irix_init_kernel_oplocks(struct smbd_server_connection *sconn)
305 struct kernel_oplocks *_ctx;
306 struct irix_oplocks_context *ctx;
307 int pfd[2];
309 if (!irix_oplocks_available())
310 return NULL;
312 _ctx = talloc_zero(sconn, struct kernel_oplocks);
313 if (!_ctx) {
314 return NULL;
317 ctx = talloc_zero(_ctx, struct irix_oplocks_context);
318 if (!ctx) {
319 talloc_free(_ctx);
320 return NULL;
322 _ctx->ops = &irix_koplocks;
323 _ctx->private_data = ctx;
324 ctx->ctx = _ctx;
325 ctx->sconn = sconn;
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;
334 ctx->read_fd = pfd[0];
335 ctx->write_fd = pfd[1];
337 ctx->read_fde = event_add_fd(sconn->ev_ctx,
338 ctx,
339 ctx->read_fd,
340 EVENT_FD_READ,
341 irix_oplocks_read_fde_handler,
342 ctx);
343 return _ctx;
345 #else
346 void oplock_irix_dummy(void);
347 void oplock_irix_dummy(void) {}
348 #endif /* HAVE_KERNEL_OPLOCKS_IRIX */