Skip to content

Commit 00ce756

Browse files
committed
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 <[email protected]>
1 parent 22ae19c commit 00ce756

File tree

1 file changed

+40
-38
lines changed

1 file changed

+40
-38
lines changed

drivers/input/misc/uinput.c

+40-38
Original file line numberDiff line numberDiff line change
@@ -56,24 +56,25 @@ static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned i
5656
}
5757

5858
/* 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)
6061
{
6162
int id;
62-
int err = -1;
63+
bool reserved = false;
6364

6465
spin_lock(&udev->requests_lock);
6566

6667
for (id = 0; id < UINPUT_NUM_REQUESTS; id++) {
6768
if (!udev->requests[id]) {
6869
request->id = id;
6970
udev->requests[id] = request;
70-
err = 0;
71+
reserved = true;
7172
break;
7273
}
7374
}
7475

7576
spin_unlock(&udev->requests_lock);
76-
return err;
77+
return reserved;
7778
}
7879

7980
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
8586
return udev->requests[id];
8687
}
8788

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)
8991
{
9092
/* Allocate slot. If none are available right away, wait. */
9193
return wait_event_interruptible(udev->requests_waitq,
92-
!uinput_request_alloc_id(udev, request));
94+
uinput_request_alloc_id(udev, request));
9395
}
9496

9597
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
101103
complete(&request->done);
102104
}
103105

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)
105108
{
106109
int retval;
107110

108-
retval = uinput_request_reserve_slot(udev, request);
109-
if (retval)
110-
return retval;
111-
112111
retval = mutex_lock_interruptible(&udev->mutex);
113112
if (retval)
114113
return retval;
@@ -118,14 +117,38 @@ static int uinput_request_submit(struct uinput_device *udev, struct uinput_reque
118117
goto out;
119118
}
120119

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+
*/
122126
uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
123127

124128
out:
125129
mutex_unlock(&udev->mutex);
126130
return retval;
127131
}
128132

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+
129152
/*
130153
* Fail all ouitstanding requests so handlers don't wait for the userspace
131154
* to finish processing them.
@@ -167,7 +190,6 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff
167190
{
168191
struct uinput_device *udev = input_get_drvdata(dev);
169192
struct uinput_request request;
170-
int retval;
171193

172194
/*
173195
* 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
180202
effect->u.periodic.waveform == FF_CUSTOM)
181203
return -EINVAL;
182204

183-
request.id = -1;
184-
init_completion(&request.done);
185205
request.code = UI_FF_UPLOAD;
186206
request.u.upload.effect = effect;
187207
request.u.upload.old = old;
188208

189-
retval = uinput_request_submit(udev, &request);
190-
if (!retval) {
191-
wait_for_completion(&request.done);
192-
retval = request.retval;
193-
}
194-
195-
return retval;
209+
return uinput_request_submit(udev, &request);
196210
}
197211

198212
static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
199213
{
200214
struct uinput_device *udev = input_get_drvdata(dev);
201215
struct uinput_request request;
202-
int retval;
203216

204217
if (!test_bit(EV_FF, dev->evbit))
205218
return -ENOSYS;
206219

207-
request.id = -1;
208-
init_completion(&request.done);
209220
request.code = UI_FF_ERASE;
210221
request.u.effect_id = effect_id;
211222

212-
retval = uinput_request_submit(udev, &request);
213-
if (!retval) {
214-
wait_for_completion(&request.done);
215-
retval = request.retval;
216-
}
217-
218-
return retval;
223+
return uinput_request_submit(udev, &request);
219224
}
220225

221226
static void uinput_destroy_device(struct uinput_device *udev)
@@ -478,20 +483,17 @@ static ssize_t uinput_events_to_user(struct uinput_device *udev,
478483
{
479484
struct input_event event;
480485
size_t read = 0;
481-
int error = 0;
482486

483487
while (read + input_event_size() <= count &&
484488
uinput_fetch_next_event(udev, &event)) {
485489

486-
if (input_event_to_user(buffer + read, &event)) {
487-
error = -EFAULT;
488-
break;
489-
}
490+
if (input_event_to_user(buffer + read, &event))
491+
return -EFAULT;
490492

491493
read += input_event_size();
492494
}
493495

494-
return read ?: error;
496+
return read;
495497
}
496498

497499
static ssize_t uinput_read(struct file *file, char __user *buffer,

0 commit comments

Comments
 (0)