smbd: Remove unused function linux_set_lease_capability
[gd/samba-autobuild/.git] / source3 / smbd / oplock_linux.c
1 /* 
2    Unix SMB/CIFS implementation.
3    kernel oplock processing for Linux
4    Copyright (C) Andrew Tridgell 2000
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 "system/filesys.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25
26 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
27
28 #ifndef F_SETLEASE
29 #define F_SETLEASE      1024
30 #endif
31
32 #ifndef F_GETLEASE
33 #define F_GETLEASE      1025
34 #endif
35
36 #ifndef CAP_LEASE
37 #define CAP_LEASE 28
38 #endif
39
40 #ifndef RT_SIGNAL_LEASE
41 #define RT_SIGNAL_LEASE (SIGRTMIN+1)
42 #endif
43
44 #ifndef F_SETSIG
45 #define F_SETSIG 10
46 #endif
47
48 /* 
49  * Call to set the kernel lease signal handler
50  */
51 int linux_set_lease_sighandler(int fd)
52 {
53         if (fcntl(fd, F_SETSIG, RT_SIGNAL_LEASE) == -1) {
54                 DEBUG(3,("Failed to set signal handler for kernel lease\n"));
55                 return -1;
56         }
57
58         return 0;
59 }
60
61 /****************************************************************************
62  Call SETLEASE. If we get EACCES then we try setting up the right capability and
63  try again.
64  Use the SMB_VFS_LINUX_SETLEASE instead of this call directly.
65 ****************************************************************************/
66
67 int linux_setlease(int fd, int leasetype)
68 {
69         int ret;
70         int saved_errno;
71
72         /*
73          * Ensure the lease owner is root to allow
74          * correct delivery of lease-break signals.
75          */
76
77         become_root();
78
79         /* First set the signal handler. */
80         if (linux_set_lease_sighandler(fd) == -1) {
81                 saved_errno = errno;
82                 ret = -1;
83                 goto out;
84         }
85         ret = fcntl(fd, F_SETLEASE, leasetype);
86         if (ret == -1) {
87                 saved_errno = errno;
88         }
89
90   out:
91
92         unbecome_root();
93
94         if (ret == -1) {
95                 errno = saved_errno;
96         }
97         return ret;
98 }
99
100 /****************************************************************************
101  * Deal with the Linux kernel <--> smbd
102  * oplock break protocol.
103 ****************************************************************************/
104
105 static void linux_oplock_signal_handler(struct tevent_context *ev_ctx,
106                                         struct tevent_signal *se,
107                                         int signum, int count,
108                                         void *_info, void *private_data)
109 {
110         struct kernel_oplocks *ctx =
111                 talloc_get_type_abort(private_data,
112                 struct kernel_oplocks);
113         struct smbd_server_connection *sconn =
114                 talloc_get_type_abort(ctx->private_data,
115                 struct smbd_server_connection);
116         siginfo_t *info = (siginfo_t *)_info;
117         int fd = info->si_fd;
118         files_struct *fsp;
119
120         fsp = file_find_fd(sconn, fd);
121         if (fsp == NULL) {
122                 DEBUG(0,("linux_oplock_signal_handler: failed to find fsp for file fd=%d (file was closed ?)\n", fd ));
123                 return;
124         }
125         break_kernel_oplock(sconn->msg_ctx, fsp);
126 }
127
128 /****************************************************************************
129  Attempt to set an kernel oplock on a file.
130 ****************************************************************************/
131
132 static bool linux_set_kernel_oplock(struct kernel_oplocks *ctx,
133                                     files_struct *fsp, int oplock_type)
134 {
135         struct file_id_buf idbuf;
136
137         if ( SMB_VFS_LINUX_SETLEASE(fsp, F_WRLCK) == -1) {
138                 DBG_NOTICE("Refused oplock on file %s, "
139                            "fd = %d, file_id = %s. (%s)\n",
140                            fsp_str_dbg(fsp),
141                            fsp->fh->fd,
142                            file_id_str_buf(fsp->file_id, &idbuf),
143                            strerror(errno));
144                 return False;
145         }
146         
147         DBG_NOTICE("got kernel oplock on file %s, "
148                    "file_id = %s gen_id = %"PRIu64"\n",
149                    fsp_str_dbg(fsp),
150                    file_id_str_buf(fsp->file_id, &idbuf),
151                    fsp->fh->gen_id);
152
153         return True;
154 }
155
156 /****************************************************************************
157  Release a kernel oplock on a file.
158 ****************************************************************************/
159
160 static void linux_release_kernel_oplock(struct kernel_oplocks *ctx,
161                                         files_struct *fsp, int oplock_type)
162 {
163         struct file_id_buf idbuf;
164
165         if (DEBUGLVL(10)) {
166                 /*
167                  * Check and print out the current kernel
168                  * oplock state of this file.
169                  */
170                 int state = fcntl(fsp->fh->fd, F_GETLEASE, 0);
171                 dbgtext("linux_release_kernel_oplock: file %s, file_id = %s "
172                         "gen_id = %"PRIu64" has kernel oplock state "
173                         "of %x.\n",
174                         fsp_str_dbg(fsp),
175                         file_id_str_buf(fsp->file_id, &idbuf),
176                         fsp->fh->gen_id,
177                         state);
178         }
179
180         /*
181          * Remove the kernel oplock on this file.
182          */
183         if ( SMB_VFS_LINUX_SETLEASE(fsp, F_UNLCK) == -1) {
184                 if (DEBUGLVL(0)) {
185                         dbgtext("linux_release_kernel_oplock: Error when "
186                                 "removing kernel oplock on file " );
187                         dbgtext("%s, file_id = %s, gen_id = %"PRIu64". "
188                                 "Error was %s\n",
189                                 fsp_str_dbg(fsp),
190                                 file_id_str_buf(fsp->file_id, &idbuf),
191                                 fsp->fh->gen_id,
192                                 strerror(errno));
193                 }
194         }
195 }
196
197 /****************************************************************************
198  See if the kernel supports oplocks.
199 ****************************************************************************/
200
201 static bool linux_oplocks_available(void)
202 {
203         int fd, ret;
204         fd = open("/dev/null", O_RDONLY);
205         if (fd == -1)
206                 return False; /* uggh! */
207         ret = fcntl(fd, F_GETLEASE, 0);
208         close(fd);
209         return ret == F_UNLCK;
210 }
211
212 /****************************************************************************
213  Setup kernel oplocks.
214 ****************************************************************************/
215
216 static const struct kernel_oplocks_ops linux_koplocks = {
217         .set_oplock                     = linux_set_kernel_oplock,
218         .release_oplock                 = linux_release_kernel_oplock,
219 };
220
221 struct kernel_oplocks *linux_init_kernel_oplocks(struct smbd_server_connection *sconn)
222 {
223         struct kernel_oplocks *ctx;
224         struct tevent_signal *se;
225
226         if (!linux_oplocks_available()) {
227                 DEBUG(3,("Linux kernel oplocks not available\n"));
228                 return NULL;
229         }
230
231         ctx = talloc_zero(sconn, struct kernel_oplocks);
232         if (!ctx) {
233                 DEBUG(0,("Linux Kernel oplocks talloc_Zero failed\n"));
234                 return NULL;
235         }
236
237         ctx->ops = &linux_koplocks;
238         ctx->private_data = sconn;
239
240         se = tevent_add_signal(sconn->ev_ctx,
241                                ctx,
242                                RT_SIGNAL_LEASE, SA_SIGINFO,
243                                linux_oplock_signal_handler,
244                                ctx);
245         if (!se) {
246                 DEBUG(0,("Failed to setup RT_SIGNAL_LEASE handler"));
247                 TALLOC_FREE(ctx);
248                 return NULL;
249         }
250
251         DEBUG(3,("Linux kernel oplocks enabled\n"));
252
253         return ctx;
254 }
255 #else
256  void oplock_linux_dummy(void);
257
258  void oplock_linux_dummy(void) {}
259 #endif /* HAVE_KERNEL_OPLOCKS_LINUX */