From patchwork Thu Sep 17 21:19:39 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 7210671 Return-Path: X-Original-To: patchwork-linux-media@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id DE381BEEC1 for ; Thu, 17 Sep 2015 21:21:20 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 8E6EF20690 for ; Thu, 17 Sep 2015 21:21:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 073772062B for ; Thu, 17 Sep 2015 21:21:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752546AbbIQVU7 (ORCPT ); Thu, 17 Sep 2015 17:20:59 -0400 Received: from mout.kundenserver.de ([212.227.17.13]:54777 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752237AbbIQVU2 (ORCPT ); Thu, 17 Sep 2015 17:20:28 -0400 Received: from wuerfel.lan. ([149.172.15.242]) by mrelayeu.kundenserver.de (mreue102) with ESMTPSA (Nemesis) id 0MZDZc-1ZK2l21gi4-00Kycr; Thu, 17 Sep 2015 23:20:16 +0200 From: Arnd Bergmann To: linux-media@vger.kernel.org Cc: linux-kernel@vger.kernel.org, y2038@lists.linaro.org, Mauro Carvalho Chehab , linux-api@vger.kernel.org, linux-samsung-soc@vger.kernel.org, Hans Verkuil , Arnd Bergmann Subject: [PATCH v2 8/9] [media] handle 64-bit time_t in v4l2_buffer Date: Thu, 17 Sep 2015 23:19:39 +0200 Message-Id: <1442524780-781677-9-git-send-email-arnd@arndb.de> X-Mailer: git-send-email 2.1.0.rc2 In-Reply-To: <1442524780-781677-1-git-send-email-arnd@arndb.de> References: <1442524780-781677-1-git-send-email-arnd@arndb.de> X-Provags-ID: V03:K0:bzKUjoPMhoSdILnmwiXNG3JBHzfzn5zds26gEOWlltY8q5UHxRw n8udEC8xfyH5JFf7Da34tlwt/Yh+FblFNavj1qf3zxdaiWlzAUIqRMmd+J0jrZLXDA70Uv4 jWesbxWbwbmdq43ENEnRssaxCEMwTn3omoBFYC5fsX/gCjGIJ8zkYFIbEjHGz7ewkbrUFo+ E0tbR1KMdmXocU8M+kUpQ== X-UI-Out-Filterresults: notjunk:1; V01:K0:UGvT/iJazzY=:92sZ0RxYI91GuY7AY5DL6r VA+isW0IWCX0evq3sN9wpVPZ9vKg1UQmOMmiZ1tKFOQ+vDgTDMOVR7K2yGMLQIC1prQpMRNcN /ddJwAAma5cHMq4uNF6k6QOmann4LPvjftSaD+WzQ+WsVD+kypWCY0Vc0YTXJtzS9KiilBYgk qQE/RnNfQh8P0BaP1LV21r9CHf1ntq4aOLttcZOsNUD5B5zJP3yO0b+y1TggoRLCZ1HSZIDGy qv8UpWchJ/mNm4n5LxwyNEEmMfcjYwEQ8w8dVOAPluOjBFqt+R67RYrNS8bM31mqtmYVbbIfo HJWAHyek+kHcZ63MulS6pq5vAfL2KFsw3gf4+2n8kexuOI1OLtD9UKDcqa5J84rHp4W1UCJHP XHWB3Q+dT7UoxuLEuxk18YgKjcl0n9tmenqWTGKZjIfSPO1dNouA0Tm/K4mkEcoF85n4BOplu QniLkeYdTBvoi+vXmZ/BZhEhPlhXgL5l0/1C8uQGAmww47QLpWGinxW4efw5wqe2iTAKaKzOl Ydal0WbC2HG4PKOQH1JcjGGk6IK54ebJ23rNZg6aWubUSsrxk1A6a3kuwKRLZ3eqG9BYSxuIM 0KNqOWa1dspvUeu7AbyoAo1mHQMe98QtHeGw+OY351byK2xvZapSgV73IwjyT6zhxaG/k3nXq RIWEnhPkXf8sgTEtoiLsvIQktLSfjEpZTSqEO13LE0zfxEFYxOXKvWCyKAdJg6EylwRI= Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This is the final change to enable user space with 64-bit time_t in the core v4l2 code. Four ioctls are affected here: VIDIOC_QUERYBUF, VIDIOC_QBUF, VIDIOC_DQBUF, and VIDIOC_PREPARE_BUF. All of them pass a struct v4l2_buffer, which can either contain a 32-bit time_t or a 64-bit time on 32-bit architectures. In this patch, we redefine the in-kernel version of this structure to use the 64-bit __s64 type through the use of v4l2_timeval. This means the normal ioctl handling now assumes 64-bit time_t and so we have to add support for 32-bit time_t in new handlers. This is somewhat similar to the 32-bit compat handling on 64-bit architectures, but those also have to modify other fields of the structure. For now, I leave that compat code alone, as it handles the normal case (32-bit compat_time_t) correctly, this has to be done as a follow-up. Signed-off-by: Arnd Bergmann --- drivers/media/v4l2-core/v4l2-ioctl.c | 174 +++++++++++++++++++++++++++++++++-- include/uapi/linux/videodev2.h | 34 ++++++- 2 files changed, 199 insertions(+), 9 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 7aab18dd2ca5..137475c28e8f 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -438,15 +438,14 @@ static void v4l_print_buffer(const void *arg, bool write_only) const struct v4l2_timecode *tc = &p->timecode; const struct v4l2_plane *plane; int i; + /* y2038 safe because of monotonic time */ + unsigned int seconds = p->timestamp.tv_sec; - pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, " + pr_cont("%02d:%02d:%02d.%08ld index=%d, type=%s, " "flags=0x%08x, field=%s, sequence=%d, memory=%s", - p->timestamp.tv_sec / 3600, - (int)(p->timestamp.tv_sec / 60) % 60, - (int)(p->timestamp.tv_sec % 60), - (long)p->timestamp.tv_usec, - p->index, - prt_names(p->type, v4l2_type_names), + seconds / 3600, (seconds / 60) % 60, + seconds % 60, (long)p->timestamp.tv_usec, + p->index, prt_names(p->type, v4l2_type_names), p->flags, prt_names(p->field, v4l2_field_names), p->sequence, prt_names(p->memory, v4l2_memory_names)); @@ -1846,6 +1845,123 @@ static int v4l_prepare_buf(const struct v4l2_ioctl_ops *ops, return ret ? ret : ops->vidioc_prepare_buf(file, fh, b); } +#ifndef CONFIG_64BIT +static void v4l_get_buffer_time32(struct v4l2_buffer *to, + const struct v4l2_buffer_time32 *from) +{ + to->index = from->index; + to->type = from->type; + to->bytesused = from->bytesused; + to->flags = from->flags; + to->field = from->field; + to->timestamp.tv_sec = from->timestamp.tv_sec; + to->timestamp.tv_usec = from->timestamp.tv_usec; + to->timecode = from->timecode; + to->sequence = from->sequence; + to->memory = from->memory; + to->m.offset = from->m.offset; + to->length = from->length; + to->reserved2 = from->reserved2; + to->reserved = from->reserved; +} + +static void v4l_put_buffer_time32(struct v4l2_buffer_time32 *to, + const struct v4l2_buffer *from) +{ + to->index = from->index; + to->type = from->type; + to->bytesused = from->bytesused; + to->flags = from->flags; + to->field = from->field; + to->timestamp.tv_sec = from->timestamp.tv_sec; + to->timestamp.tv_usec = from->timestamp.tv_usec; + to->timecode = from->timecode; + to->sequence = from->sequence; + to->memory = from->memory; + to->m.offset = from->m.offset; + to->length = from->length; + to->reserved2 = from->reserved2; + to->reserved = from->reserved; +} + +static int v4l_querybuf_time32(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_buffer buffer; + int ret; + + v4l_get_buffer_time32(&buffer, arg); + ret = v4l_querybuf(ops, file, fh, &buffer); + v4l_put_buffer_time32(arg, &buffer); + + return ret; +} + +static int v4l_qbuf_time32(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_buffer buffer; + int ret; + + v4l_get_buffer_time32(&buffer, arg); + ret = v4l_qbuf(ops, file, fh, &buffer); + v4l_put_buffer_time32(arg, &buffer); + + return ret; +} + +static int v4l_dqbuf_time32(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_buffer buffer; + int ret; + + v4l_get_buffer_time32(&buffer, arg); + ret = v4l_dqbuf(ops, file, fh, &buffer); + v4l_put_buffer_time32(arg, &buffer); + + return ret; +} + +static int v4l_prepare_buf_time32(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct v4l2_buffer buffer; + int ret; + + v4l_get_buffer_time32(&buffer, arg); + ret = v4l_prepare_buf(ops, file, fh, &buffer); + + return ret; +} + +static void v4l_print_buffer_time32(const void *arg, bool write_only) +{ + struct v4l2_buffer buffer; + + v4l_get_buffer_time32(&buffer, arg); + v4l_print_buffer(&buffer, write_only); +} + +#ifdef CONFIG_TRACEPOINTS +static void trace_v4l2_dqbuf_time32(int minor, const struct v4l2_buffer_time32 *arg) +{ + struct v4l2_buffer buffer; + + v4l_get_buffer_time32(&buffer, arg); + trace_v4l2_dqbuf(minor, &buffer); +} + +static void trace_v4l2_qbuf_time32(int minor, const struct v4l2_buffer_time32 *arg) +{ + struct v4l2_buffer buffer; + + v4l_get_buffer_time32(&buffer, arg); + trace_v4l2_qbuf(minor, &buffer); +} +#endif +#endif + static int v4l_g_parm(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -2408,12 +2524,21 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_FNC(VIDIOC_S_FMT, v4l_s_fmt, v4l_print_format, INFO_FL_PRIO), IOCTL_INFO_FNC(VIDIOC_REQBUFS, v4l_reqbufs, v4l_print_requestbuffers, INFO_FL_PRIO | INFO_FL_QUEUE), IOCTL_INFO_FNC(VIDIOC_QUERYBUF, v4l_querybuf, v4l_print_buffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_buffer, length)), +#ifndef CONFIG_64BIT + IOCTL_INFO_FNC(VIDIOC_QUERYBUF_TIME32, v4l_querybuf_time32, v4l_print_buffer_time32, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_buffer, length)), +#endif IOCTL_INFO_STD(VIDIOC_G_FBUF, vidioc_g_fbuf, v4l_print_framebuffer, 0), IOCTL_INFO_STD(VIDIOC_S_FBUF, vidioc_s_fbuf, v4l_print_framebuffer, INFO_FL_PRIO), IOCTL_INFO_FNC(VIDIOC_OVERLAY, v4l_overlay, v4l_print_u32, INFO_FL_PRIO), IOCTL_INFO_FNC(VIDIOC_QBUF, v4l_qbuf, v4l_print_buffer, INFO_FL_QUEUE), +#ifndef CONFIG_64BIT + IOCTL_INFO_FNC(VIDIOC_QBUF_TIME32, v4l_qbuf_time32, v4l_print_buffer_time32, INFO_FL_QUEUE), +#endif IOCTL_INFO_STD(VIDIOC_EXPBUF, vidioc_expbuf, v4l_print_exportbuffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_exportbuffer, flags)), IOCTL_INFO_FNC(VIDIOC_DQBUF, v4l_dqbuf, v4l_print_buffer, INFO_FL_QUEUE), +#ifndef CONFIG_64BIT + IOCTL_INFO_FNC(VIDIOC_DQBUF_TIME32, v4l_dqbuf_time32, v4l_print_buffer_time32, INFO_FL_QUEUE), +#endif IOCTL_INFO_FNC(VIDIOC_STREAMON, v4l_streamon, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE), IOCTL_INFO_FNC(VIDIOC_STREAMOFF, v4l_streamoff, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE), IOCTL_INFO_FNC(VIDIOC_G_PARM, v4l_g_parm, v4l_print_streamparm, INFO_FL_CLEAR(v4l2_streamparm, type)), @@ -2479,6 +2604,9 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_FNC(VIDIOC_UNSUBSCRIBE_EVENT, v4l_unsubscribe_event, v4l_print_event_subscription, 0), IOCTL_INFO_FNC(VIDIOC_CREATE_BUFS, v4l_create_bufs, v4l_print_create_buffers, INFO_FL_PRIO | INFO_FL_QUEUE), IOCTL_INFO_FNC(VIDIOC_PREPARE_BUF, v4l_prepare_buf, v4l_print_buffer, INFO_FL_QUEUE), +#ifndef CONFIG_64BIT + IOCTL_INFO_FNC(VIDIOC_PREPARE_BUF_TIME32, v4l_prepare_buf_time32, v4l_print_buffer_time32, INFO_FL_QUEUE), +#endif IOCTL_INFO_STD(VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings, v4l_print_enum_dv_timings, 0), IOCTL_INFO_STD(VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings, v4l_print_dv_timings, 0), IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, type)), @@ -2608,6 +2736,12 @@ done: (cmd == VIDIOC_QBUF || cmd == VIDIOC_DQBUF)) return ret; +#ifndef CONFIG_64BIT + if (!(dev_debug & V4L2_DEV_DEBUG_STREAMING) && + (cmd == VIDIOC_QBUF_TIME32 || cmd == VIDIOC_DQBUF_TIME32)) + return ret; +#endif + v4l_printk_ioctl(video_device_node_name(vfd), cmd); if (ret < 0) pr_cont(": error %ld", ret); @@ -2630,6 +2764,26 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, int ret = 0; switch (cmd) { +#ifndef CONFIG_64BIT + case VIDIOC_PREPARE_BUF_TIME32: + case VIDIOC_QUERYBUF_TIME32: + case VIDIOC_QBUF_TIME32: + case VIDIOC_DQBUF_TIME32: { + struct v4l2_buffer_time32 *buf = parg; + + if (V4L2_TYPE_IS_MULTIPLANAR(buf->type) && buf->length > 0) { + if (buf->length > VIDEO_MAX_PLANES) { + ret = -EINVAL; + break; + } + *user_ptr = (void __user *)buf->m.planes; + *kernel_ptr = (void **)&buf->m.planes; + *array_size = sizeof(struct v4l2_plane) * buf->length; + ret = 1; + } + break; + } +#endif case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: @@ -2774,6 +2928,12 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, trace_v4l2_dqbuf(video_devdata(file)->minor, parg); else if (cmd == VIDIOC_QBUF) trace_v4l2_qbuf(video_devdata(file)->minor, parg); +#ifndef CONFIG_64BIT + else if (cmd == VIDIOC_DQBUF_TIME32) + trace_v4l2_dqbuf_time32(video_devdata(file)->minor, parg); + else if (cmd == VIDIOC_QBUF_TIME32) + trace_v4l2_qbuf_time32(video_devdata(file)->minor, parg); +#endif } if (has_array_args) { diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 450b3249ba30..0d3688a97ab8 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -811,8 +811,8 @@ struct v4l2_plane { * time_t, so we have to convert it when accessing user data. */ struct v4l2_timeval { - long tv_sec; - long tv_usec; + __s64 tv_sec; + __s64 tv_usec; }; #endif @@ -873,6 +873,32 @@ struct v4l2_buffer { __u32 reserved; }; +struct v4l2_buffer_time32 { + __u32 index; + __u32 type; + __u32 bytesused; + __u32 flags; + __u32 field; + struct { + __s32 tv_sec; + __s32 tv_usec; + } timestamp; + struct v4l2_timecode timecode; + __u32 sequence; + + /* memory location */ + __u32 memory; + union { + __u32 offset; + unsigned long userptr; + struct v4l2_plane *planes; + __s32 fd; + } m; + __u32 length; + __u32 reserved2; + __u32 reserved; +}; + /* Flags for 'flags' field */ /* Buffer is mapped (flag) */ #define V4L2_BUF_FLAG_MAPPED 0x00000001 @@ -2216,12 +2242,15 @@ struct v4l2_create_buffers { #define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format) #define VIDIOC_REQBUFS _IOWR('V', 8, struct v4l2_requestbuffers) #define VIDIOC_QUERYBUF _IOWR('V', 9, struct v4l2_buffer) +#define VIDIOC_QUERYBUF_TIME32 _IOWR('V', 9, struct v4l2_buffer_time32) #define VIDIOC_G_FBUF _IOR('V', 10, struct v4l2_framebuffer) #define VIDIOC_S_FBUF _IOW('V', 11, struct v4l2_framebuffer) #define VIDIOC_OVERLAY _IOW('V', 14, int) #define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer) +#define VIDIOC_QBUF_TIME32 _IOWR('V', 15, struct v4l2_buffer_time32) #define VIDIOC_EXPBUF _IOWR('V', 16, struct v4l2_exportbuffer) #define VIDIOC_DQBUF _IOWR('V', 17, struct v4l2_buffer) +#define VIDIOC_DQBUF_TIME32 _IOWR('V', 17, struct v4l2_buffer_time32) #define VIDIOC_STREAMON _IOW('V', 18, int) #define VIDIOC_STREAMOFF _IOW('V', 19, int) #define VIDIOC_G_PARM _IOWR('V', 21, struct v4l2_streamparm) @@ -2292,6 +2321,7 @@ struct v4l2_create_buffers { versions */ #define VIDIOC_CREATE_BUFS _IOWR('V', 92, struct v4l2_create_buffers) #define VIDIOC_PREPARE_BUF _IOWR('V', 93, struct v4l2_buffer) +#define VIDIOC_PREPARE_BUF_TIME32 _IOWR('V', 93, struct v4l2_buffer_time32) /* Experimental selection API */ #define VIDIOC_G_SELECTION _IOWR('V', 94, struct v4l2_selection)