Commit b3bd0249 authored by Sven Schnelle's avatar Sven Schnelle Committed by Vasily Gorbik

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: default avatarSven Schnelle <svens@linux.ibm.com>
Reviewed-by: default avatarAlexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent fa6999e3
...@@ -299,8 +299,9 @@ static DEFINE_PER_CPU(atomic_t, clock_sync_word); ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment