diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-07-30 01:48:32 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-08-22 01:29:54 -0400 |
commit | 00ce756ce53acdb82d408346e6a7b734ca9e5bad (patch) | |
tree | 020ee9aba5b30c72fdf2e46ee0dcf210afa9427e /drivers/input | |
parent | 22ae19c6e3c22b390952e90f452f26adad9b8687 (diff) |
Input: uinput - mark failed submission requests as free
If uinput_request_submit() fails after new request ID was allocated
we need to mark that request ID as free, otherwise it will always
stay occupied and we may run out of available IDs.
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/misc/uinput.c | 78 |
1 files changed, 40 insertions, 38 deletions
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 1719554fe194..6099365102db 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c | |||
@@ -56,10 +56,11 @@ static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned i | |||
56 | } | 56 | } |
57 | 57 | ||
58 | /* Atomically allocate an ID for the given request. Returns 0 on success. */ | 58 | /* Atomically allocate an ID for the given request. Returns 0 on success. */ |
59 | static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request) | 59 | static bool uinput_request_alloc_id(struct uinput_device *udev, |
60 | struct uinput_request *request) | ||
60 | { | 61 | { |
61 | int id; | 62 | int id; |
62 | int err = -1; | 63 | bool reserved = false; |
63 | 64 | ||
64 | spin_lock(&udev->requests_lock); | 65 | spin_lock(&udev->requests_lock); |
65 | 66 | ||
@@ -67,13 +68,13 @@ static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_req | |||
67 | if (!udev->requests[id]) { | 68 | if (!udev->requests[id]) { |
68 | request->id = id; | 69 | request->id = id; |
69 | udev->requests[id] = request; | 70 | udev->requests[id] = request; |
70 | err = 0; | 71 | reserved = true; |
71 | break; | 72 | break; |
72 | } | 73 | } |
73 | } | 74 | } |
74 | 75 | ||
75 | spin_unlock(&udev->requests_lock); | 76 | spin_unlock(&udev->requests_lock); |
76 | return err; | 77 | return reserved; |
77 | } | 78 | } |
78 | 79 | ||
79 | static struct uinput_request *uinput_request_find(struct uinput_device *udev, int id) | 80 | static struct uinput_request *uinput_request_find(struct uinput_device *udev, int id) |
@@ -85,11 +86,12 @@ static struct uinput_request *uinput_request_find(struct uinput_device *udev, in | |||
85 | return udev->requests[id]; | 86 | return udev->requests[id]; |
86 | } | 87 | } |
87 | 88 | ||
88 | static inline int uinput_request_reserve_slot(struct uinput_device *udev, struct uinput_request *request) | 89 | static int uinput_request_reserve_slot(struct uinput_device *udev, |
90 | struct uinput_request *request) | ||
89 | { | 91 | { |
90 | /* Allocate slot. If none are available right away, wait. */ | 92 | /* Allocate slot. If none are available right away, wait. */ |
91 | return wait_event_interruptible(udev->requests_waitq, | 93 | return wait_event_interruptible(udev->requests_waitq, |
92 | !uinput_request_alloc_id(udev, request)); | 94 | uinput_request_alloc_id(udev, request)); |
93 | } | 95 | } |
94 | 96 | ||
95 | static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request) | 97 | static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request) |
@@ -101,14 +103,11 @@ static void uinput_request_done(struct uinput_device *udev, struct uinput_reques | |||
101 | complete(&request->done); | 103 | complete(&request->done); |
102 | } | 104 | } |
103 | 105 | ||
104 | static int uinput_request_submit(struct uinput_device *udev, struct uinput_request *request) | 106 | static int uinput_request_send(struct uinput_device *udev, |
107 | struct uinput_request *request) | ||
105 | { | 108 | { |
106 | int retval; | 109 | int retval; |
107 | 110 | ||
108 | retval = uinput_request_reserve_slot(udev, request); | ||
109 | if (retval) | ||
110 | return retval; | ||
111 | |||
112 | retval = mutex_lock_interruptible(&udev->mutex); | 111 | retval = mutex_lock_interruptible(&udev->mutex); |
113 | if (retval) | 112 | if (retval) |
114 | return retval; | 113 | return retval; |
@@ -118,7 +117,12 @@ static int uinput_request_submit(struct uinput_device *udev, struct uinput_reque | |||
118 | goto out; | 117 | goto out; |
119 | } | 118 | } |
120 | 119 | ||
121 | /* Tell our userspace app about this new request by queueing an input event */ | 120 | init_completion(&request->done); |
121 | |||
122 | /* | ||
123 | * Tell our userspace application about this new request | ||
124 | * by queueing an input event. | ||
125 | */ | ||
122 | uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id); | 126 | uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id); |
123 | 127 | ||
124 | out: | 128 | out: |
@@ -126,6 +130,25 @@ static int uinput_request_submit(struct uinput_device *udev, struct uinput_reque | |||
126 | return retval; | 130 | return retval; |
127 | } | 131 | } |
128 | 132 | ||
133 | static int uinput_request_submit(struct uinput_device *udev, | ||
134 | struct uinput_request *request) | ||
135 | { | ||
136 | int error; | ||
137 | |||
138 | error = uinput_request_reserve_slot(udev, request); | ||
139 | if (error) | ||
140 | return error; | ||
141 | |||
142 | error = uinput_request_send(udev, request); | ||
143 | if (error) { | ||
144 | uinput_request_done(udev, request); | ||
145 | return error; | ||
146 | } | ||
147 | |||
148 | wait_for_completion(&request->done); | ||
149 | return request->retval; | ||
150 | } | ||
151 | |||
129 | /* | 152 | /* |
130 | * Fail all ouitstanding requests so handlers don't wait for the userspace | 153 | * Fail all ouitstanding requests so handlers don't wait for the userspace |
131 | * to finish processing them. | 154 | * to finish processing them. |
@@ -167,7 +190,6 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff | |||
167 | { | 190 | { |
168 | struct uinput_device *udev = input_get_drvdata(dev); | 191 | struct uinput_device *udev = input_get_drvdata(dev); |
169 | struct uinput_request request; | 192 | struct uinput_request request; |
170 | int retval; | ||
171 | 193 | ||
172 | /* | 194 | /* |
173 | * uinput driver does not currently support periodic effects with | 195 | * uinput driver does not currently support periodic effects with |
@@ -180,42 +202,25 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff | |||
180 | effect->u.periodic.waveform == FF_CUSTOM) | 202 | effect->u.periodic.waveform == FF_CUSTOM) |
181 | return -EINVAL; | 203 | return -EINVAL; |
182 | 204 | ||
183 | request.id = -1; | ||
184 | init_completion(&request.done); | ||
185 | request.code = UI_FF_UPLOAD; | 205 | request.code = UI_FF_UPLOAD; |
186 | request.u.upload.effect = effect; | 206 | request.u.upload.effect = effect; |
187 | request.u.upload.old = old; | 207 | request.u.upload.old = old; |
188 | 208 | ||
189 | retval = uinput_request_submit(udev, &request); | 209 | return uinput_request_submit(udev, &request); |
190 | if (!retval) { | ||
191 | wait_for_completion(&request.done); | ||
192 | retval = request.retval; | ||
193 | } | ||
194 | |||
195 | return retval; | ||
196 | } | 210 | } |
197 | 211 | ||
198 | static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) | 212 | static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) |
199 | { | 213 | { |
200 | struct uinput_device *udev = input_get_drvdata(dev); | 214 | struct uinput_device *udev = input_get_drvdata(dev); |
201 | struct uinput_request request; | 215 | struct uinput_request request; |
202 | int retval; | ||
203 | 216 | ||
204 | if (!test_bit(EV_FF, dev->evbit)) | 217 | if (!test_bit(EV_FF, dev->evbit)) |
205 | return -ENOSYS; | 218 | return -ENOSYS; |
206 | 219 | ||
207 | request.id = -1; | ||
208 | init_completion(&request.done); | ||
209 | request.code = UI_FF_ERASE; | 220 | request.code = UI_FF_ERASE; |
210 | request.u.effect_id = effect_id; | 221 | request.u.effect_id = effect_id; |
211 | 222 | ||
212 | retval = uinput_request_submit(udev, &request); | 223 | return uinput_request_submit(udev, &request); |
213 | if (!retval) { | ||
214 | wait_for_completion(&request.done); | ||
215 | retval = request.retval; | ||
216 | } | ||
217 | |||
218 | return retval; | ||
219 | } | 224 | } |
220 | 225 | ||
221 | static void uinput_destroy_device(struct uinput_device *udev) | 226 | static void uinput_destroy_device(struct uinput_device *udev) |
@@ -478,20 +483,17 @@ static ssize_t uinput_events_to_user(struct uinput_device *udev, | |||
478 | { | 483 | { |
479 | struct input_event event; | 484 | struct input_event event; |
480 | size_t read = 0; | 485 | size_t read = 0; |
481 | int error = 0; | ||
482 | 486 | ||
483 | while (read + input_event_size() <= count && | 487 | while (read + input_event_size() <= count && |
484 | uinput_fetch_next_event(udev, &event)) { | 488 | uinput_fetch_next_event(udev, &event)) { |
485 | 489 | ||
486 | if (input_event_to_user(buffer + read, &event)) { | 490 | if (input_event_to_user(buffer + read, &event)) |
487 | error = -EFAULT; | 491 | return -EFAULT; |
488 | break; | ||
489 | } | ||
490 | 492 | ||
491 | read += input_event_size(); | 493 | read += input_event_size(); |
492 | } | 494 | } |
493 | 495 | ||
494 | return read ?: error; | 496 | return read; |
495 | } | 497 | } |
496 | 498 | ||
497 | static ssize_t uinput_read(struct file *file, char __user *buffer, | 499 | static ssize_t uinput_read(struct file *file, char __user *buffer, |