smb2_server: call smbXsrv_connection_disconnect_transport() early on network errors
[gd/samba-autobuild/.git] / source3 / smbd / oplock_linux.c
index 190578e0ccb6d86cd9757344931f86a0597124ca..44ed976b92cbd63237313ebd86f9fc7886959101 100644 (file)
@@ -23,7 +23,7 @@
 #include "smbd/smbd.h"
 #include "smbd/globals.h"
 
-#if HAVE_KERNEL_OPLOCKS_LINUX
+#ifdef HAVE_KERNEL_OPLOCKS_LINUX
 
 #ifndef F_SETLEASE
 #define F_SETLEASE     1024
 #define F_GETLEASE     1025
 #endif
 
-#ifndef CAP_LEASE
-#define CAP_LEASE 28
-#endif
-
 #ifndef RT_SIGNAL_LEASE
 #define RT_SIGNAL_LEASE (SIGRTMIN+1)
 #endif
 #define F_SETSIG 10
 #endif
 
-/*
- * public function to get linux lease capability. Needed by some VFS modules (eg. gpfs.c)
- */
-void linux_set_lease_capability(void)
-{
-       set_effective_capability(LEASE_CAPABILITY);
-}
-
 /* 
  * Call to set the kernel lease signal handler
  */
@@ -75,13 +63,33 @@ int linux_set_lease_sighandler(int fd)
 int linux_setlease(int fd, int leasetype)
 {
        int ret;
+       int saved_errno;
+
+       /*
+        * Ensure the lease owner is root to allow
+        * correct delivery of lease-break signals.
+        */
+
+       become_root();
 
+       /* First set the signal handler. */
+       if (linux_set_lease_sighandler(fd) == -1) {
+               saved_errno = errno;
+               ret = -1;
+               goto out;
+       }
        ret = fcntl(fd, F_SETLEASE, leasetype);
-       if (ret == -1 && errno == EACCES) {
-               set_effective_capability(LEASE_CAPABILITY);
-               ret = fcntl(fd, F_SETLEASE, leasetype);
+       if (ret == -1) {
+               saved_errno = errno;
        }
 
+  out:
+
+       unbecome_root();
+
+       if (ret == -1) {
+               errno = saved_errno;
+       }
        return ret;
 }
 
@@ -120,19 +128,23 @@ static void linux_oplock_signal_handler(struct tevent_context *ev_ctx,
 static bool linux_set_kernel_oplock(struct kernel_oplocks *ctx,
                                    files_struct *fsp, int oplock_type)
 {
+       struct file_id_buf idbuf;
+
        if ( SMB_VFS_LINUX_SETLEASE(fsp, F_WRLCK) == -1) {
-               DEBUG(3,("linux_set_kernel_oplock: Refused oplock on file %s, "
-                        "fd = %d, file_id = %s. (%s)\n",
-                        fsp_str_dbg(fsp), fsp->fh->fd,
-                        file_id_string_tos(&fsp->file_id),
-                        strerror(errno)));
+               DBG_NOTICE("Refused oplock on file %s, "
+                          "fd = %d, file_id = %s. (%s)\n",
+                          fsp_str_dbg(fsp),
+                          fsp->fh->fd,
+                          file_id_str_buf(fsp->file_id, &idbuf),
+                          strerror(errno));
                return False;
        }
        
-       DEBUG(3,("linux_set_kernel_oplock: got kernel oplock on file %s, "
-                "file_id = %s gen_id = %lu\n",
-                fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id),
-                fsp->fh->gen_id));
+       DBG_NOTICE("got kernel oplock on file %s, "
+                  "file_id = %s gen_id = %"PRIu64"\n",
+                  fsp_str_dbg(fsp),
+                  file_id_str_buf(fsp->file_id, &idbuf),
+                  fsp->fh->gen_id);
 
        return True;
 }
@@ -144,6 +156,8 @@ static bool linux_set_kernel_oplock(struct kernel_oplocks *ctx,
 static void linux_release_kernel_oplock(struct kernel_oplocks *ctx,
                                        files_struct *fsp, int oplock_type)
 {
+       struct file_id_buf idbuf;
+
        if (DEBUGLVL(10)) {
                /*
                 * Check and print out the current kernel
@@ -151,10 +165,12 @@ static void linux_release_kernel_oplock(struct kernel_oplocks *ctx,
                 */
                int state = fcntl(fsp->fh->fd, F_GETLEASE, 0);
                dbgtext("linux_release_kernel_oplock: file %s, file_id = %s "
-                       "gen_id = %lu has kernel oplock state "
-                       "of %x.\n", fsp_str_dbg(fsp),
-                       file_id_string_tos(&fsp->file_id),
-                       fsp->fh->gen_id, state );
+                       "gen_id = %"PRIu64" has kernel oplock state "
+                       "of %x.\n",
+                       fsp_str_dbg(fsp),
+                       file_id_str_buf(fsp->file_id, &idbuf),
+                       fsp->fh->gen_id,
+                       state);
        }
 
        /*
@@ -164,10 +180,12 @@ static void linux_release_kernel_oplock(struct kernel_oplocks *ctx,
                if (DEBUGLVL(0)) {
                        dbgtext("linux_release_kernel_oplock: Error when "
                                "removing kernel oplock on file " );
-                       dbgtext("%s, file_id = %s, gen_id = %lu. "
-                               "Error was %s\n", fsp_str_dbg(fsp),
-                               file_id_string_tos(&fsp->file_id),
-                               fsp->fh->gen_id, strerror(errno) );
+                       dbgtext("%s, file_id = %s, gen_id = %"PRIu64". "
+                               "Error was %s\n",
+                               fsp_str_dbg(fsp),
+                               file_id_str_buf(fsp->file_id, &idbuf),
+                               fsp->fh->gen_id,
+                               strerror(errno));
                }
        }
 }
@@ -194,8 +212,6 @@ static bool linux_oplocks_available(void)
 static const struct kernel_oplocks_ops linux_koplocks = {
        .set_oplock                     = linux_set_kernel_oplock,
        .release_oplock                 = linux_release_kernel_oplock,
-       .contend_level2_oplocks_begin   = NULL,
-       .contend_level2_oplocks_end     = NULL,
 };
 
 struct kernel_oplocks *linux_init_kernel_oplocks(struct smbd_server_connection *sconn)