All of lore.kernel.org
 help / color / mirror / Atom feed
From: Baolin Wang <baolin.wang@linaro.org>
To: perex@perex.cz, tiwai@suse.com
Cc: lgirdwood@gmail.com, mingo@kernel.org, o-takashi@sakamocchi.jp,
	elfring@users.sourceforge.net, dan.carpenter@oracle.com,
	jeeja.kp@intel.com, vinod.koul@intel.com,
	dharageswari.r@intel.com, guneshwor.o.singh@intel.com,
	bhumirks@gmail.com, gudishax.kranthikumar@intel.com,
	naveen.m@intel.com, hardik.t.shah@intel.com,
	arvind.yadav.cs@gmail.com, fabf@skynet.be, arnd@arndb.de,
	broonie@kernel.org, deepa.kernel@gmail.com,
	baolin.wang@linaro.org, alsa-devel@alsa-project.org,
	linux-kernel@vger.kernel.org
Subject: [RFC PATCH 2/7] sound: core: Avoid using timespec for struct snd_pcm_status
Date: Thu, 21 Sep 2017 14:18:04 +0800	[thread overview]
Message-ID: <78aa803db47d99c2bee1a4dc8d426621324785b8.1505973912.git.baolin.wang@linaro.org> (raw)
In-Reply-To: <cover.1505973912.git.baolin.wang@linaro.org>
In-Reply-To: <cover.1505973912.git.baolin.wang@linaro.org>

The struct snd_pcm_status will use 'timespec' type variables to record
timestamp, which is not year 2038 safe on 32bits system.

Userspace will use SNDRV_PCM_IOCTL_STATUS and SNDRV_PCM_IOCTL_STATUS_EXT
as commands to issue ioctl() to fill the 'snd_pcm_status' structure in
userspace. The command number is always defined through _IOR/_IOW/IORW,
so when userspace changes the definition of 'struct timespec' to use
64-bit types, the command number also changes.

Thus in the kernel, we now need to define two versions of each such ioctl
and corresponding ioctl commands to handle 32bit time_t and 64bit time_t
in native mode:
struct snd_pcm_status32 {
	......
	struct { s32 tv_sec; s32 tv_nsec; } trigger_tstamp;
	struct { s32 tv_sec; s32 tv_nsec; } tstamp;
	......
}

struct snd_pcm_status64 {
	......
	struct { s64 tv_sec; s64 tv_nsec; } trigger_tstamp;
	struct { s64 tv_sec; s64 tv_nsec; } tstamp;
	......
}

Moreover in compat file, we renamed or introduced new structures to handle
32bit/64bit time_t in compatible mode. 'struct compat_snd_pcm_status32' and
snd_pcm_status_user_compat() are used to handle 32bit time_t in compat mode.
'struct compat_snd_pcm_status64' and snd_pcm_status_user_compat64() are used
to handle 64bit time_t with 64bit alignment. 'struct compat_snd_pcm_status64_x86_32'
and snd_pcm_status_user_compat64_x86_32() are used to handle 64bit time_t with
32bit alignment.

Finally we can replace SNDRV_PCM_IOCTL_STATUS and SNDRV_PCM_IOCTL_STATUS_EXT
with new commands and introduce new functions to fill new 'struct snd_pcm_status64'
instead of using unsafe 'struct snd_pcm_status'. Then in future, the new
commands can be matched when userspace changes 'timespec' to 64bit type
to make a size change of 'struct snd_pcm_status'. When glibc changes time_t
to 64-bit, any recompiled program will issue ioctl commands that the kernel
does not understand without this patch.

Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
 include/sound/pcm.h     |   49 +++++++++-
 sound/core/pcm.c        |    8 +-
 sound/core/pcm_compat.c |  238 ++++++++++++++++++++++++++++++++++++-----------
 sound/core/pcm_native.c |  108 +++++++++++++++++----
 4 files changed, 324 insertions(+), 79 deletions(-)

diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index cd1ecd6..114cc29 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -58,6 +58,7 @@ struct snd_pcm_hardware {
 	size_t fifo_size;		/* fifo size in bytes */
 };
 
+struct snd_pcm_status64;
 struct snd_pcm_substream;
 
 struct snd_pcm_audio_tstamp_config; /* definitions further down */
@@ -565,8 +566,8 @@ struct snd_pcm_notify {
 int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info);
 int snd_pcm_info_user(struct snd_pcm_substream *substream,
 		      struct snd_pcm_info __user *info);
-int snd_pcm_status(struct snd_pcm_substream *substream,
-		   struct snd_pcm_status *status);
+int snd_pcm_status64(struct snd_pcm_substream *substream,
+		     struct snd_pcm_status64 *status);
 int snd_pcm_start(struct snd_pcm_substream *substream);
 int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t status);
 int snd_pcm_drain_done(struct snd_pcm_substream *substream);
@@ -1440,4 +1441,48 @@ static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format)
 #define pcm_dbg(pcm, fmt, args...) \
 	dev_dbg((pcm)->card->dev, fmt, ##args)
 
+struct snd_pcm_status64 {
+	snd_pcm_state_t state;		/* stream state */
+	struct { s64 tv_sec; s64 tv_nsec; } trigger_tstamp;	/* time when stream was started/stopped/paused */
+	struct { s64 tv_sec; s64 tv_nsec; } tstamp;		/* reference timestamp */
+	snd_pcm_uframes_t appl_ptr;	/* appl ptr */
+	snd_pcm_uframes_t hw_ptr;	/* hw ptr */
+	snd_pcm_sframes_t delay;	/* current delay in frames */
+	snd_pcm_uframes_t avail;	/* number of frames available */
+	snd_pcm_uframes_t avail_max;	/* max frames available on hw since last status */
+	snd_pcm_uframes_t overrange;	/* count of ADC (capture) overrange detections from last status */
+	snd_pcm_state_t suspended_state; /* suspended stream state */
+	__u32 audio_tstamp_data;	 /* needed for 64-bit alignment, used for configs/report to/from userspace */
+	struct { s64 tv_sec; s64 tv_nsec; } audio_tstamp;	/* sample counter, wall clock, PHC or on-demand sync'ed */
+	struct { s64 tv_sec; s64 tv_nsec; } driver_tstamp;	/* useful in case reference system tstamp is reported with delay */
+	__u32 audio_tstamp_accuracy;	/* in ns units, only valid if indicated in audio_tstamp_data */
+	unsigned char reserved[52-2*sizeof(struct { s64 tv_sec; s64 tv_nsec; })]; /* must be filled with zero */
+};
+
+#define SNDRV_PCM_IOCTL_STATUS64	_IOR('A', 0x20, struct snd_pcm_status64)
+#define SNDRV_PCM_IOCTL_STATUS_EXT64	_IOWR('A', 0x24, struct snd_pcm_status64)
+
+#if __BITS_PER_LONG == 32
+struct snd_pcm_status32 {
+	snd_pcm_state_t state;		/* stream state */
+	struct { s32 tv_sec; s32 tv_nsec; } trigger_tstamp;	/* time when stream was started/stopped/paused */
+	struct { s32 tv_sec; s32 tv_nsec; } tstamp;		/* reference timestamp */
+	snd_pcm_uframes_t appl_ptr;	/* appl ptr */
+	snd_pcm_uframes_t hw_ptr;	/* hw ptr */
+	snd_pcm_sframes_t delay;	/* current delay in frames */
+	snd_pcm_uframes_t avail;	/* number of frames available */
+	snd_pcm_uframes_t avail_max;	/* max frames available on hw since last status */
+	snd_pcm_uframes_t overrange;	/* count of ADC (capture) overrange detections from last status */
+	snd_pcm_state_t suspended_state; /* suspended stream state */
+	__u32 audio_tstamp_data;	 /* needed for 64-bit alignment, used for configs/report to/from userspace */
+	struct { s32 tv_sec; s32 tv_nsec; } audio_tstamp;	/* sample counter, wall clock, PHC or on-demand sync'ed */
+	struct { s32 tv_sec; s32 tv_nsec; } driver_tstamp;	/* useful in case reference system tstamp is reported with delay */
+	__u32 audio_tstamp_accuracy;	/* in ns units, only valid if indicated in audio_tstamp_data */
+	unsigned char reserved[52-2*sizeof(struct { s32 tv_sec; s32 tv_nsec; })]; /* must be filled with zero */
+};
+
+#define SNDRV_PCM_IOCTL_STATUS32	_IOR('A', 0x20, struct snd_pcm_status32)
+#define SNDRV_PCM_IOCTL_STATUS_EXT32	_IOWR('A', 0x24, struct snd_pcm_status32)
+#endif
+
 #endif /* __SOUND_PCM_H */
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 7eadb7f..2d990d9 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -453,7 +453,7 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
 {
 	struct snd_pcm_substream *substream = entry->private_data;
 	struct snd_pcm_runtime *runtime;
-	struct snd_pcm_status status;
+	struct snd_pcm_status64 status;
 	int err;
 
 	mutex_lock(&substream->pcm->open_mutex);
@@ -463,16 +463,16 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
 		goto unlock;
 	}
 	memset(&status, 0, sizeof(status));
-	err = snd_pcm_status(substream, &status);
+	err = snd_pcm_status64(substream, &status);
 	if (err < 0) {
 		snd_iprintf(buffer, "error %d\n", err);
 		goto unlock;
 	}
 	snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
 	snd_iprintf(buffer, "owner_pid   : %d\n", pid_vnr(substream->pid));
-	snd_iprintf(buffer, "trigger_time: %ld.%09ld\n",
+	snd_iprintf(buffer, "trigger_time: %lld.%09lld\n",
 		status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec);
-	snd_iprintf(buffer, "tstamp      : %ld.%09ld\n",
+	snd_iprintf(buffer, "tstamp      : %lld.%09lld\n",
 		status.tstamp.tv_sec, status.tstamp.tv_nsec);
 	snd_iprintf(buffer, "delay       : %ld\n", status.delay);
 	snd_iprintf(buffer, "avail       : %ld\n", status.avail);
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index b719d0b..79e7475 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -187,7 +187,7 @@ static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream,
 	snd_pcm_channel_info_user(s, p)
 #endif /* CONFIG_X86_X32 */
 
-struct snd_pcm_status32 {
+struct compat_snd_pcm_status32 {
 	s32 state;
 	struct compat_timespec trigger_tstamp;
 	struct compat_timespec tstamp;
@@ -207,13 +207,15 @@ struct snd_pcm_status32 {
 
 
 static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
-				      struct snd_pcm_status32 __user *src,
+				      struct compat_snd_pcm_status32 __user *src,
 				      bool ext)
 {
-	struct snd_pcm_status status;
+	struct snd_pcm_status64 status;
+	struct compat_snd_pcm_status32 compat_status32;
 	int err;
 
 	memset(&status, 0, sizeof(status));
+	memset(&compat_status32, 0, sizeof(compat_status32));
 	/*
 	 * with extension, parameters are read/write,
 	 * get audio_tstamp_data from user,
@@ -222,38 +224,53 @@ static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
 	if (ext && get_user(status.audio_tstamp_data,
 				(u32 __user *)(&src->audio_tstamp_data)))
 		return -EFAULT;
-	err = snd_pcm_status(substream, &status);
+	err = snd_pcm_status64(substream, &status);
 	if (err < 0)
 		return err;
 
 	if (clear_user(src, sizeof(*src)))
 		return -EFAULT;
-	if (put_user(status.state, &src->state) ||
-	    compat_put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) ||
-	    compat_put_timespec(&status.tstamp, &src->tstamp) ||
-	    put_user(status.appl_ptr, &src->appl_ptr) ||
-	    put_user(status.hw_ptr, &src->hw_ptr) ||
-	    put_user(status.delay, &src->delay) ||
-	    put_user(status.avail, &src->avail) ||
-	    put_user(status.avail_max, &src->avail_max) ||
-	    put_user(status.overrange, &src->overrange) ||
-	    put_user(status.suspended_state, &src->suspended_state) ||
-	    put_user(status.audio_tstamp_data, &src->audio_tstamp_data) ||
-	    compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp) ||
-	    compat_put_timespec(&status.driver_tstamp, &src->driver_tstamp) ||
-	    put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy))
+
+	compat_status32 = (struct compat_snd_pcm_status32) {
+		.state = status.state,
+		.trigger_tstamp = {
+			.tv_sec = status.trigger_tstamp.tv_sec,
+			.tv_nsec = status.trigger_tstamp.tv_nsec,
+		},
+		.tstamp = {
+			.tv_sec = status.tstamp.tv_sec,
+			.tv_nsec = status.tstamp.tv_nsec,
+		},
+		.appl_ptr = status.appl_ptr,
+		.hw_ptr = status.hw_ptr,
+		.delay = status.delay,
+		.avail = status.avail,
+		.avail_max = status.avail_max,
+		.overrange = status.overrange,
+		.suspended_state = status.suspended_state,
+		.audio_tstamp_data = status.audio_tstamp_data,
+		.audio_tstamp = {
+			.tv_sec = status.audio_tstamp.tv_sec,
+			.tv_nsec = status.audio_tstamp.tv_nsec,
+		},
+		.driver_tstamp = {
+			.tv_sec = status.audio_tstamp.tv_sec,
+			.tv_nsec = status.audio_tstamp.tv_nsec,
+		},
+		.audio_tstamp_accuracy = status.audio_tstamp_accuracy,
+	};
+
+	if (copy_to_user(src, &compat_status32, sizeof(compat_status32)))
 		return -EFAULT;
 
 	return err;
 }
 
-#ifdef CONFIG_X86_X32
-/* X32 ABI has 64bit timespec and 64bit alignment */
-struct snd_pcm_status_x32 {
+struct compat_snd_pcm_status64 {
 	s32 state;
 	u32 rsvd; /* alignment */
-	struct timespec trigger_tstamp;
-	struct timespec tstamp;
+	struct { s64 tv_sec; s64 tv_nsec; } trigger_tstamp;
+	struct { s64 tv_sec; s64 tv_nsec; } tstamp;
 	u32 appl_ptr;
 	u32 hw_ptr;
 	s32 delay;
@@ -262,22 +279,24 @@ struct snd_pcm_status_x32 {
 	u32 overrange;
 	s32 suspended_state;
 	u32 audio_tstamp_data;
-	struct timespec audio_tstamp;
-	struct timespec driver_tstamp;
+	struct { s64 tv_sec; s64 tv_nsec; } audio_tstamp;
+	struct { s64 tv_sec; s64 tv_nsec; } driver_tstamp;
 	u32 audio_tstamp_accuracy;
-	unsigned char reserved[52-2*sizeof(struct timespec)];
+	unsigned char reserved[52-2*sizeof(struct { s64 tv_sec; s64 tv_nsec; })];
 } __packed;
 
 #define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst))
 
-static int snd_pcm_status_user_x32(struct snd_pcm_substream *substream,
-				   struct snd_pcm_status_x32 __user *src,
-				   bool ext)
+static int snd_pcm_status_user_compat64(struct snd_pcm_substream *substream,
+					struct compat_snd_pcm_status64 __user *src,
+					bool ext)
 {
-	struct snd_pcm_status status;
+	struct snd_pcm_status64 status;
+	struct compat_snd_pcm_status64 compat_status64;
 	int err;
 
 	memset(&status, 0, sizeof(status));
+	memset(&compat_status64, 0, sizeof(compat_status64));
 	/*
 	 * with extension, parameters are read/write,
 	 * get audio_tstamp_data from user,
@@ -286,31 +305,128 @@ static int snd_pcm_status_user_x32(struct snd_pcm_substream *substream,
 	if (ext && get_user(status.audio_tstamp_data,
 				(u32 __user *)(&src->audio_tstamp_data)))
 		return -EFAULT;
-	err = snd_pcm_status(substream, &status);
+	err = snd_pcm_status64(substream, &status);
 	if (err < 0)
 		return err;
 
 	if (clear_user(src, sizeof(*src)))
 		return -EFAULT;
-	if (put_user(status.state, &src->state) ||
-	    put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) ||
-	    put_timespec(&status.tstamp, &src->tstamp) ||
-	    put_user(status.appl_ptr, &src->appl_ptr) ||
-	    put_user(status.hw_ptr, &src->hw_ptr) ||
-	    put_user(status.delay, &src->delay) ||
-	    put_user(status.avail, &src->avail) ||
-	    put_user(status.avail_max, &src->avail_max) ||
-	    put_user(status.overrange, &src->overrange) ||
-	    put_user(status.suspended_state, &src->suspended_state) ||
-	    put_user(status.audio_tstamp_data, &src->audio_tstamp_data) ||
-	    put_timespec(&status.audio_tstamp, &src->audio_tstamp) ||
-	    put_timespec(&status.driver_tstamp, &src->driver_tstamp) ||
-	    put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy))
+
+	compat_status64 = (struct compat_snd_pcm_status64) {
+		.state = status.state,
+		.trigger_tstamp = {
+			.tv_sec = status.trigger_tstamp.tv_sec,
+			.tv_nsec = status.trigger_tstamp.tv_nsec,
+		},
+		.tstamp = {
+			.tv_sec = status.tstamp.tv_sec,
+			.tv_nsec = status.tstamp.tv_nsec,
+		},
+		.appl_ptr = status.appl_ptr,
+		.hw_ptr = status.hw_ptr,
+		.delay = status.delay,
+		.avail = status.avail,
+		.avail_max = status.avail_max,
+		.overrange = status.overrange,
+		.suspended_state = status.suspended_state,
+		.audio_tstamp_data = status.audio_tstamp_data,
+		.audio_tstamp = {
+			.tv_sec = status.audio_tstamp.tv_sec,
+			.tv_nsec = status.audio_tstamp.tv_nsec,
+		},
+		.driver_tstamp = {
+			.tv_sec = status.audio_tstamp.tv_sec,
+			.tv_nsec = status.audio_tstamp.tv_nsec,
+		},
+		.audio_tstamp_accuracy = status.audio_tstamp_accuracy,
+	};
+
+	if (copy_to_user(src, &compat_status64, sizeof(compat_status64)))
 		return -EFAULT;
 
 	return err;
 }
-#endif /* CONFIG_X86_X32 */
+
+#ifdef IA32_EMULATION
+struct compat_snd_pcm_status64_x86_32 {
+	s32 state;
+	struct { s64 tv_sec; s64 tv_nsec; } trigger_tstamp;
+	struct { s64 tv_sec; s64 tv_nsec; } tstamp;
+	u32 appl_ptr;
+	u32 hw_ptr;
+	s32 delay;
+	u32 avail;
+	u32 avail_max;
+	u32 overrange;
+	s32 suspended_state;
+	u32 audio_tstamp_data;
+	struct { s64 tv_sec; s64 tv_nsec; } audio_tstamp;
+	struct { s64 tv_sec; s64 tv_nsec; } driver_tstamp;
+	u32 audio_tstamp_accuracy;
+	unsigned char reserved[52-2*sizeof(struct { s64 tv_sec; s64 tv_nsec; })];
+} __packed;
+
+static int
+snd_pcm_status_user_compat64_x86_32(struct snd_pcm_substream *substream,
+				    struct compat_snd_pcm_status64_x86_32 __user *src,
+				    bool ext)
+{
+	struct snd_pcm_status64 status;
+	struct compat_snd_pcm_status64_x86_32 status_x86_32;
+	int err;
+
+	memset(&status, 0, sizeof(status));
+	memset(&status_x86_32, 0, sizeof(status_x86_32));
+	/*
+	 * with extension, parameters are read/write,
+	 * get audio_tstamp_data from user,
+	 * ignore rest of status structure
+	 */
+	if (ext && get_user(status.audio_tstamp_data,
+				(u32 __user *)(&src->audio_tstamp_data)))
+		return -EFAULT;
+	err = snd_pcm_status64(substream, &status);
+	if (err < 0)
+		return err;
+
+	if (clear_user(src, sizeof(*src)))
+		return -EFAULT;
+
+	status_x86_32 = (struct compat_snd_pcm_status64_x86_32) {
+		.state = status.state,
+		.trigger_tstamp = {
+			.tv_sec = status.trigger_tstamp.tv_sec,
+			.tv_nsec = status.trigger_tstamp.tv_nsec,
+		},
+		.tstamp = {
+			.tv_sec = status.tstamp.tv_sec,
+			.tv_nsec = status.tstamp.tv_nsec,
+		},
+		.appl_ptr = status.appl_ptr,
+		.hw_ptr = status.hw_ptr,
+		.delay = status.delay,
+		.avail = status.avail,
+		.avail_max = status.avail_max,
+		.overrange = status.overrange,
+		.suspended_state = status.suspended_state,
+		.audio_tstamp_data = status.audio_tstamp_data,
+		.audio_tstamp = {
+			.tv_sec = status.audio_tstamp.tv_sec,
+			.tv_nsec = status.audio_tstamp.tv_nsec,
+		},
+		.driver_tstamp = {
+			.tv_sec = status.audio_tstamp.tv_sec,
+			.tv_nsec = status.audio_tstamp.tv_nsec,
+		},
+		.audio_tstamp_accuracy = status.audio_tstamp_accuracy,
+	};
+
+	if (copy_to_user(src, &status_x86_32, sizeof(status_x86_32)))
+		return -EFAULT;
+
+	return err;
+}
+#endif
 
 /* both for HW_PARAMS and HW_REFINE */
 static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
@@ -633,8 +749,8 @@ enum {
 	SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct snd_pcm_hw_params32),
 	SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32),
 	SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32),
-	SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct snd_pcm_status32),
-	SNDRV_PCM_IOCTL_STATUS_EXT32 = _IOWR('A', 0x24, struct snd_pcm_status32),
+	SNDRV_PCM_IOCTL_STATUS_COMPAT32 = _IOR('A', 0x20, struct compat_snd_pcm_status32),
+	SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32 = _IOWR('A', 0x24, struct compat_snd_pcm_status32),
 	SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
 	SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32),
 	SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
@@ -644,10 +760,14 @@ enum {
 	SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct snd_xfern32),
 	SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct snd_xfern32),
 	SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr32),
+	SNDRV_PCM_IOCTL_STATUS_COMPAT64 = _IOR('A', 0x20, struct compat_snd_pcm_status64),
+	SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64 = _IOWR('A', 0x24, struct compat_snd_pcm_status64),
+#ifdef IA32_EMULATION
+	SNDRV_PCM_IOCTL_STATUS_COMPAT64_X86_32 = _IOR('A', 0x20, struct compat_snd_pcm_status64_x86_32),
+	SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64_X86_32 = _IOWR('A', 0x24, struct compat_snd_pcm_status64_x86_32),
+#endif
 #ifdef CONFIG_X86_X32
 	SNDRV_PCM_IOCTL_CHANNEL_INFO_X32 = _IOR('A', 0x32, struct snd_pcm_channel_info),
-	SNDRV_PCM_IOCTL_STATUS_X32 = _IOR('A', 0x20, struct snd_pcm_status_x32),
-	SNDRV_PCM_IOCTL_STATUS_EXT_X32 = _IOWR('A', 0x24, struct snd_pcm_status_x32),
 	SNDRV_PCM_IOCTL_SYNC_PTR_X32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr_x32),
 #endif /* CONFIG_X86_X32 */
 };
@@ -697,9 +817,9 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
 		return snd_pcm_ioctl_hw_params_compat(substream, 0, argp);
 	case SNDRV_PCM_IOCTL_SW_PARAMS32:
 		return snd_pcm_ioctl_sw_params_compat(substream, argp);
-	case SNDRV_PCM_IOCTL_STATUS32:
+	case SNDRV_PCM_IOCTL_STATUS_COMPAT32:
 		return snd_pcm_status_user_compat(substream, argp, false);
-	case SNDRV_PCM_IOCTL_STATUS_EXT32:
+	case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32:
 		return snd_pcm_status_user_compat(substream, argp, true);
 	case SNDRV_PCM_IOCTL_SYNC_PTR32:
 		return snd_pcm_ioctl_sync_ptr_compat(substream, argp);
@@ -719,11 +839,17 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
 		return snd_pcm_ioctl_rewind_compat(substream, argp);
 	case SNDRV_PCM_IOCTL_FORWARD32:
 		return snd_pcm_ioctl_forward_compat(substream, argp);
+	case SNDRV_PCM_IOCTL_STATUS_COMPAT64:
+		return snd_pcm_status_user_compat64(substream, argp, false);
+	case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64:
+		return snd_pcm_status_user_compat64(substream, argp, true);
+#ifdef IA32_EMULATION
+	case SNDRV_PCM_IOCTL_STATUS_COMPAT64_X86_32:
+		return snd_pcm_status_user_compat64_x86_32(substream, argp, false);
+	case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64_X86_32:
+		return snd_pcm_status_user_compat64_x86_32(substream, argp, true);
+#endif
 #ifdef CONFIG_X86_X32
-	case SNDRV_PCM_IOCTL_STATUS_X32:
-		return snd_pcm_status_user_x32(substream, argp, false);
-	case SNDRV_PCM_IOCTL_STATUS_EXT_X32:
-		return snd_pcm_status_user_x32(substream, argp, true);
 	case SNDRV_PCM_IOCTL_SYNC_PTR_X32:
 		return snd_pcm_ioctl_sync_ptr_x32(substream, argp);
 	case SNDRV_PCM_IOCTL_CHANNEL_INFO_X32:
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 60bc303..7f1f60d 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -854,8 +854,8 @@ static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream,
 	return err;
 }
 
-int snd_pcm_status(struct snd_pcm_substream *substream,
-		   struct snd_pcm_status *status)
+int snd_pcm_status64(struct snd_pcm_substream *substream,
+		     struct snd_pcm_status64 *status)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
@@ -881,14 +881,22 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
 	status->suspended_state = runtime->status->suspended_state;
 	if (status->state == SNDRV_PCM_STATE_OPEN)
 		goto _end;
-	status->trigger_tstamp = timespec64_to_timespec(runtime->trigger_tstamp);
+	status->trigger_tstamp.tv_sec = runtime->trigger_tstamp.tv_sec;
+	status->trigger_tstamp.tv_nsec = runtime->trigger_tstamp.tv_nsec;
 	if (snd_pcm_running(substream)) {
 		snd_pcm_update_hw_ptr(substream);
 		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
-			status->tstamp = runtime->status->tstamp;
-			status->driver_tstamp = timespec64_to_timespec(runtime->driver_tstamp);
-			status->audio_tstamp =
-				runtime->status->audio_tstamp;
+			status->tstamp.tv_sec = runtime->status->tstamp.tv_sec;
+			status->tstamp.tv_nsec =
+				runtime->status->tstamp.tv_nsec;
+			status->driver_tstamp.tv_sec =
+				runtime->driver_tstamp.tv_sec;
+			status->driver_tstamp.tv_nsec =
+				runtime->driver_tstamp.tv_nsec;
+			status->audio_tstamp.tv_sec =
+				runtime->status->audio_tstamp.tv_sec;
+			status->audio_tstamp.tv_nsec =
+				runtime->status->audio_tstamp.tv_nsec;
 			if (runtime->audio_tstamp_report.valid == 1)
 				/* backwards compatibility, no report provided in COMPAT mode */
 				snd_pcm_pack_audio_tstamp_report(&status->audio_tstamp_data,
@@ -903,7 +911,8 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
 			struct timespec64 tstamp;
 
 			snd_pcm_gettime(runtime, &tstamp);
-			status->tstamp = timespec64_to_timespec(tstamp);
+			status->tstamp.tv_sec = tstamp.tv_sec;
+			status->tstamp.tv_nsec = tstamp.tv_nsec;
 		}
 	}
  _tstamp_end:
@@ -933,11 +942,11 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static int snd_pcm_status_user(struct snd_pcm_substream *substream,
-			       struct snd_pcm_status __user * _status,
-			       bool ext)
+static int snd_pcm_status_user64(struct snd_pcm_substream *substream,
+				 struct snd_pcm_status64 __user * _status,
+				 bool ext)
 {
-	struct snd_pcm_status status;
+	struct snd_pcm_status64 status;
 	int res;
 
 	memset(&status, 0, sizeof(status));
@@ -949,7 +958,7 @@ static int snd_pcm_status_user(struct snd_pcm_substream *substream,
 	if (ext && get_user(status.audio_tstamp_data,
 				(u32 __user *)(&_status->audio_tstamp_data)))
 		return -EFAULT;
-	res = snd_pcm_status(substream, &status);
+	res = snd_pcm_status64(substream, &status);
 	if (res < 0)
 		return res;
 	if (copy_to_user(_status, &status, sizeof(status)))
@@ -957,6 +966,65 @@ static int snd_pcm_status_user(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+#if __BITS_PER_LONG == 32
+static int snd_pcm_status_user32(struct snd_pcm_substream *substream,
+				 struct snd_pcm_status32 __user * _status,
+				 bool ext)
+{
+	struct snd_pcm_status64 status64;
+	struct snd_pcm_status32 status32;
+	int res;
+
+	memset(&status64, 0, sizeof(status64));
+	memset(&status32, 0, sizeof(status32));
+	/*
+	 * with extension, parameters are read/write,
+	 * get audio_tstamp_data from user,
+	 * ignore rest of status structure
+	 */
+	if (ext && get_user(status64.audio_tstamp_data,
+			    (u32 __user *)(&_status->audio_tstamp_data)))
+		return -EFAULT;
+	res = snd_pcm_status64(substream, &status64);
+	if (res < 0)
+		return res;
+
+	status32 = (struct snd_pcm_status32) {
+		.state = status64.state,
+		.trigger_tstamp = {
+			.tv_sec = status64.trigger_tstamp.tv_sec,
+			.tv_nsec = status64.trigger_tstamp.tv_nsec,
+		},
+		.tstamp = {
+			.tv_sec = status64.tstamp.tv_sec,
+			.tv_nsec = status64.tstamp.tv_nsec,
+		},
+		.appl_ptr = status64.appl_ptr,
+		.hw_ptr = status64.hw_ptr,
+		.delay = status64.delay,
+		.avail = status64.avail,
+		.avail_max = status64.avail_max,
+		.overrange = status64.overrange,
+		.suspended_state = status64.suspended_state,
+		.audio_tstamp_data = status64.audio_tstamp_data,
+		.audio_tstamp = {
+			.tv_sec = status64.audio_tstamp.tv_sec,
+			.tv_nsec = status64.audio_tstamp.tv_nsec,
+		},
+		.driver_tstamp = {
+			.tv_sec = status64.audio_tstamp.tv_sec,
+			.tv_nsec = status64.audio_tstamp.tv_nsec,
+		},
+		.audio_tstamp_accuracy = status64.audio_tstamp_accuracy,
+	};
+
+	if (copy_to_user(_status, &status32, sizeof(status32)))
+		return -EFAULT;
+
+	return 0;
+}
+#endif
+
 static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
 				struct snd_pcm_channel_info * info)
 {
@@ -2888,10 +2956,16 @@ static int snd_pcm_common_ioctl(struct file *file,
 		return snd_pcm_hw_free(substream);
 	case SNDRV_PCM_IOCTL_SW_PARAMS:
 		return snd_pcm_sw_params_user(substream, arg);
-	case SNDRV_PCM_IOCTL_STATUS:
-		return snd_pcm_status_user(substream, arg, false);
-	case SNDRV_PCM_IOCTL_STATUS_EXT:
-		return snd_pcm_status_user(substream, arg, true);
+#if __BITS_PER_LONG == 32
+	case SNDRV_PCM_IOCTL_STATUS32:
+		return snd_pcm_status_user32(substream, arg, false);
+	case SNDRV_PCM_IOCTL_STATUS_EXT32:
+		return snd_pcm_status_user32(substream, arg, true);
+#endif
+	case SNDRV_PCM_IOCTL_STATUS64:
+		return snd_pcm_status_user64(substream, arg, false);
+	case SNDRV_PCM_IOCTL_STATUS_EXT64:
+		return snd_pcm_status_user64(substream, arg, true);
 	case SNDRV_PCM_IOCTL_CHANNEL_INFO:
 		return snd_pcm_channel_info_user(substream, arg);
 	case SNDRV_PCM_IOCTL_PREPARE:
-- 
1.7.9.5

  parent reply	other threads:[~2017-09-21  6:18 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-09-21  6:18 [RFC PATCH 0/7] Fix year 2038 issue for sound subsystem Baolin Wang
2017-09-21  6:18 ` [RFC PATCH 1/7] sound: Replace timespec with timespec64 Baolin Wang
2017-09-21 10:02   ` Arnd Bergmann
2017-09-21  6:18 ` Baolin Wang [this message]
2017-09-22  9:31   ` [RFC PATCH 2/7] sound: core: Avoid using timespec for struct snd_pcm_status Takashi Iwai
2017-09-22  9:31     ` Takashi Iwai
2017-09-22 10:14     ` Arnd Bergmann
2017-09-22 10:49       ` Takashi Iwai
2017-09-22 11:43         ` Arnd Bergmann
2017-09-22 12:19           ` Takashi Iwai
2017-09-21  6:18 ` [RFC PATCH 3/7] sound: core: Avoid using timespec for struct snd_pcm_sync_ptr Baolin Wang
2017-09-21 12:50   ` Arnd Bergmann
2017-09-21 12:50     ` Arnd Bergmann
2017-09-22  6:47     ` Baolin Wang
2017-09-22  8:48       ` Arnd Bergmann
2017-09-26 22:24         ` Baolin Wang
2017-09-26 22:24           ` Baolin Wang
2017-09-21  6:18 ` [RFC PATCH 4/7] sound: core: Avoid using timespec for struct snd_rawmidi_status Baolin Wang
2017-09-21 12:56   ` Arnd Bergmann
2017-09-21 12:56     ` Arnd Bergmann
2017-09-22  1:54     ` Baolin Wang
2017-09-21  6:18 ` [RFC PATCH 5/7] sound: core: Avoid using timespec for struct snd_timer_status Baolin Wang
2017-09-21 13:14   ` Arnd Bergmann
2017-09-22  2:03     ` Baolin Wang
2017-09-22  2:03       ` Baolin Wang
2017-09-21  6:18 ` [RFC PATCH 6/7] uapi: sound: Avoid using timespec for struct snd_ctl_elem_value Baolin Wang
2017-09-21 12:58   ` Arnd Bergmann
2017-09-26 21:54     ` Baolin Wang
2017-09-21  6:18 ` [RFC PATCH 7/7] sound: core: Avoid using timespec for struct snd_timer_tread Baolin Wang
2017-09-21 13:09   ` Arnd Bergmann
2017-09-22  3:00     ` Baolin Wang
2017-09-22  7:57       ` Arnd Bergmann
2017-09-22  7:57         ` Arnd Bergmann
2017-09-22  8:38         ` Baolin Wang
2017-09-22  8:38           ` Baolin Wang
2017-09-22  4:07 ` [RFC PATCH 0/7] Fix year 2038 issue for sound subsystem Takashi Sakamoto
2017-09-22  5:30   ` Baolin Wang
2017-09-22  9:15   ` Mark Brown
2017-09-22  9:15     ` Mark Brown
2017-09-22  9:17     ` Takashi Iwai
2017-09-22  9:17       ` Takashi Iwai

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=78aa803db47d99c2bee1a4dc8d426621324785b8.1505973912.git.baolin.wang@linaro.org \
    --to=baolin.wang@linaro.org \
    --cc=alsa-devel@alsa-project.org \
    --cc=arnd@arndb.de \
    --cc=arvind.yadav.cs@gmail.com \
    --cc=bhumirks@gmail.com \
    --cc=broonie@kernel.org \
    --cc=dan.carpenter@oracle.com \
    --cc=deepa.kernel@gmail.com \
    --cc=dharageswari.r@intel.com \
    --cc=elfring@users.sourceforge.net \
    --cc=fabf@skynet.be \
    --cc=gudishax.kranthikumar@intel.com \
    --cc=guneshwor.o.singh@intel.com \
    --cc=hardik.t.shah@intel.com \
    --cc=jeeja.kp@intel.com \
    --cc=lgirdwood@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@kernel.org \
    --cc=naveen.m@intel.com \
    --cc=o-takashi@sakamocchi.jp \
    --cc=perex@perex.cz \
    --cc=tiwai@suse.com \
    --cc=vinod.koul@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.