smbd/oplock_linux.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    kernel oplock processing for Linux
00004    Copyright (C) Andrew Tridgell 2000
00005    
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015    
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software
00018    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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  Handle a LEASE signal, incrementing the signals_received and blocking the signal.
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         } /* Else signal is lost. */
00060         sys_select_signal(RT_SIGNAL_LEASE);
00061 }
00062 
00063 /*
00064  Call to set the kernel lease signal handler
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  Call SETLEASE. If we get EACCES then we try setting up the right capability and
00078  try again.
00079  Use the SMB_VFS_LINUX_SETLEASE instead of this call directly.
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  * Deal with the Linux kernel <--> smbd
00097  * oplock break protocol.
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         /* now we can receive more signals */
00115         BlockSignals(False, RT_SIGNAL_LEASE);
00116 
00117         return fsp;
00118 }
00119 
00120 /****************************************************************************
00121  Attempt to set an kernel oplock on a file.
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  Release a kernel oplock on a file.
00145 ****************************************************************************/
00146 
00147 static void linux_release_kernel_oplock(files_struct *fsp)
00148 {
00149         if (DEBUGLVL(10)) {
00150                 /*
00151                  * Check and print out the current kernel
00152                  * oplock state of this file.
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          * Remove the kernel oplock on this file.
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  See if a oplock message is waiting.
00178 ****************************************************************************/
00179 
00180 static BOOL linux_oplock_msg_waiting(fd_set *fds)
00181 {
00182         return signals_received != 0;
00183 }
00184 
00185 /****************************************************************************
00186  See if the kernel supports oplocks.
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; /* uggh! */
00195         ret = fcntl(fd, F_GETLEASE, 0);
00196         close(fd);
00197         return ret == F_UNLCK;
00198 }
00199 
00200 /****************************************************************************
00201  Setup kernel oplocks.
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         /* the signal can start off blocked due to a bug in bash */
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 /* HAVE_KERNEL_OPLOCKS_LINUX */

Sambaに対してSat Aug 29 21:23:24 2009に生成されました。  doxygen 1.4.7