1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-24 13:57:43 +03:00

vfs_gpfs: add gpfs:clamp_invalid_times

The timestamp validation added as part of the fix for bug 15151 causes hard
failures for certain clients that seem to use a temporary timestamp initially
when creating files, changing in a later step.

Clamp invalid timestamps to the allowed range 0..UINT32_MAX if
"gpfs:clamp_invalid_times = yes" is set.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15151

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Christof Schmitt <cs@samba.org>

Autobuild-User(master): Christof Schmitt <cs@samba.org>
Autobuild-Date(master): Wed Feb  5 23:42:15 UTC 2025 on atb-devel-224
This commit is contained in:
Ralph Boehme 2025-01-22 12:34:31 +01:00 committed by Christof Schmitt
parent 9bf92bd9fe
commit 0a48167044
2 changed files with 60 additions and 12 deletions

View File

@ -316,6 +316,35 @@
</varlistentry>
<varlistentry>
<term>gpfs:clamp_invalid_times = [ yes | no ]</term>
<listitem>
<para>
GPFS stores timestamps using 32-bit unsigned integers for the
seconds component. When using gpfs:settimes = yes, this module
validates times that clients attempt to set are within the
supported GPFS range between 0 and UINT32_MAX. If a timestamp is
outside of this range, the client request is rejected. To cope
with clients setting eg temporary timestamps outside the valid
range, this parameter can be used to clamp the client timestamp
to the allowed range. Times before Thu Jan 1 12:00:00 AM UTC
1970 (the UNIX epock) are then set to Thu Jan 1 12:00:00 AM UTC
1970, times after Sun Feb 7 06:28:15 AM UTC 2106 will be set to
Sun Feb 7 06:28:15 AM UTC 2106.
</para>
<itemizedlist>
<listitem><para>
<command>no(default)</command> - Fail request with invalid time.
</para></listitem>
<listitem><para>
<command>yes</command> - clamp invalid times to 0 or UINT32_MAX.
</para></listitem>
</itemizedlist>
</listitem>
</varlistentry>
<varlistentry>
<term>gpfs:syncio = [yes|no]</term>
<listitem>

View File

@ -55,6 +55,7 @@ struct gpfs_config_data {
bool acl;
bool settimes;
bool recalls;
bool clamp_invalid_times;
struct {
bool gpfs_fstat_x;
} pathref_ok;
@ -1588,19 +1589,29 @@ static NTSTATUS vfs_gpfs_fset_dos_attributes(struct vfs_handle_struct *handle,
return NT_STATUS_OK;
}
static int timespec_to_gpfs_time(
struct timespec ts, gpfs_timestruc_t *gt, int idx, int *flags)
static int timespec_to_gpfs_time(struct gpfs_config_data *config,
struct timespec ts,
gpfs_timestruc_t *gt,
int idx,
int *flags)
{
if (is_omit_timespec(&ts)) {
return 0;
}
if (ts.tv_sec < 0 || ts.tv_sec > UINT32_MAX) {
DBG_NOTICE("GPFS uses 32-bit unsigned timestamps "
"and cannot handle %jd.\n",
(intmax_t)ts.tv_sec);
errno = ERANGE;
return -1;
if (!config->clamp_invalid_times) {
DBG_NOTICE("GPFS uses 32-bit unsigned timestamps "
"and cannot handle %jd.\n",
(intmax_t)ts.tv_sec);
errno = ERANGE;
return -1;
}
if (ts.tv_sec < 0) {
ts.tv_sec = 0;
} else {
ts.tv_sec = UINT32_MAX;
}
}
*flags |= 1 << idx;
@ -1611,7 +1622,8 @@ static int timespec_to_gpfs_time(
return 0;
}
static int smbd_gpfs_set_times(struct files_struct *fsp,
static int smbd_gpfs_set_times(struct gpfs_config_data *config,
struct files_struct *fsp,
struct smb_file_time *ft)
{
gpfs_timestruc_t gpfs_times[4];
@ -1619,18 +1631,22 @@ static int smbd_gpfs_set_times(struct files_struct *fsp,
int rc;
ZERO_ARRAY(gpfs_times);
rc = timespec_to_gpfs_time(ft->atime, gpfs_times, 0, &flags);
rc = timespec_to_gpfs_time(config, ft->atime, gpfs_times, 0, &flags);
if (rc != 0) {
return rc;
}
rc = timespec_to_gpfs_time(ft->mtime, gpfs_times, 1, &flags);
rc = timespec_to_gpfs_time(config, ft->mtime, gpfs_times, 1, &flags);
if (rc != 0) {
return rc;
}
/* No good mapping from LastChangeTime to ctime, not storing */
rc = timespec_to_gpfs_time(ft->create_time, gpfs_times, 3, &flags);
rc = timespec_to_gpfs_time(config,
ft->create_time,
gpfs_times,
3,
&flags);
if (rc != 0) {
return rc;
}
@ -1696,7 +1712,7 @@ static int vfs_gpfs_fntimes(struct vfs_handle_struct *handle,
/* Try to use gpfs_set_times if it is enabled and available */
if (config->settimes) {
return smbd_gpfs_set_times(fsp, ft);
return smbd_gpfs_set_times(config, fsp, ft);
}
DBG_DEBUG("gpfs_set_times() not available or disabled, "
@ -2048,6 +2064,9 @@ static int vfs_gpfs_connect(struct vfs_handle_struct *handle,
config->recalls = lp_parm_bool(SNUM(handle->conn), "gpfs",
"recalls", true);
config->clamp_invalid_times = lp_parm_bool(SNUM(handle->conn), "gpfs",
"clamp_invalid_times", false);
ret = vfs_gpfs_check_pathref(config, handle->conn);
if (ret != 0) {
DBG_ERR("vfs_gpfs_check_pathref() on [%s] failed\n",