summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil-cisco@xs4all.nl>2021-04-27 10:38:33 +0200
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>2021-05-25 17:02:26 +0200
commitc3bf5129f33923c92bf3bddaf4359b7b25ecb4ba (patch)
tree96755503c48c5bf7e0044215131dcbcd365f2b85
parent2fb27551ba4053ae503ce6c3b7b5d87cd206b1fd (diff)
media: v4l2-ctrls: always copy the controls on completion
When v4l2_ctrl_request_complete() is called and there is no control handler object found in the request, then create such an object so that all controls at completion state can be stored and are available to userspace. Otherwise any attempt by userspace to read the completed request data will fail. If allocating the control handler object failed, then indicate that by returning ENOMEM when attempting to get the controls from the completed request instead of returning ENOENT. Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c36
1 files changed, 32 insertions, 4 deletions
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index d4e2c7318ee6..09992e76bad6 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -4121,8 +4121,19 @@ v4l2_ctrls_find_req_obj(struct v4l2_ctrl_handler *hdl,
obj = media_request_object_find(req, &req_ops, hdl);
if (obj)
return obj;
+ /*
+ * If there are no controls in this completed request,
+ * then that can only happen if:
+ *
+ * 1) no controls were present in the queued request, and
+ * 2) v4l2_ctrl_request_complete() could not allocate a
+ * control handler object to store the completed state in.
+ *
+ * So return ENOMEM to indicate that there was an out-of-memory
+ * error.
+ */
if (!set)
- return ERR_PTR(-ENOENT);
+ return ERR_PTR(-ENOMEM);
new_hdl = kzalloc(sizeof(*new_hdl), GFP_KERNEL);
if (!new_hdl)
@@ -4133,8 +4144,8 @@ v4l2_ctrls_find_req_obj(struct v4l2_ctrl_handler *hdl,
if (!ret)
ret = v4l2_ctrl_request_bind(req, new_hdl, hdl);
if (ret) {
+ v4l2_ctrl_handler_free(new_hdl);
kfree(new_hdl);
-
return ERR_PTR(ret);
}
@@ -4728,8 +4739,25 @@ void v4l2_ctrl_request_complete(struct media_request *req,
* wants to leave the controls unchanged.
*/
obj = media_request_object_find(req, &req_ops, main_hdl);
- if (!obj)
- return;
+ if (!obj) {
+ int ret;
+
+ /* Create a new request so the driver can return controls */
+ hdl = kzalloc(sizeof(*hdl), GFP_KERNEL);
+ if (!hdl)
+ return;
+
+ ret = v4l2_ctrl_handler_init(hdl, (main_hdl->nr_of_buckets - 1) * 8);
+ if (!ret)
+ ret = v4l2_ctrl_request_bind(req, hdl, main_hdl);
+ if (ret) {
+ v4l2_ctrl_handler_free(hdl);
+ kfree(hdl);
+ return;
+ }
+ hdl->request_is_queued = true;
+ obj = media_request_object_find(req, &req_ops, main_hdl);
+ }
hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
list_for_each_entry(ref, &hdl->ctrl_refs, node) {