summaryrefslogtreecommitdiff
path: root/drivers/media/v4l2-core/v4l2-subdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/v4l2-core/v4l2-subdev.c')
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c63
1 files changed, 46 insertions, 17 deletions
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 8f09b1175ef9..47d480786f03 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -27,8 +27,9 @@
static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
{
struct v4l2_subdev_state *state;
+ static struct lock_class_key key;
- state = __v4l2_subdev_state_alloc(sd);
+ state = __v4l2_subdev_state_alloc(sd, "fh->state->lock", &key);
if (IS_ERR(state))
return PTR_ERR(state);
@@ -379,21 +380,18 @@ subdev_ioctl_get_state(struct v4l2_subdev *sd, struct v4l2_subdev_fh *subdev_fh,
return which == V4L2_SUBDEV_FORMAT_TRY ?
subdev_fh->state :
- v4l2_subdev_get_active_state(sd);
+ v4l2_subdev_get_unlocked_active_state(sd);
}
-static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
+ struct v4l2_subdev_state *state)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
struct v4l2_fh *vfh = file->private_data;
- struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);
bool ro_subdev = test_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags);
- struct v4l2_subdev_state *state;
int rval;
- state = subdev_ioctl_get_state(sd, subdev_fh, cmd, arg);
-
switch (cmd) {
case VIDIOC_SUBDEV_QUERYCAP: {
struct v4l2_subdev_capability *cap = arg;
@@ -706,8 +704,24 @@ static long subdev_do_ioctl_lock(struct file *file, unsigned int cmd, void *arg)
if (lock && mutex_lock_interruptible(lock))
return -ERESTARTSYS;
- if (video_is_registered(vdev))
- ret = subdev_do_ioctl(file, cmd, arg);
+
+ if (video_is_registered(vdev)) {
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+ struct v4l2_fh *vfh = file->private_data;
+ struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);
+ struct v4l2_subdev_state *state;
+
+ state = subdev_ioctl_get_state(sd, subdev_fh, cmd, arg);
+
+ if (state)
+ v4l2_subdev_lock_state(state);
+
+ ret = subdev_do_ioctl(file, cmd, arg, state);
+
+ if (state)
+ v4l2_subdev_unlock_state(state);
+ }
+
if (lock)
mutex_unlock(lock);
return ret;
@@ -861,13 +875,10 @@ v4l2_subdev_link_validate_get_format(struct media_pad *pad,
if (is_media_entity_v4l2_subdev(pad->entity)) {
struct v4l2_subdev *sd =
media_entity_to_v4l2_subdev(pad->entity);
- struct v4l2_subdev_state *state;
-
- state = v4l2_subdev_get_active_state(sd);
fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
fmt->pad = pad->index;
- return v4l2_subdev_call(sd, pad, get_fmt, state, fmt);
+ return v4l2_subdev_call_state_active(sd, pad, get_fmt, fmt);
}
WARN(pad->entity->function != MEDIA_ENT_F_IO_V4L,
@@ -905,7 +916,9 @@ int v4l2_subdev_link_validate(struct media_link *link)
}
EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate);
-struct v4l2_subdev_state *__v4l2_subdev_state_alloc(struct v4l2_subdev *sd)
+struct v4l2_subdev_state *
+__v4l2_subdev_state_alloc(struct v4l2_subdev *sd, const char *lock_name,
+ struct lock_class_key *lock_key)
{
struct v4l2_subdev_state *state;
int ret;
@@ -914,6 +927,12 @@ struct v4l2_subdev_state *__v4l2_subdev_state_alloc(struct v4l2_subdev *sd)
if (!state)
return ERR_PTR(-ENOMEM);
+ __mutex_init(&state->_lock, lock_name, lock_key);
+ if (sd->state_lock)
+ state->lock = sd->state_lock;
+ else
+ state->lock = &state->_lock;
+
if (sd->entity.num_pads) {
state->pads = kvmalloc_array(sd->entity.num_pads,
sizeof(*state->pads),
@@ -924,7 +943,14 @@ struct v4l2_subdev_state *__v4l2_subdev_state_alloc(struct v4l2_subdev *sd)
}
}
+ /*
+ * There can be no race at this point, but we lock the state anyway to
+ * satisfy lockdep checks.
+ */
+ v4l2_subdev_lock_state(state);
ret = v4l2_subdev_call(sd, pad, init_cfg, state);
+ v4l2_subdev_unlock_state(state);
+
if (ret < 0 && ret != -ENOIOCTLCMD)
goto err;
@@ -945,16 +971,19 @@ void __v4l2_subdev_state_free(struct v4l2_subdev_state *state)
if (!state)
return;
+ mutex_destroy(&state->_lock);
+
kvfree(state->pads);
kfree(state);
}
EXPORT_SYMBOL_GPL(__v4l2_subdev_state_free);
-int v4l2_subdev_init_finalize(struct v4l2_subdev *sd)
+int __v4l2_subdev_init_finalize(struct v4l2_subdev *sd, const char *name,
+ struct lock_class_key *key)
{
struct v4l2_subdev_state *state;
- state = __v4l2_subdev_state_alloc(sd);
+ state = __v4l2_subdev_state_alloc(sd, name, key);
if (IS_ERR(state))
return PTR_ERR(state);
@@ -962,7 +991,7 @@ int v4l2_subdev_init_finalize(struct v4l2_subdev *sd)
return 0;
}
-EXPORT_SYMBOL_GPL(v4l2_subdev_init_finalize);
+EXPORT_SYMBOL_GPL(__v4l2_subdev_init_finalize);
void v4l2_subdev_cleanup(struct v4l2_subdev *sd)
{