]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/3.18.127/media-v4l-event-add-subscription-to-list-before-calling-add-operation.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.18.127 / media-v4l-event-add-subscription-to-list-before-calling-add-operation.patch
CommitLineData
ff3d1419
GKH
1From 92539d3eda2c090b382699bbb896d4b54e9bdece Mon Sep 17 00:00:00 2001
2From: Sakari Ailus <sakari.ailus@linux.intel.com>
3Date: Mon, 5 Nov 2018 09:35:44 -0500
4Subject: media: v4l: event: Add subscription to list before calling "add" operation
5
6From: Sakari Ailus <sakari.ailus@linux.intel.com>
7
8commit 92539d3eda2c090b382699bbb896d4b54e9bdece upstream.
9
10Patch ad608fbcf166 changed how events were subscribed to address an issue
11elsewhere. As a side effect of that change, the "add" callback was called
12before the event subscription was added to the list of subscribed events,
13causing the first event queued by the add callback (and possibly other
14events arriving soon afterwards) to be lost.
15
16Fix this by adding the subscription to the list before calling the "add"
17callback, and clean up afterwards if that fails.
18
19Fixes: ad608fbcf166 ("media: v4l: event: Prevent freeing event subscriptions while accessed")
20
21Reported-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
22Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
23Tested-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
24Reviewed-by: Hans Verkuil <hans.verkuil@cisco.com>
25Tested-by: Hans Verkuil <hans.verkuil@cisco.com>
26Cc: stable@vger.kernel.org (for 4.14 and up)
27Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
28Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
29
30---
31 drivers/media/v4l2-core/v4l2-event.c | 43 +++++++++++++++++++----------------
32 1 file changed, 24 insertions(+), 19 deletions(-)
33
34--- a/drivers/media/v4l2-core/v4l2-event.c
35+++ b/drivers/media/v4l2-core/v4l2-event.c
36@@ -194,6 +194,22 @@ int v4l2_event_pending(struct v4l2_fh *f
37 }
38 EXPORT_SYMBOL_GPL(v4l2_event_pending);
39
40+static void __v4l2_event_unsubscribe(struct v4l2_subscribed_event *sev)
41+{
42+ struct v4l2_fh *fh = sev->fh;
43+ unsigned int i;
44+
45+ lockdep_assert_held(&fh->subscribe_lock);
46+ assert_spin_locked(&fh->vdev->fh_lock);
47+
48+ /* Remove any pending events for this subscription */
49+ for (i = 0; i < sev->in_use; i++) {
50+ list_del(&sev->events[sev_pos(sev, i)].list);
51+ fh->navailable--;
52+ }
53+ list_del(&sev->list);
54+}
55+
56 int v4l2_event_subscribe(struct v4l2_fh *fh,
57 const struct v4l2_event_subscription *sub, unsigned elems,
58 const struct v4l2_subscribed_event_ops *ops)
59@@ -225,27 +241,23 @@ int v4l2_event_subscribe(struct v4l2_fh
60
61 spin_lock_irqsave(&fh->vdev->fh_lock, flags);
62 found_ev = v4l2_event_subscribed(fh, sub->type, sub->id);
63+ if (!found_ev)
64+ list_add(&sev->list, &fh->subscribed);
65 spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
66
67 if (found_ev) {
68 /* Already listening */
69 kfree(sev);
70- goto out_unlock;
71- }
72-
73- if (sev->ops && sev->ops->add) {
74+ } else if (sev->ops && sev->ops->add) {
75 ret = sev->ops->add(sev, elems);
76 if (ret) {
77+ spin_lock_irqsave(&fh->vdev->fh_lock, flags);
78+ __v4l2_event_unsubscribe(sev);
79+ spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
80 kfree(sev);
81- goto out_unlock;
82 }
83 }
84
85- spin_lock_irqsave(&fh->vdev->fh_lock, flags);
86- list_add(&sev->list, &fh->subscribed);
87- spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
88-
89-out_unlock:
90 mutex_unlock(&fh->subscribe_lock);
91
92 return ret;
93@@ -280,7 +292,6 @@ int v4l2_event_unsubscribe(struct v4l2_f
94 {
95 struct v4l2_subscribed_event *sev;
96 unsigned long flags;
97- int i;
98
99 if (sub->type == V4L2_EVENT_ALL) {
100 v4l2_event_unsubscribe_all(fh);
101@@ -292,14 +303,8 @@ int v4l2_event_unsubscribe(struct v4l2_f
102 spin_lock_irqsave(&fh->vdev->fh_lock, flags);
103
104 sev = v4l2_event_subscribed(fh, sub->type, sub->id);
105- if (sev != NULL) {
106- /* Remove any pending events for this subscription */
107- for (i = 0; i < sev->in_use; i++) {
108- list_del(&sev->events[sev_pos(sev, i)].list);
109- fh->navailable--;
110- }
111- list_del(&sev->list);
112- }
113+ if (sev != NULL)
114+ __v4l2_event_unsubscribe(sev);
115
116 spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
117