summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristof Schmitt <cs@samba.org>2014-01-07 11:55:46 -0700
committerChristof Schmitt <cs@samba.org>2014-01-09 00:04:47 +0100
commitd1dacd62bbff93351763ff339cca13ba8180dd89 (patch)
tree39e9dd8b8f75f1d92c22605366a30b44e002da5c
parentca931e460460ffe46735f98b31db47220772d566 (diff)
downloadsamba-d1dacd62bbff93351763ff339cca13ba8180dd89.tar.gz
s3: Avoid oplock break by storing timestamps with gpfs_set_times
The gpfs_set_times API call allows setting timestamps directly in GPFS without going through the utime() call. Using this API call fixes an unecessary oplock break when a client sends a SET_FILE_ALLOCATION_INFO request and no other client has opened the file. The call to utime() triggers the oplock break through the Linux kernel. Using the gpfs_set_times call for updating the timestamp avoids the call to utime() and the oplock break. Signed-off-by: Christof Schmitt <cs@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org> Autobuild-User(master): Christof Schmitt <cs@samba.org> Autobuild-Date(master): Thu Jan 9 00:04:48 CET 2014 on sn-devel-104
-rw-r--r--docs-xml/manpages/vfs_gpfs.8.xml23
-rw-r--r--source3/modules/gpfs.c46
-rw-r--r--source3/modules/vfs_gpfs.c28
-rw-r--r--source3/modules/vfs_gpfs.h1
4 files changed, 92 insertions, 6 deletions
diff --git a/docs-xml/manpages/vfs_gpfs.8.xml b/docs-xml/manpages/vfs_gpfs.8.xml
index 20dba68ffc1..4ba1b251a77 100644
--- a/docs-xml/manpages/vfs_gpfs.8.xml
+++ b/docs-xml/manpages/vfs_gpfs.8.xml
@@ -318,6 +318,29 @@
<varlistentry>
+ <term>gpfs:settimes = [ yes | no ]</term>
+ <listitem>
+ <para>
+ Use the gpfs_set_times API when changing the
+ timestamps of a file or directory. If the GPFS API is
+ not available the old method of using utime and the
+ GPFS winattr call will be used instead.
+ </para>
+
+ <itemizedlist>
+ <listitem><para>
+ <command>yes(default)</command> - Use gpfs_set_times.
+ Fall back to utime and winattr when it is not available.
+ </para></listitem>
+ <listitem><para>
+ <command>no</command> - Do not use gpfs_set_times.
+ </para></listitem>
+ </itemizedlist>
+ </listitem>
+
+ </varlistentry>
+ <varlistentry>
+
<term>nfs4:mode = [ simple | special ]</term>
<listitem>
<para>
diff --git a/source3/modules/gpfs.c b/source3/modules/gpfs.c
index 9730d3af617..62502866ac8 100644
--- a/source3/modules/gpfs.c
+++ b/source3/modules/gpfs.c
@@ -39,6 +39,8 @@ static int (*gpfs_get_winattrs_fn)(int fd, struct gpfs_winattr *attrs);
static int (*gpfs_prealloc_fn)(int fd, gpfs_off64_t startOffset, gpfs_off64_t bytesToPrealloc);
static int (*gpfs_ftruncate_fn)(int fd, gpfs_off64_t length);
static int (*gpfs_lib_init_fn)(int flags);
+static int (*gpfs_set_times_path_fn)(char *pathname, int flags,
+ gpfs_timestruc_t times[4]);
static int (*gpfs_quotactl_fn)(char *pathname, int cmd, int id, void *bufferP);
static int (*gpfs_fcntl_fn)(gpfs_file_t fileDesc, void *fcntlArgP);
static int (*gpfs_getfilesetid_fn)(char *pathname, char *name, int *idP);
@@ -290,6 +292,49 @@ void smbd_gpfs_lib_init()
}
}
+static void timespec_to_gpfs_time(struct timespec ts, gpfs_timestruc_t *gt,
+ int idx, int *flags)
+{
+ if (!null_timespec(ts)) {
+ *flags |= 1 << idx;
+ gt[idx].tv_sec = ts.tv_sec;
+ gt[idx].tv_nsec = ts.tv_nsec;
+ DEBUG(10, ("Setting GPFS time %d, flags 0x%x\n", idx, *flags));
+ }
+}
+
+int smbd_gpfs_set_times_path(char *path, struct smb_file_time *ft)
+{
+ gpfs_timestruc_t gpfs_times[4];
+ int flags = 0;
+ int rc;
+
+ if (!gpfs_set_times_path_fn) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ ZERO_ARRAY(gpfs_times);
+ timespec_to_gpfs_time(ft->atime, gpfs_times, 0, &flags);
+ timespec_to_gpfs_time(ft->mtime, gpfs_times, 1, &flags);
+ /* No good mapping from LastChangeTime to ctime, not storing */
+ timespec_to_gpfs_time(ft->create_time, gpfs_times, 3, &flags);
+
+ if (!flags) {
+ DEBUG(10, ("nothing to do, return to avoid EINVAL\n"));
+ return 0;
+ }
+
+ rc = gpfs_set_times_path_fn(path, flags, gpfs_times);
+
+ if (rc != 0) {
+ DEBUG(1,("gpfs_set_times() returned with error %s\n",
+ strerror(errno)));
+ }
+
+ return rc;
+}
+
static bool init_gpfs_function_lib(void *plibhandle_pointer,
const char *libname,
void *pfn_pointer, const char *fn_name)
@@ -354,6 +399,7 @@ void init_gpfs(void)
init_gpfs_function(&gpfs_prealloc_fn, "gpfs_prealloc");
init_gpfs_function(&gpfs_ftruncate_fn, "gpfs_ftruncate");
init_gpfs_function(&gpfs_lib_init_fn,"gpfs_lib_init");
+ init_gpfs_function(&gpfs_set_times_path_fn, "gpfs_set_times_path");
init_gpfs_function(&gpfs_quotactl_fn, "gpfs_quotactl");
init_gpfs_function(&gpfs_fcntl_fn, "gpfs_fcntl");
init_gpfs_function(&gpfs_getfilesetid_fn, "gpfs_getfilesetid");
diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c
index c374957c213..5c9981fea94 100644
--- a/source3/modules/vfs_gpfs.c
+++ b/source3/modules/vfs_gpfs.c
@@ -48,6 +48,7 @@ struct gpfs_config_data {
bool dfreequota;
bool prealloc;
bool acl;
+ bool settimes;
};
@@ -1588,6 +1589,24 @@ static int vfs_gpfs_ntimes(struct vfs_handle_struct *handle,
struct gpfs_config_data,
return -1);
+ status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = map_errno_from_nt_status(status);
+ return -1;
+ }
+
+ /* Try to use gpfs_set_times if it is enabled and available */
+ if (config->settimes) {
+ ret = smbd_gpfs_set_times_path(path, ft);
+
+ if (ret == 0 || (ret == -1 && errno != ENOSYS)) {
+ return ret;
+ }
+ }
+
+ DEBUG(10,("gpfs_set_times() not available or disabled, "
+ "use ntimes and winattr\n"));
+
ret = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
if(ret == -1){
/* don't complain if access was denied */
@@ -1607,12 +1626,6 @@ static int vfs_gpfs_ntimes(struct vfs_handle_struct *handle,
return 0;
}
- status = get_full_smb_filename(talloc_tos(), smb_fname, &path);
- if (!NT_STATUS_IS_OK(status)) {
- errno = map_errno_from_nt_status(status);
- return -1;
- }
-
attrs.winAttrs = 0;
attrs.creationTime.tv_sec = ft->create_time.tv_sec;
attrs.creationTime.tv_nsec = ft->create_time.tv_nsec;
@@ -1795,6 +1808,9 @@ static int vfs_gpfs_connect(struct vfs_handle_struct *handle,
config->acl = lp_parm_bool(SNUM(handle->conn), "gpfs", "acl", true);
+ config->settimes = lp_parm_bool(SNUM(handle->conn), "gpfs",
+ "settimes", true);
+
SMB_VFS_HANDLE_SET_DATA(handle, config,
NULL, struct gpfs_config_data,
return -1);
diff --git a/source3/modules/vfs_gpfs.h b/source3/modules/vfs_gpfs.h
index 70355e8738b..728231f146b 100644
--- a/source3/modules/vfs_gpfs.h
+++ b/source3/modules/vfs_gpfs.h
@@ -42,6 +42,7 @@ int smbd_gpfs_ftruncate(int fd, gpfs_off64_t length);
int get_gpfs_quota(const char *pathname, int type, int id,
struct gpfs_quotaInfo *qi);
int get_gpfs_fset_id(const char *pathname, int *fset_id);
+int smbd_gpfs_set_times_path(char *path, struct smb_file_time *ft);
void init_gpfs(void);
void smbd_gpfs_lib_init(void);