r12721: GPFS 2.4 on Linux will contain some windows semantics, ie share modes and
authorVolker Lendecke <vlendec@samba.org>
Thu, 5 Jan 2006 11:35:29 +0000 (11:35 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 16:06:01 +0000 (11:06 -0500)
oplocks across the cluster. Adapt Samba to it.

The gpfs API is called via libgpfs.so. This code is written with dlopen(), so
that you can compile on a system with gpfs installed and later on run on
systems without gpfs available.

So to actually make Samba call gpfs share mode calls you need to compile with
gpfs.h and libgpfs.so around and set 'gpfs share = yes' on the shares you
export from GPFS.

Volker
(This used to be commit 2253b17a1a88555291b59d52c826c81c2b8f7e7f)

source3/Makefile.in
source3/configure.in
source3/param/loadparm.c
source3/smbd/gpfs.c [new file with mode: 0644]
source3/smbd/open.c
source3/smbd/oplock_linux.c
source3/smbd/server.c

index 9d00cb72a1d966d1147baa95815d884d8d25ebfc..54dbecb764e7c5ff012b37cbc499c97b7eeba8b4 100644 (file)
@@ -403,7 +403,7 @@ SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \
               lib/sysquotas_xfs.o lib/sysquotas_4A.o \
               smbd/change_trust_pw.o smbd/fake_file.o \
               smbd/quotas.o smbd/ntquotas.o $(AFS_OBJ) smbd/msdfs.o \
-              $(AFS_SETTOKEN_OBJ) smbd/aio.o smbd/statvfs.o \
+              $(AFS_SETTOKEN_OBJ) smbd/aio.o smbd/gpfs.o smbd/statvfs.o \
               $(MANGLE_OBJ) @VFS_STATIC@
 
 SMBD_OBJ_BASE = $(PARAM_OBJ) $(SMBD_OBJ_SRV) $(LIBSMB_OBJ) \
index ec1bdacad84e495db4f8f593b19282a71a003e9d..2b1f4d691f9835fadb7dd5bee9b0ebeead8da5e6 100644 (file)
@@ -1159,6 +1159,19 @@ AC_CHECK_FUNCS(setbuffer shmget shm_open backtrace_symbols)
 AC_CHECK_HEADERS(libexc.h)
 AC_CHECK_LIB(exc, trace_back_stack)
 
+echo -n "checking for GPFS 2.4 libs... "
+save_LIBS="$LIBS"
+LIBS="$LIBS -lgpfs"
+AC_TRY_LINK([#include <gpfs.h>],
+           [gpfs_set_share(0,GPFS_SHARE_READ,GPFS_DENY_NONE)],
+           samba_cv_HAVE_GPFS_SET_SHARE=yes,
+           samba_cv_HAVE_GPFS_SET_SHARE=no)
+echo $samba_cv_HAVE_GPFS_SET_SHARE
+if test x"$samba_cv_HAVE_GPFS_SET_SHARE" = x"yes"; then
+    AC_DEFINE(HAVE_GPFS_SET_SHARE,1,[Whether GPFS 2.4 libs are available])
+fi
+LIBS="$save_LIBS"
+
 # syscall() is needed for smbwrapper.
 AC_CHECK_FUNCS(syscall)
 
index 526bce9b60ebb70e1df8be7f8e93dccdffbe1a3f..3fa6dee5a249c30a4a31d2200fdb4b594eb5d3c7 100644 (file)
@@ -433,6 +433,7 @@ typedef struct
        BOOL bProfileAcls;
        BOOL bMap_acl_inherit;
        BOOL bAfs_Share;
+       BOOL bGpfs_Share;
        BOOL bEASupport;
        BOOL bAclCheckPermissions;
        BOOL bAclMapFullControl;
@@ -569,6 +570,7 @@ static service sDefault = {
        False,                  /* bProfileAcls */
        False,                  /* bMap_acl_inherit */
        False,                  /* bAfs_Share */
+       False,                  /* bGpfs_Share */
        False,                  /* bEASupport */
        True,                   /* bAclCheckPermissions */
        True,                   /* bAclMapFullControl */
@@ -967,6 +969,7 @@ static struct parm_struct parm_table[] = {
        {"announce as", P_ENUM, P_GLOBAL, &Globals.announce_as, NULL, enum_announce_as,  FLAG_ADVANCED}, 
        {"map acl inherit", P_BOOL, P_LOCAL, &sDefault.bMap_acl_inherit, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, 
        {"afs share", P_BOOL, P_LOCAL, &sDefault.bAfs_Share, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL},
+       {"gpfs share", P_BOOL, P_LOCAL, &sDefault.bGpfs_Share, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL},
        {"max mux", P_INTEGER, P_GLOBAL, &Globals.max_mux, NULL, NULL, FLAG_ADVANCED}, 
        {"max xmit", P_INTEGER, P_GLOBAL, &Globals.max_xmit, NULL, NULL, FLAG_ADVANCED}, 
 
@@ -2001,6 +2004,7 @@ FN_LOCAL_BOOL(_lp_use_sendfile, bUseSendfile)
 FN_LOCAL_BOOL(lp_profile_acls, bProfileAcls)
 FN_LOCAL_BOOL(lp_map_acl_inherit, bMap_acl_inherit)
 FN_LOCAL_BOOL(lp_afs_share, bAfs_Share)
+FN_LOCAL_BOOL(lp_gpfs_share, bGpfs_Share)
 FN_LOCAL_BOOL(lp_acl_check_permissions, bAclCheckPermissions)
 FN_LOCAL_BOOL(lp_acl_group_control, bAclGroupControl)
 FN_LOCAL_BOOL(lp_acl_map_full_control, bAclMapFullControl)
diff --git a/source3/smbd/gpfs.c b/source3/smbd/gpfs.c
new file mode 100644 (file)
index 0000000..4a8b9ee
--- /dev/null
@@ -0,0 +1,159 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  Provide a connection to GPFS specific features
+ *  Copyright (C) Volker Lendecke 2005
+ *
+ *  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
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  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.
+ */
+
+#include "includes.h"
+
+#ifdef HAVE_GPFS_SET_SHARE
+
+#include "gpfs.h"
+
+static void *libgpfs_handle = NULL;
+
+static int (*gpfs_set_share_fn)(int fd, unsigned int allow, unsigned int deny);
+static int (*gpfs_set_lease_fn)(int fd, unsigned int leaseType);
+
+BOOL set_gpfs_sharemode(files_struct *fsp, uint32 access_mask,
+                       uint32 share_access)
+{
+       unsigned int allow = GPFS_SHARE_NONE;
+       unsigned int deny = GPFS_DENY_NONE;
+       int result;
+
+       if (gpfs_set_share_fn == NULL) {
+               return False;
+       }
+
+       if ((fsp == NULL) || (fsp->fh == NULL) || (fsp->fh->fd < 0)) {
+               /* No real file, don't disturb */
+               return True;
+       }
+
+       allow |= (access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA|
+                                DELETE_ACCESS)) ? GPFS_SHARE_WRITE : 0;
+       allow |= (access_mask & (FILE_READ_DATA|FILE_EXECUTE)) ?
+               GPFS_SHARE_READ : 0;
+       deny |= (share_access & (FILE_SHARE_WRITE|FILE_SHARE_DELETE)) ?
+               0 : GPFS_DENY_WRITE;
+       deny |= (share_access & (FILE_SHARE_READ)) ?
+               0 : GPFS_DENY_READ;
+
+       DEBUG(10, ("am=%x, allow=%d, sa=%x, deny=%d\n",
+                  access_mask, allow, share_access, deny));
+
+       result = gpfs_set_share_fn(fsp->fh->fd, allow, deny);
+       if (result != 0) {
+               if (errno == ENOSYS) {
+                       DEBUG(5, ("'gpfs share = yes' set, but no gpfs "
+                                 "available. Allowing access\n"));
+                       return True;
+               } else {
+                       DEBUG(10, ("gpfs_set_share failed: %s\n",
+                                  strerror(errno)));
+               }
+       }
+
+       return (result == 0);
+}
+
+int set_gpfs_lease(int fd, int leasetype)
+{
+       int gpfs_type = GPFS_LEASE_NONE;
+
+       if (gpfs_set_lease_fn == NULL) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (leasetype == F_RDLCK) {
+               gpfs_type = GPFS_LEASE_READ;
+       }
+       if (leasetype == F_WRLCK) {
+               gpfs_type = GPFS_LEASE_WRITE;
+       }
+       return gpfs_set_lease_fn(fd, gpfs_type);
+}
+
+void init_gpfs(void)
+{
+       if (libgpfs_handle != NULL) {
+               return;
+       }
+
+       libgpfs_handle = sys_dlopen("libgpfs.so", RTLD_LAZY);
+
+       if (libgpfs_handle == NULL) {
+               DEBUG(10, ("sys_dlopen for libgpfs.so failed: %s\n",
+                          strerror(errno)));
+               return;
+       }
+
+       DEBUG(10, ("libgpfs.so loaded\n"));
+
+       gpfs_set_share_fn = sys_dlsym(libgpfs_handle, "gpfs_set_share");
+       if (gpfs_set_share_fn == NULL) {
+               DEBUG(3, ("libgpfs.so does not contain the symbol "
+                         "'gpfs_set_share'\n"));
+               sys_dlclose(libgpfs_handle);
+
+               /* leave libgpfs_handle != NULL around, no point
+                  in trying twice */
+               gpfs_set_lease_fn = NULL;
+               return;
+       }
+
+       gpfs_set_lease_fn = sys_dlsym(libgpfs_handle, "gpfs_set_lease");
+       if (gpfs_set_lease_fn == NULL) {
+               DEBUG(3, ("libgpfs.so does not contain the symbol "
+                         "'gpfs_set_lease'\n"));
+               sys_dlclose(libgpfs_handle);
+
+               /* leave libgpfs_handle != NULL around, no point
+                  in trying twice */
+               gpfs_set_share_fn = NULL;
+               return;
+       }
+}
+
+#else
+
+int set_gpfs_lease(int snum, int leasetype)
+{
+       DEBUG(0, ("'gpfs share = yes' set without gpfs support compiled\n"));
+
+       /* We need to indicate that no GPFS is around by returning ENOSYS, so
+        * that the normal linux kernel oplock code is called. */
+       errno = ENOSYS;
+       return -1;
+}
+
+BOOL set_gpfs_sharemode(files_struct *fsp, uint32 access_mask,
+                       uint32 share_access)
+{
+       DEBUG(0, ("'gpfs share = yes' set without gpfs support compiled\n"));
+       /* Don't disturb but complain */
+       return True;
+}
+
+void init_gpfs(void)
+{
+       return;
+}
+
+#endif
index e6c749fab9cf48c58a2f4cabd72c81d702985437..2f82f04b6398e16212542da44b2d2631db91692d 100644 (file)
@@ -1599,6 +1599,20 @@ files_struct *open_file_ntcreate(connection_struct *conn,
         * deny mode is compatible with all current opens.
         */
 
+       if (lp_gpfs_share(SNUM(fsp->conn)) &&
+           !set_gpfs_sharemode(fsp, access_mask, share_access)) {
+
+               /* GPFS does have share mode support, so the comment above wrt
+                * NFS being wrong is not correct here. */
+
+               set_saved_error_triple(ERRDOS, ERRbadshare,
+                                      NT_STATUS_SHARING_VIOLATION);
+               talloc_free(lck);
+               fd_close(conn, fsp);
+               file_free(fsp);
+               return NULL;
+       }
+
        /*
         * If requested, truncate the file.
         */
index ab0c08f7fcc524b3b74eccde5ea1646889617992..0285bfce97ab816f85fa76321510c4737b878a21 100644 (file)
@@ -101,11 +101,11 @@ static void set_capability(unsigned capability)
 }
 
 /****************************************************************************
- Call SETLEASE. If we get EACCES then we try setting up the right capability and
- try again
+ Call SETLEASE. If we get EACCES then we try setting up the right capability
and try again
 ****************************************************************************/
 
-static int linux_setlease(int fd, int leasetype)
+static int linux_setlease(int snum, int fd, int leasetype)
 {
        int ret;
 
@@ -114,7 +114,17 @@ static int linux_setlease(int fd, int leasetype)
                return -1;
        }
 
-       ret = fcntl(fd, F_SETLEASE, leasetype);
+       if (lp_gpfs_share(snum)) {
+               ret = set_gpfs_lease(fd, leasetype);
+       } else {
+               ret = fcntl(fd, F_SETLEASE, leasetype);
+       }
+
+       if ((ret < 0) && (errno == ENOSYS)) {
+               /* This must have come from GPFS not being available */
+               ret = fcntl(fd, F_SETLEASE, leasetype);
+       }
+
        if (ret == -1 && errno == EACCES) {
                set_capability(CAP_LEASE);
                ret = fcntl(fd, F_SETLEASE, leasetype);
@@ -154,7 +164,7 @@ static files_struct *linux_oplock_receive_message(fd_set *fds)
 
 static BOOL linux_set_kernel_oplock(files_struct *fsp, int oplock_type)
 {
-       if (linux_setlease(fsp->fh->fd, F_WRLCK) == -1) {
+       if (linux_setlease(SNUM(fsp->conn), fsp->fh->fd, F_WRLCK) == -1) {
                DEBUG(3,("linux_set_kernel_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
 inode = %.0f. (%s)\n",
                         fsp->fsp_name, fsp->fh->fd, 
@@ -188,7 +198,7 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
        /*
         * Remove the kernel oplock on this file.
         */
-       if (linux_setlease(fsp->fh->fd, F_UNLCK) == -1) {
+       if (linux_setlease(SNUM(fsp->conn), fsp->fh->fd, F_UNLCK) == -1) {
                if (DEBUGLVL(0)) {
                        dbgtext("linux_release_kernel_oplock: Error when removing kernel oplock on file " );
                        dbgtext("%s, dev = %x, inode = %.0f, file_id = %lu. Error was %s\n",
index ff894e2460c54f07bb91eb3fca727ec075ee2e25..56c9c7212767cfe1811b08a6f3490c029677e852 100644 (file)
@@ -899,6 +899,8 @@ void build_options(BOOL screen);
        if (!print_backend_init())
                exit(1);
 
+       init_gpfs();
+
        /* Setup the main smbd so that we can get messages. */
        /* don't worry about general printing messages here */