diff options
author | Christof Schmitt <cs@samba.org> | 2014-01-07 11:55:46 -0700 |
---|---|---|
committer | Christof Schmitt <cs@samba.org> | 2014-01-09 00:04:47 +0100 |
commit | d1dacd62bbff93351763ff339cca13ba8180dd89 (patch) | |
tree | 39e9dd8b8f75f1d92c22605366a30b44e002da5c | |
parent | ca931e460460ffe46735f98b31db47220772d566 (diff) | |
download | samba-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.xml | 23 | ||||
-rw-r--r-- | source3/modules/gpfs.c | 46 | ||||
-rw-r--r-- | source3/modules/vfs_gpfs.c | 28 | ||||
-rw-r--r-- | source3/modules/vfs_gpfs.h | 1 |
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); |