• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source3/smbd/
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
26struct 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
38static 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 */
110static 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
129static 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
204static 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
243static 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
276static 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
293static 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
300struct 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 */
345