Skip to content

Commit 56aa767

Browse files
ribaldagregkh
authored andcommitted
media: uvcvideo: Rollback non processed entities on error
commit a70705d upstream. If we fail to commit an entity, we need to restore the UVC_CTRL_DATA_BACKUP for the other uncommitted entities. Otherwise the control cache and the device would be out of sync. Cc: stable@kernel.org Fixes: b401200 ("[media] uvcvideo: Add support for control events") Reported-by: Hans de Goede <hdegoede@redhat.com> Closes: https://lore.kernel.org/linux-media/fe845e04-9fde-46ee-9763-a6f00867929a@redhat.com/ Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> Message-ID: <20250224-uvc-data-backup-v2-3-de993ed9823b@chromium.org> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent f165d04 commit 56aa767

1 file changed

Lines changed: 26 additions & 13 deletions

File tree

drivers/media/usb/uvc/uvc_ctrl.c

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1801,7 +1801,7 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
18011801
unsigned int processed_ctrls = 0;
18021802
struct uvc_control *ctrl;
18031803
unsigned int i;
1804-
int ret;
1804+
int ret = 0;
18051805

18061806
if (entity == NULL)
18071807
return 0;
@@ -1830,8 +1830,6 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
18301830
dev->intfnum, ctrl->info.selector,
18311831
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
18321832
ctrl->info.size);
1833-
else
1834-
ret = 0;
18351833

18361834
if (!ret)
18371835
processed_ctrls++;
@@ -1843,17 +1841,25 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
18431841

18441842
ctrl->dirty = 0;
18451843

1846-
if (ret < 0) {
1844+
if (!rollback && handle &&
1845+
ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
1846+
uvc_ctrl_set_handle(handle, ctrl, handle);
1847+
1848+
if (ret < 0 && !rollback) {
18471849
if (err_ctrl)
18481850
*err_ctrl = ctrl;
1849-
return ret;
1851+
/*
1852+
* If we fail to set a control, we need to rollback
1853+
* the next ones.
1854+
*/
1855+
rollback = 1;
18501856
}
18511857

1852-
if (!rollback && handle &&
1853-
ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
1854-
uvc_ctrl_set_handle(handle, ctrl, handle);
18551858
}
18561859

1860+
if (ret)
1861+
return ret;
1862+
18571863
return processed_ctrls;
18581864
}
18591865

@@ -1884,7 +1890,8 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
18841890
struct uvc_video_chain *chain = handle->chain;
18851891
struct uvc_control *err_ctrl;
18861892
struct uvc_entity *entity;
1887-
int ret = 0;
1893+
int ret_out = 0;
1894+
int ret;
18881895

18891896
/* Find the control. */
18901897
list_for_each_entry(entity, &chain->entities, chain) {
@@ -1895,17 +1902,23 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
18951902
ctrls->error_idx =
18961903
uvc_ctrl_find_ctrl_idx(entity, ctrls,
18971904
err_ctrl);
1898-
goto done;
1905+
/*
1906+
* When we fail to commit an entity, we need to
1907+
* restore the UVC_CTRL_DATA_BACKUP for all the
1908+
* controls in the other entities, otherwise our cache
1909+
* and the hardware will be out of sync.
1910+
*/
1911+
rollback = 1;
1912+
1913+
ret_out = ret;
18991914
} else if (ret > 0 && !rollback) {
19001915
uvc_ctrl_send_events(handle, entity,
19011916
ctrls->controls, ctrls->count);
19021917
}
19031918
}
19041919

1905-
ret = 0;
1906-
done:
19071920
mutex_unlock(&chain->ctrl_mutex);
1908-
return ret;
1921+
return ret_out;
19091922
}
19101923

19111924
int uvc_ctrl_get(struct uvc_video_chain *chain,

0 commit comments

Comments
 (0)