00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #define DBGC_CLASS DBGC_LOCKING
00022 #include "includes.h"
00023
00024 #if HAVE_KERNEL_OPLOCKS_LINUX
00025
00026 static SIG_ATOMIC_T signals_received;
00027 #define FD_PENDING_SIZE 100
00028 static SIG_ATOMIC_T fd_pending_array[FD_PENDING_SIZE];
00029
00030 #ifndef F_SETLEASE
00031 #define F_SETLEASE 1024
00032 #endif
00033
00034 #ifndef F_GETLEASE
00035 #define F_GETLEASE 1025
00036 #endif
00037
00038 #ifndef CAP_LEASE
00039 #define CAP_LEASE 28
00040 #endif
00041
00042 #ifndef RT_SIGNAL_LEASE
00043 #define RT_SIGNAL_LEASE (SIGRTMIN+1)
00044 #endif
00045
00046 #ifndef F_SETSIG
00047 #define F_SETSIG 10
00048 #endif
00049
00050
00051
00052
00053
00054 static void signal_handler(int sig, siginfo_t *info, void *unused)
00055 {
00056 if (signals_received < FD_PENDING_SIZE - 1) {
00057 fd_pending_array[signals_received] = (SIG_ATOMIC_T)info->si_fd;
00058 signals_received++;
00059 }
00060 sys_select_signal(RT_SIGNAL_LEASE);
00061 }
00062
00063
00064
00065
00066 int linux_set_lease_sighandler(int fd)
00067 {
00068 if (fcntl(fd, F_SETSIG, RT_SIGNAL_LEASE) == -1) {
00069 DEBUG(3,("Failed to set signal handler for kernel lease\n"));
00070 return -1;
00071 }
00072
00073 return 0;
00074 }
00075
00076
00077
00078
00079
00080
00081
00082 int linux_setlease(int fd, int leasetype)
00083 {
00084 int ret;
00085
00086 ret = fcntl(fd, F_SETLEASE, leasetype);
00087 if (ret == -1 && errno == EACCES) {
00088 set_effective_capability(LEASE_CAPABILITY);
00089 ret = fcntl(fd, F_SETLEASE, leasetype);
00090 }
00091
00092 return ret;
00093 }
00094
00095
00096
00097
00098
00099
00100 static files_struct *linux_oplock_receive_message(fd_set *fds)
00101 {
00102 int fd;
00103 files_struct *fsp;
00104
00105 BlockSignals(True, RT_SIGNAL_LEASE);
00106 fd = fd_pending_array[0];
00107 fsp = file_find_fd(fd);
00108 fd_pending_array[0] = (SIG_ATOMIC_T)-1;
00109 if (signals_received > 1)
00110 memmove(CONST_DISCARD(void *, &fd_pending_array[0]),
00111 CONST_DISCARD(void *, &fd_pending_array[1]),
00112 sizeof(SIG_ATOMIC_T)*(signals_received-1));
00113 signals_received--;
00114
00115 BlockSignals(False, RT_SIGNAL_LEASE);
00116
00117 return fsp;
00118 }
00119
00120
00121
00122
00123
00124 static BOOL linux_set_kernel_oplock(files_struct *fsp, int oplock_type)
00125 {
00126 if ( SMB_VFS_LINUX_SETLEASE(fsp,fsp->fh->fd, F_WRLCK) == -1) {
00127 DEBUG(3,("linux_set_kernel_oplock: Refused oplock on file %s, "
00128 "fd = %d, dev = %x, inode = %.0f. (%s)\n",
00129 fsp->fsp_name, fsp->fh->fd,
00130 (unsigned int)fsp->dev, (double)fsp->inode,
00131 strerror(errno)));
00132 return False;
00133 }
00134
00135 DEBUG(3,("linux_set_kernel_oplock: got kernel oplock on file %s, "
00136 "dev = %x, inode = %.0f, file_id = %lu\n",
00137 fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode,
00138 fsp->fh->file_id));
00139
00140 return True;
00141 }
00142
00143
00144
00145
00146
00147 static void linux_release_kernel_oplock(files_struct *fsp)
00148 {
00149 if (DEBUGLVL(10)) {
00150
00151
00152
00153
00154 int state = fcntl(fsp->fh->fd, F_GETLEASE, 0);
00155 dbgtext("linux_release_kernel_oplock: file %s, dev = %x, "
00156 "inode = %.0f file_id = %lu has kernel oplock state "
00157 "of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
00158 (double)fsp->inode, fsp->fh->file_id, state );
00159 }
00160
00161
00162
00163
00164 if ( SMB_VFS_LINUX_SETLEASE(fsp,fsp->fh->fd, F_UNLCK) == -1) {
00165 if (DEBUGLVL(0)) {
00166 dbgtext("linux_release_kernel_oplock: Error when "
00167 "removing kernel oplock on file " );
00168 dbgtext("%s, dev = %x, inode = %.0f, file_id = %lu. "
00169 "Error was %s\n", fsp->fsp_name,
00170 (unsigned int)fsp->dev, (double)fsp->inode,
00171 fsp->fh->file_id, strerror(errno) );
00172 }
00173 }
00174 }
00175
00176
00177
00178
00179
00180 static BOOL linux_oplock_msg_waiting(fd_set *fds)
00181 {
00182 return signals_received != 0;
00183 }
00184
00185
00186
00187
00188
00189 static BOOL linux_oplocks_available(void)
00190 {
00191 int fd, ret;
00192 fd = open("/dev/null", O_RDONLY);
00193 if (fd == -1)
00194 return False;
00195 ret = fcntl(fd, F_GETLEASE, 0);
00196 close(fd);
00197 return ret == F_UNLCK;
00198 }
00199
00200
00201
00202
00203
00204 struct kernel_oplocks *linux_init_kernel_oplocks(void)
00205 {
00206 static struct kernel_oplocks koplocks;
00207 struct sigaction act;
00208
00209 if (!linux_oplocks_available()) {
00210 DEBUG(3,("Linux kernel oplocks not available\n"));
00211 return NULL;
00212 }
00213
00214 ZERO_STRUCT(act);
00215
00216 act.sa_handler = NULL;
00217 act.sa_sigaction = signal_handler;
00218 act.sa_flags = SA_SIGINFO;
00219 sigemptyset( &act.sa_mask );
00220 if (sigaction(RT_SIGNAL_LEASE, &act, NULL) != 0) {
00221 DEBUG(0,("Failed to setup RT_SIGNAL_LEASE handler\n"));
00222 return NULL;
00223 }
00224
00225 koplocks.receive_message = linux_oplock_receive_message;
00226 koplocks.set_oplock = linux_set_kernel_oplock;
00227 koplocks.release_oplock = linux_release_kernel_oplock;
00228 koplocks.msg_waiting = linux_oplock_msg_waiting;
00229 koplocks.notification_fd = -1;
00230
00231
00232 BlockSignals(False, RT_SIGNAL_LEASE);
00233
00234 DEBUG(3,("Linux kernel oplocks enabled\n"));
00235
00236 return &koplocks;
00237 }
00238 #else
00239 void oplock_linux_dummy(void);
00240
00241 void oplock_linux_dummy(void) {}
00242 #endif