s3: vfs: bump to version 40, Samba 4.10 will ship with that
[vlendec/samba-autobuild/.git] / source3 / smbd / oplock_irix.c
index c1159cd73b49285b47ddd581ff9f18fc7884c8f3..75f34df1c2059a0d53b0e509254d744b6a1fe391 100644 (file)
@@ -5,7 +5,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #define DBGC_CLASS DBGC_LOCKING
 #include "includes.h"
+#include "system/filesys.h"
+#include "smbd/smbd.h"
+#include "smbd/globals.h"
 
 #if HAVE_KERNEL_OPLOCKS_IRIX
 
-static int oplock_pipe_write = -1;
-static int oplock_pipe_read = -1;
+struct irix_oplocks_context {
+       struct kernel_oplocks *ctx;
+       struct smbd_server_connection *sconn;
+       int write_fd;
+       int read_fd;
+       struct tevent_fd *read_fde;
+       bool pending;
+};
 
 /****************************************************************************
  Test to see if IRIX kernel oplocks work.
 ****************************************************************************/
 
-static BOOL irix_oplocks_available(void)
+static bool irix_oplocks_available(void)
 {
        int fd;
        int pfd[2];
-       pstring tmpname;
+       TALLOC_CTX *ctx = talloc_stackframe();
+       char *tmpname = NULL;
 
        set_effective_capability(KERNEL_OPLOCK_CAPABILITY);
 
-       slprintf(tmpname,sizeof(tmpname)-1, "%s/koplock.%d", lp_lockdir(),
-                (int)sys_getpid());
+       tmpname = talloc_asprintf(ctx,
+                               "%s/koplock.%d",
+                               lp_lock_directory(),
+                               (int)getpid());
+       if (!tmpname) {
+               TALLOC_FREE(ctx);
+               return False;
+       }
 
        if(pipe(pfd) != 0) {
                DEBUG(0,("check_kernel_oplocks: Unable to create pipe. Error "
                         "was %s\n",
                         strerror(errno) ));
+               TALLOC_FREE(ctx);
                return False;
        }
 
-       if((fd = sys_open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600)) < 0) {
+       if((fd = open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600)) < 0) {
                DEBUG(0,("check_kernel_oplocks: Unable to open temp test file "
                         "%s. Error was %s\n",
                         tmpname, strerror(errno) ));
                unlink( tmpname );
                close(pfd[0]);
                close(pfd[1]);
+               TALLOC_FREE(ctx);
                return False;
        }
 
        unlink(tmpname);
 
+       TALLOC_FREE(ctx);
+
        if(sys_fcntl_long(fd, F_OPLKREG, pfd[1]) == -1) {
                DEBUG(0,("check_kernel_oplocks: Kernel oplocks are not "
                         "available on this machine. Disabling kernel oplock "
@@ -87,31 +106,53 @@ static BOOL irix_oplocks_available(void)
        return True;
 }
 
+/*
+ * This is bad because the file_id should always be created through the vfs
+ * layer!  Unfortunately, a conn struct isn't available here.
+ */
+static struct file_id file_id_create_dev(SMB_DEV_T dev, SMB_INO_T inode)
+{
+       struct file_id key;
+
+       /* the ZERO_STRUCT ensures padding doesn't break using the key as a
+        * blob */
+       ZERO_STRUCT(key);
+
+       key.devid = dev;
+       key.inode = inode;
+
+       return key;
+}
+
 /****************************************************************************
  * Deal with the IRIX kernel <--> smbd
  * oplock break protocol.
 ****************************************************************************/
 
-static files_struct *irix_oplock_receive_message(fd_set *fds)
+static files_struct *irix_oplock_receive_message(struct kernel_oplocks *_ctx)
 {
-       extern int smb_read_error;
+       struct irix_oplocks_context *ctx = talloc_get_type(_ctx->private_data,
+                                          struct irix_oplocks_context);
        oplock_stat_t os;
        char dummy;
+       struct file_id fileid;
        files_struct *fsp;
 
-       /* Ensure we only get one call per select fd set. */
-       FD_CLR(oplock_pipe_read, fds);
+       /*
+        * TODO: is it correct to assume we only get one
+        * oplock break, for each byte we read from the pipe?
+        */
+       ctx->pending = false;
 
        /*
         * Read one byte of zero to clear the
         * kernel break notify message.
         */
 
-       if(read(oplock_pipe_read, &dummy, 1) != 1) {
+       if(read(ctx->read_fd, &dummy, 1) != 1) {
                DEBUG(0,("irix_oplock_receive_message: read of kernel "
                         "notification failed. Error was %s.\n",
                         strerror(errno) ));
-               smb_read_error = READ_ERROR;
                return NULL;
        }
 
@@ -121,7 +162,7 @@ static files_struct *irix_oplock_receive_message(fd_set *fds)
         * request outstanding.
         */
 
-       if(sys_fcntl_ptr(oplock_pipe_read, F_OPLKSTAT, &os) < 0) {
+       if(sys_fcntl_ptr(ctx->read_fd, F_OPLKSTAT, &os) < 0) {
                DEBUG(0,("irix_oplock_receive_message: fcntl of kernel "
                         "notification failed. Error was %s.\n",
                         strerror(errno) ));
@@ -131,17 +172,20 @@ static files_struct *irix_oplock_receive_message(fd_set *fds)
                         */
                        return NULL;
                }
-               smb_read_error = READ_ERROR;
                return NULL;
        }
 
        /*
         * We only have device and inode info here - we have to guess that this
         * is the first fsp open with this dev,ino pair.
+        *
+        * NOTE: this doesn't work if any VFS modules overloads
+        *       the file_id_create() hook!
         */
 
-       if ((fsp = file_find_di_first((SMB_DEV_T)os.os_dev,
-                                     (SMB_INO_T)os.os_ino)) == NULL) {
+       fileid = file_id_create_dev((SMB_DEV_T)os.os_dev,
+                                   (SMB_INO_T)os.os_ino);
+       if ((fsp = file_find_di_first(ctx->sconn, fileid)) == NULL) {
                DEBUG(0,("irix_oplock_receive_message: unable to find open "
                         "file with dev = %x, inode = %.0f\n",
                         (unsigned int)os.os_dev, (double)os.os_ino ));
@@ -149,9 +193,9 @@ static files_struct *irix_oplock_receive_message(fd_set *fds)
        }
      
        DEBUG(5,("irix_oplock_receive_message: kernel oplock break request "
-                "received for dev = %x, inode = %.0f\n, file_id = %ul",
-                (unsigned int)fsp->dev, (double)fsp->inode,
-                fsp->fh->file_id ));
+                "received for file_id %s gen_id = %ul",
+                file_id_string_tos(&fsp->file_id),
+                fsp->fh->gen_id ));
 
        return fsp;
 }
@@ -160,32 +204,37 @@ static files_struct *irix_oplock_receive_message(fd_set *fds)
  Attempt to set an kernel oplock on a file.
 ****************************************************************************/
 
-static BOOL irix_set_kernel_oplock(files_struct *fsp, int oplock_type)
+static bool irix_set_kernel_oplock(struct kernel_oplocks *_ctx,
+                                  files_struct *fsp, int oplock_type)
 {
-       if (sys_fcntl_long(fsp->fh->fd, F_OPLKREG, oplock_pipe_write) == -1) {
+       struct irix_oplocks_context *ctx = talloc_get_type(_ctx->private_data,
+                                          struct irix_oplocks_context);
+
+       if (sys_fcntl_long(fsp->fh->fd, F_OPLKREG, ctx->write_fd) == -1) {
                if(errno != EAGAIN) {
                        DEBUG(0,("irix_set_kernel_oplock: Unable to get "
-                                "kernel oplock on file %s, dev = %x, inode "
-                                "= %.0f, file_id = %ul. Error was %s\n", 
-                                fsp->fsp_name, (unsigned int)fsp->dev,
-                                (double)fsp->inode, fsp->fh->file_id,
+                                "kernel oplock on file %s, file_id %s "
+                                "gen_id = %ul. Error was %s\n", 
+                                fsp_str_dbg(fsp),
+                                file_id_string_tos(&fsp->file_id),
+                                fsp->fh->gen_id,
                                 strerror(errno) ));
                } else {
                        DEBUG(5,("irix_set_kernel_oplock: Refused oplock on "
-                                "file %s, fd = %d, dev = %x, inode = %.0f, "
-                                "file_id = %ul. Another process had the file "
+                                "file %s, fd = %d, file_id = %s, "
+                                "gen_id = %ul. Another process had the file "
                                 "open.\n",
-                                fsp->fsp_name, fsp->fh->fd,
-                                (unsigned int)fsp->dev, (double)fsp->inode,
-                                fsp->fh->file_id ));
+                                fsp_str_dbg(fsp), fsp->fh->fd,
+                                file_id_string_tos(&fsp->file_id),
+                                fsp->fh->gen_id ));
                }
                return False;
        }
        
-       DEBUG(10,("irix_set_kernel_oplock: got kernel oplock on file %s, dev "
-                 "= %x, inode = %.0f, file_id = %ul\n",
-                 fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode,
-                 fsp->fh->file_id));
+       DEBUG(10,("irix_set_kernel_oplock: got kernel oplock on file %s, file_id = %s "
+                 "gen_id = %ul\n",
+                 fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id),
+                 fsp->fh->gen_id));
 
        return True;
 }
@@ -194,7 +243,8 @@ static BOOL irix_set_kernel_oplock(files_struct *fsp, int oplock_type)
  Release a kernel oplock on a file.
 ****************************************************************************/
 
-static void irix_release_kernel_oplock(files_struct *fsp)
+static void irix_release_kernel_oplock(struct kernel_oplocks *_ctx,
+                                      files_struct *fsp, int oplock_type)
 {
        if (DEBUGLVL(10)) {
                /*
@@ -202,10 +252,11 @@ static void irix_release_kernel_oplock(files_struct *fsp)
                 * oplock state of this file.
                 */
                int state = sys_fcntl_long(fsp->fh->fd, F_OPLKACK, -1);
-               dbgtext("irix_release_kernel_oplock: file %s, dev = %x, "
-                       "inode = %.0f file_id = %ul, has kernel oplock state "
-                       "of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
-                        (double)fsp->inode, fsp->fh->file_id, state );
+               dbgtext("irix_release_kernel_oplock: file %s, file_id = %s"
+                       "gen_id = %ul, has kernel oplock state "
+                       "of %x.\n", fsp_str_dbg(fsp),
+                       file_id_string_tos(&fsp->file_id),
+                        fsp->fh->gen_id, state );
        }
 
        /*
@@ -215,73 +266,81 @@ static void irix_release_kernel_oplock(files_struct *fsp)
                if( DEBUGLVL( 0 )) {
                        dbgtext("irix_release_kernel_oplock: Error when "
                                "removing kernel oplock on file " );
-                       dbgtext("%s, dev = %x, inode = %.0f, file_id = %ul. "
+                       dbgtext("%s, file_id = %s gen_id = %ul. "
                                "Error was %s\n",
-                               fsp->fsp_name, (unsigned int)fsp->dev, 
-                               (double)fsp->inode, fsp->fh->file_id,
+                               fsp_str_dbg(fsp),
+                               file_id_string_tos(&fsp->file_id),
+                               fsp->fh->gen_id,
                                strerror(errno) );
                }
        }
 }
 
-/****************************************************************************
- See if there is a message waiting in this fd set.
- Note that fds MAY BE NULL ! If so we must do our own select.
-****************************************************************************/
-
-static BOOL irix_oplock_msg_waiting(fd_set *fds)
+static void irix_oplocks_read_fde_handler(struct tevent_context *ev,
+                                         struct tevent_fd *fde,
+                                         uint16_t flags,
+                                         void *private_data)
 {
-       int selrtn;
-       fd_set myfds;
-       struct timeval to;
-
-       if (oplock_pipe_read == -1)
-               return False;
-
-       if (fds) {
-               return FD_ISSET(oplock_pipe_read, fds);
-       }
-
-       /* Do a zero-time select. We just need to find out if there
-        * are any outstanding messages. We use sys_select_intr as
-        * we need to ignore any signals. */
-
-       FD_ZERO(&myfds);
-       FD_SET(oplock_pipe_read, &myfds);
+       struct irix_oplocks_context *ctx = talloc_get_type(private_data,
+                                          struct irix_oplocks_context);
+       files_struct *fsp;
 
-       to = timeval_set(0, 0);
-       selrtn = sys_select_intr(oplock_pipe_read+1,&myfds,NULL,NULL,&to);
-       return (selrtn == 1) ? True : False;
+       fsp = irix_oplock_receive_message(ctx->ctx);
+       break_kernel_oplock(ctx->sconn->msg_ctx, fsp);
 }
 
 /****************************************************************************
  Setup kernel oplocks.
 ****************************************************************************/
 
-struct kernel_oplocks *irix_init_kernel_oplocks(void) 
+static const struct kernel_oplocks_ops irix_koplocks = {
+       .set_oplock                     = irix_set_kernel_oplock,
+       .release_oplock                 = irix_release_kernel_oplock,
+       .contend_level2_oplocks_begin   = NULL,
+       .contend_level2_oplocks_end     = NULL,
+};
+
+struct kernel_oplocks *irix_init_kernel_oplocks(struct smbd_server_connection *sconn)
 {
+       struct kernel_oplocks *_ctx;
+       struct irix_oplocks_context *ctx;
        int pfd[2];
-       static struct kernel_oplocks koplocks;
 
        if (!irix_oplocks_available())
                return NULL;
 
+       _ctx = talloc_zero(sconn, struct kernel_oplocks);
+       if (!_ctx) {
+               return NULL;
+       }
+
+       ctx = talloc_zero(_ctx, struct irix_oplocks_context);
+       if (!ctx) {
+               talloc_free(_ctx);
+               return NULL;
+       }
+       _ctx->ops = &irix_koplocks;
+       _ctx->private_data = ctx;
+       ctx->ctx = _ctx;
+       ctx->sconn = sconn;
+
        if(pipe(pfd) != 0) {
+               talloc_free(_ctx);
                DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. "
                         "Error was %s\n", strerror(errno) ));
                return False;
        }
 
-       oplock_pipe_read = pfd[0];
-       oplock_pipe_write = pfd[1];
-
-       koplocks.receive_message = irix_oplock_receive_message;
-       koplocks.set_oplock = irix_set_kernel_oplock;
-       koplocks.release_oplock = irix_release_kernel_oplock;
-       koplocks.msg_waiting = irix_oplock_msg_waiting;
-       koplocks.notification_fd = oplock_pipe_read;
+       ctx->read_fd = pfd[0];
+       ctx->write_fd = pfd[1];
 
-       return &koplocks;
+       ctx->read_fde = tevent_add_fd(sconn->ev_ctx,
+                                    ctx,
+                                    ctx->read_fd,
+                                    TEVENT_FD_READ,
+                                    irix_oplocks_read_fde_handler,
+                                    ctx);
+       return _ctx;
 }
 #else
  void oplock_irix_dummy(void);