summaryrefslogtreecommitdiff
path: root/drivers/media/v4l2-core/v4l2-ctrls.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/v4l2-core/v4l2-ctrls.c')
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index e7fcbaeec0ae..c7bcc5c25771 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -2650,7 +2650,15 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
if (hdl == NULL || hdl->buckets == NULL)
return;
- if (!hdl->req_obj.req && !list_empty(&hdl->requests)) {
+ /*
+ * If the main handler is freed and it is used by handler objects in
+ * outstanding requests, then unbind and put those objects before
+ * freeing the main handler.
+ *
+ * The main handler can be identified by having a NULL ops pointer in
+ * the request object.
+ */
+ if (!hdl->req_obj.ops && !list_empty(&hdl->requests)) {
struct v4l2_ctrl_handler *req, *next_req;
list_for_each_entry_safe(req, next_req, &hdl->requests, requests) {
@@ -3730,8 +3738,8 @@ static void v4l2_ctrl_request_unbind(struct media_request_object *obj)
container_of(obj, struct v4l2_ctrl_handler, req_obj);
struct v4l2_ctrl_handler *main_hdl = obj->priv;
- list_del_init(&hdl->requests);
mutex_lock(main_hdl->lock);
+ list_del_init(&hdl->requests);
if (hdl->request_is_queued) {
list_del_init(&hdl->requests_queued);
hdl->request_is_queued = false;
@@ -3790,8 +3798,11 @@ static int v4l2_ctrl_request_bind(struct media_request *req,
if (!ret) {
ret = media_request_object_bind(req, &req_ops,
from, false, &hdl->req_obj);
- if (!ret)
+ if (!ret) {
+ mutex_lock(from->lock);
list_add_tail(&hdl->requests, &from->requests);
+ mutex_unlock(from->lock);
+ }
}
return ret;
}