lkml.org 
[lkml]   [2020]   [Nov]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.9 285/391] s390/stp: add locking to sysfs functions
    Date
    From: Sven Schnelle <svens@linux.ibm.com>

    commit b3bd02495cb339124f13135d51940cf48d83e5cb upstream.

    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>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    arch/s390/kernel/time.c | 118 ++++++++++++++++++++++++++++++++++--------------
    1 file changed, 85 insertions(+), 33 deletions(-)

    --- a/arch/s390/kernel/time.c
    +++ b/arch/s390/kernel/time.c
    @@ -345,8 +345,9 @@ static DEFINE_PER_CPU(atomic_t, clock_sy
    static DEFINE_MUTEX(clock_sync_mutex);
    static unsigned long clock_sync_flags;

    -#define CLOCK_SYNC_HAS_STP 0
    -#define CLOCK_SYNC_STP 1
    +#define CLOCK_SYNC_HAS_STP 0
    +#define CLOCK_SYNC_STP 1
    +#define CLOCK_SYNC_STPINFO_VALID 2

    /*
    * The get_clock function for the physical clock. It will get the current
    @@ -583,6 +584,22 @@ void stp_queue_work(void)
    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)
    {
    struct clock_sync_data *sync = data;
    @@ -604,8 +621,7 @@ static int stp_sync_clock(void *data)
    if (rc == 0) {
    sync->clock_delta = clock_delta;
    clock_sync_global(clock_delta);
    - rc = chsc_sstpi(stp_page, &stp_info,
    - sizeof(struct stp_sstpi));
    + rc = __store_stpinfo();
    if (rc == 0 && stp_info.tmd != 2)
    rc = -EAGAIN;
    }
    @@ -650,7 +666,7 @@ static void stp_work_fn(struct work_stru
    if (rc)
    goto out_unlock;

    - rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi));
    + rc = __store_stpinfo();
    if (rc || stp_info.c == 0)
    goto out_unlock;

    @@ -687,10 +703,14 @@ static ssize_t ctn_id_show(struct device
    struct device_attribute *attr,
    char *buf)
    {
    - if (!stp_online)
    - return -ENODATA;
    - return sprintf(buf, "%016llx\n",
    - *(unsigned long long *) stp_info.ctnid);
    + ssize_t ret = -ENODATA;
    +
    + mutex_lock(&stp_work_mutex);
    + 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);
    @@ -699,9 +719,13 @@ static ssize_t ctn_type_show(struct devi
    struct device_attribute *attr,
    char *buf)
    {
    - if (!stp_online)
    - return -ENODATA;
    - return sprintf(buf, "%i\n", stp_info.ctn);
    + ssize_t ret = -ENODATA;
    +
    + 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);
    @@ -710,9 +734,13 @@ static ssize_t dst_offset_show(struct de
    struct device_attribute *attr,
    char *buf)
    {
    - if (!stp_online || !(stp_info.vbits & 0x2000))
    - return -ENODATA;
    - return sprintf(buf, "%i\n", (int)(s16) stp_info.dsto);
    + ssize_t ret = -ENODATA;
    +
    + 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);
    @@ -721,9 +749,13 @@ static ssize_t leap_seconds_show(struct
    struct device_attribute *attr,
    char *buf)
    {
    - if (!stp_online || !(stp_info.vbits & 0x8000))
    - return -ENODATA;
    - return sprintf(buf, "%i\n", (int)(s16) stp_info.leaps);
    + ssize_t ret = -ENODATA;
    +
    + 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);
    @@ -732,9 +764,13 @@ static ssize_t stratum_show(struct devic
    struct device_attribute *attr,
    char *buf)
    {
    - if (!stp_online)
    - return -ENODATA;
    - return sprintf(buf, "%i\n", (int)(s16) stp_info.stratum);
    + ssize_t ret = -ENODATA;
    +
    + 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);
    @@ -743,9 +779,13 @@ static ssize_t time_offset_show(struct d
    struct device_attribute *attr,
    char *buf)
    {
    - if (!stp_online || !(stp_info.vbits & 0x0800))
    - return -ENODATA;
    - return sprintf(buf, "%i\n", (int) stp_info.tto);
    + ssize_t ret = -ENODATA;
    +
    + 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);
    @@ -754,9 +794,13 @@ static ssize_t time_zone_offset_show(str
    struct device_attribute *attr,
    char *buf)
    {
    - if (!stp_online || !(stp_info.vbits & 0x4000))
    - return -ENODATA;
    - return sprintf(buf, "%i\n", (int)(s16) stp_info.tzo);
    + ssize_t ret = -ENODATA;
    +
    + 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);
    @@ -765,9 +809,13 @@ static ssize_t timing_mode_show(struct d
    struct device_attribute *attr,
    char *buf)
    {
    - if (!stp_online)
    - return -ENODATA;
    - return sprintf(buf, "%i\n", stp_info.tmd);
    + ssize_t ret = -ENODATA;
    +
    + 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);
    @@ -776,9 +824,13 @@ static ssize_t timing_state_show(struct
    struct device_attribute *attr,
    char *buf)
    {
    - if (!stp_online)
    - return -ENODATA;
    - return sprintf(buf, "%i\n", stp_info.tst);
    + ssize_t ret = -ENODATA;
    +
    + 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);

    \
     
     \ /
      Last update: 2020-11-03 22:51    [W:4.177 / U:0.032 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site