Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b7089ce authored by Sven Schnelle's avatar Sven Schnelle Committed by Greg Kroah-Hartman
Browse files

s390/stp: add locking to sysfs functions



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: 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>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 77d89366
Loading
Loading
Loading
Loading
+85 −33
Original line number Diff line number Diff line
@@ -356,6 +356,7 @@ static unsigned long clock_sync_flags;

#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
@@ -592,6 +593,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;
@@ -613,8 +630,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;
			}
@@ -659,7 +675,7 @@ static void stp_work_fn(struct work_struct *work)
	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;

@@ -696,10 +712,14 @@ static ssize_t stp_ctn_id_show(struct device *dev,
				struct device_attribute *attr,
				char *buf)
{
	if (!stp_online)
		return -ENODATA;
	return sprintf(buf, "%016llx\n",
	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(ctn_id, 0400, stp_ctn_id_show, NULL);
@@ -708,9 +728,13 @@ static ssize_t stp_ctn_type_show(struct device *dev,
				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(ctn_type, 0400, stp_ctn_type_show, NULL);
@@ -719,9 +743,13 @@ static ssize_t stp_dst_offset_show(struct device *dev,
				   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(dst_offset, 0400, stp_dst_offset_show, NULL);
@@ -730,9 +758,13 @@ static ssize_t stp_leap_seconds_show(struct device *dev,
					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(leap_seconds, 0400, stp_leap_seconds_show, NULL);
@@ -741,9 +773,13 @@ static ssize_t stp_stratum_show(struct device *dev,
				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(stratum, 0400, stp_stratum_show, NULL);
@@ -752,9 +788,13 @@ static ssize_t stp_time_offset_show(struct device *dev,
				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(time_offset, 0400, stp_time_offset_show, NULL);
@@ -763,9 +803,13 @@ static ssize_t stp_time_zone_offset_show(struct device *dev,
				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(time_zone_offset, 0400,
@@ -775,9 +819,13 @@ static ssize_t stp_timing_mode_show(struct device *dev,
				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(timing_mode, 0400, stp_timing_mode_show, NULL);
@@ -786,9 +834,13 @@ static ssize_t stp_timing_state_show(struct device *dev,
				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(timing_state, 0400, stp_timing_state_show, NULL);