mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 10:57:46 +00:00
s390/stp: add locking to sysfs functions
The sysfs function might race with stp_work_fn. To prevent that, add the required locking. Another issue is that the sysfs functions are checking the stp_online flag, but this flag just holds the user setting whether STP is enabled. Add a flag to clock_sync_flag whether stp_info holds valid data and use that instead. Cc: stable@vger.kernel.org Signed-off-by: Sven Schnelle <svens@linux.ibm.com> Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
This commit is contained in:
parent
fa6999e326
commit
b3bd02495c
1 changed files with 85 additions and 33 deletions
|
@ -299,8 +299,9 @@ static DEFINE_PER_CPU(atomic_t, clock_sync_word);
|
||||||
static DEFINE_MUTEX(clock_sync_mutex);
|
static DEFINE_MUTEX(clock_sync_mutex);
|
||||||
static unsigned long clock_sync_flags;
|
static unsigned long clock_sync_flags;
|
||||||
|
|
||||||
#define CLOCK_SYNC_HAS_STP 0
|
#define CLOCK_SYNC_HAS_STP 0
|
||||||
#define CLOCK_SYNC_STP 1
|
#define CLOCK_SYNC_STP 1
|
||||||
|
#define CLOCK_SYNC_STPINFO_VALID 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The get_clock function for the physical clock. It will get the current
|
* The get_clock function for the physical clock. It will get the current
|
||||||
|
@ -535,6 +536,22 @@ void stp_queue_work(void)
|
||||||
queue_work(time_sync_wq, &stp_work);
|
queue_work(time_sync_wq, &stp_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __store_stpinfo(void)
|
||||||
|
{
|
||||||
|
int rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi));
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
clear_bit(CLOCK_SYNC_STPINFO_VALID, &clock_sync_flags);
|
||||||
|
else
|
||||||
|
set_bit(CLOCK_SYNC_STPINFO_VALID, &clock_sync_flags);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stpinfo_valid(void)
|
||||||
|
{
|
||||||
|
return stp_online && test_bit(CLOCK_SYNC_STPINFO_VALID, &clock_sync_flags);
|
||||||
|
}
|
||||||
|
|
||||||
static int stp_sync_clock(void *data)
|
static int stp_sync_clock(void *data)
|
||||||
{
|
{
|
||||||
struct clock_sync_data *sync = data;
|
struct clock_sync_data *sync = data;
|
||||||
|
@ -557,8 +574,7 @@ static int stp_sync_clock(void *data)
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
sync->clock_delta = clock_delta;
|
sync->clock_delta = clock_delta;
|
||||||
clock_sync_global(clock_delta);
|
clock_sync_global(clock_delta);
|
||||||
rc = chsc_sstpi(stp_page, &stp_info,
|
rc = __store_stpinfo();
|
||||||
sizeof(struct stp_sstpi));
|
|
||||||
if (rc == 0 && stp_info.tmd != 2)
|
if (rc == 0 && stp_info.tmd != 2)
|
||||||
rc = -EAGAIN;
|
rc = -EAGAIN;
|
||||||
}
|
}
|
||||||
|
@ -604,7 +620,7 @@ static void stp_work_fn(struct work_struct *work)
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi));
|
rc = __store_stpinfo();
|
||||||
if (rc || stp_info.c == 0)
|
if (rc || stp_info.c == 0)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
|
@ -641,10 +657,14 @@ static ssize_t ctn_id_show(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
if (!stp_online)
|
ssize_t ret = -ENODATA;
|
||||||
return -ENODATA;
|
|
||||||
return sprintf(buf, "%016llx\n",
|
mutex_lock(&stp_work_mutex);
|
||||||
*(unsigned long long *) stp_info.ctnid);
|
if (stpinfo_valid())
|
||||||
|
ret = sprintf(buf, "%016llx\n",
|
||||||
|
*(unsigned long long *) stp_info.ctnid);
|
||||||
|
mutex_unlock(&stp_work_mutex);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR_RO(ctn_id);
|
static DEVICE_ATTR_RO(ctn_id);
|
||||||
|
@ -653,9 +673,13 @@ static ssize_t ctn_type_show(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
if (!stp_online)
|
ssize_t ret = -ENODATA;
|
||||||
return -ENODATA;
|
|
||||||
return sprintf(buf, "%i\n", stp_info.ctn);
|
mutex_lock(&stp_work_mutex);
|
||||||
|
if (stpinfo_valid())
|
||||||
|
ret = sprintf(buf, "%i\n", stp_info.ctn);
|
||||||
|
mutex_unlock(&stp_work_mutex);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR_RO(ctn_type);
|
static DEVICE_ATTR_RO(ctn_type);
|
||||||
|
@ -664,9 +688,13 @@ static ssize_t dst_offset_show(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
if (!stp_online || !(stp_info.vbits & 0x2000))
|
ssize_t ret = -ENODATA;
|
||||||
return -ENODATA;
|
|
||||||
return sprintf(buf, "%i\n", (int)(s16) stp_info.dsto);
|
mutex_lock(&stp_work_mutex);
|
||||||
|
if (stpinfo_valid() && (stp_info.vbits & 0x2000))
|
||||||
|
ret = sprintf(buf, "%i\n", (int)(s16) stp_info.dsto);
|
||||||
|
mutex_unlock(&stp_work_mutex);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR_RO(dst_offset);
|
static DEVICE_ATTR_RO(dst_offset);
|
||||||
|
@ -675,9 +703,13 @@ static ssize_t leap_seconds_show(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
if (!stp_online || !(stp_info.vbits & 0x8000))
|
ssize_t ret = -ENODATA;
|
||||||
return -ENODATA;
|
|
||||||
return sprintf(buf, "%i\n", (int)(s16) stp_info.leaps);
|
mutex_lock(&stp_work_mutex);
|
||||||
|
if (stpinfo_valid() && (stp_info.vbits & 0x8000))
|
||||||
|
ret = sprintf(buf, "%i\n", (int)(s16) stp_info.leaps);
|
||||||
|
mutex_unlock(&stp_work_mutex);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR_RO(leap_seconds);
|
static DEVICE_ATTR_RO(leap_seconds);
|
||||||
|
@ -686,9 +718,13 @@ static ssize_t stratum_show(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
if (!stp_online)
|
ssize_t ret = -ENODATA;
|
||||||
return -ENODATA;
|
|
||||||
return sprintf(buf, "%i\n", (int)(s16) stp_info.stratum);
|
mutex_lock(&stp_work_mutex);
|
||||||
|
if (stpinfo_valid())
|
||||||
|
ret = sprintf(buf, "%i\n", (int)(s16) stp_info.stratum);
|
||||||
|
mutex_unlock(&stp_work_mutex);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR_RO(stratum);
|
static DEVICE_ATTR_RO(stratum);
|
||||||
|
@ -697,9 +733,13 @@ static ssize_t time_offset_show(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
if (!stp_online || !(stp_info.vbits & 0x0800))
|
ssize_t ret = -ENODATA;
|
||||||
return -ENODATA;
|
|
||||||
return sprintf(buf, "%i\n", (int) stp_info.tto);
|
mutex_lock(&stp_work_mutex);
|
||||||
|
if (stpinfo_valid() && (stp_info.vbits & 0x0800))
|
||||||
|
ret = sprintf(buf, "%i\n", (int) stp_info.tto);
|
||||||
|
mutex_unlock(&stp_work_mutex);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR_RO(time_offset);
|
static DEVICE_ATTR_RO(time_offset);
|
||||||
|
@ -708,9 +748,13 @@ static ssize_t time_zone_offset_show(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
if (!stp_online || !(stp_info.vbits & 0x4000))
|
ssize_t ret = -ENODATA;
|
||||||
return -ENODATA;
|
|
||||||
return sprintf(buf, "%i\n", (int)(s16) stp_info.tzo);
|
mutex_lock(&stp_work_mutex);
|
||||||
|
if (stpinfo_valid() && (stp_info.vbits & 0x4000))
|
||||||
|
ret = sprintf(buf, "%i\n", (int)(s16) stp_info.tzo);
|
||||||
|
mutex_unlock(&stp_work_mutex);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR_RO(time_zone_offset);
|
static DEVICE_ATTR_RO(time_zone_offset);
|
||||||
|
@ -719,9 +763,13 @@ static ssize_t timing_mode_show(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
if (!stp_online)
|
ssize_t ret = -ENODATA;
|
||||||
return -ENODATA;
|
|
||||||
return sprintf(buf, "%i\n", stp_info.tmd);
|
mutex_lock(&stp_work_mutex);
|
||||||
|
if (stpinfo_valid())
|
||||||
|
ret = sprintf(buf, "%i\n", stp_info.tmd);
|
||||||
|
mutex_unlock(&stp_work_mutex);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR_RO(timing_mode);
|
static DEVICE_ATTR_RO(timing_mode);
|
||||||
|
@ -730,9 +778,13 @@ static ssize_t timing_state_show(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
if (!stp_online)
|
ssize_t ret = -ENODATA;
|
||||||
return -ENODATA;
|
|
||||||
return sprintf(buf, "%i\n", stp_info.tst);
|
mutex_lock(&stp_work_mutex);
|
||||||
|
if (stpinfo_valid())
|
||||||
|
ret = sprintf(buf, "%i\n", stp_info.tst);
|
||||||
|
mutex_unlock(&stp_work_mutex);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR_RO(timing_state);
|
static DEVICE_ATTR_RO(timing_state);
|
||||||
|
|
Loading…
Reference in a new issue