summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
authorVolker Lendecke <vlendec@samba.org>2006-01-05 11:35:29 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:06:01 -0500
commita189257c15725e36e68970ed723f3365d4496792 (patch)
tree9b02968535257705af636aa43830fba00b68b82f /source3/smbd
parentc3a2101da021abf52d06842598325a6cef6bbc83 (diff)
downloadsamba-a189257c15725e36e68970ed723f3365d4496792.tar.gz
samba-a189257c15725e36e68970ed723f3365d4496792.tar.bz2
samba-a189257c15725e36e68970ed723f3365d4496792.zip
r12721: GPFS 2.4 on Linux will contain some windows semantics, ie share modes and
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)
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/gpfs.c159
-rw-r--r--source3/smbd/open.c14
-rw-r--r--source3/smbd/oplock_linux.c22
-rw-r--r--source3/smbd/server.c2
4 files changed, 191 insertions, 6 deletions
diff --git a/source3/smbd/gpfs.c b/source3/smbd/gpfs.c
new file mode 100644
index 0000000000..4a8b9eea6c
--- /dev/null
+++ b/source3/smbd/gpfs.c
@@ -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
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index e6c749fab9..2f82f04b63 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -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.
*/
diff --git a/source3/smbd/oplock_linux.c b/source3/smbd/oplock_linux.c
index ab0c08f7fc..0285bfce97 100644
--- a/source3/smbd/oplock_linux.c
+++ b/source3/smbd/oplock_linux.c
@@ -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",
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index ff894e2460..56c9c72127 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -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 */