media: v4l: subdev: Add a function to lock two sub-device states, use it
authorSakari Ailus <sakari.ailus@linux.intel.com>
Wed, 6 Sep 2023 07:56:14 +0000 (10:56 +0300)
committerHans Verkuil <hverkuil-cisco@xs4all.nl>
Mon, 29 Apr 2024 12:56:37 +0000 (14:56 +0200)
Add two new functions, v4l2_subdev_lock_states() and
v4l2_subdev_unclock_states(), to acquire and release the state of two
sub-devices. They differ from calling v4l2_subdev_{un,}lock_state() so
that if the two states share the same lock, the lock is acquired only
once.

Also use the new functions in v4l2_subdev_link_validate().

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Julien Massot <julien.massot@collabora.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
drivers/media/v4l2-core/v4l2-subdev.c
include/media/v4l2-subdev.h

index 2d67ec54569aadf97ff916d7e9bfa377f1d5dcc7..779583447eacfaa5b8744da7920cdaea43a26bba 100644 (file)
@@ -1437,17 +1437,13 @@ int v4l2_subdev_link_validate(struct media_link *link)
 
        states_locked = sink_state && source_state;
 
-       if (states_locked) {
-               v4l2_subdev_lock_state(sink_state);
-               v4l2_subdev_lock_state(source_state);
-       }
+       if (states_locked)
+               v4l2_subdev_lock_states(sink_state, source_state);
 
        ret = v4l2_subdev_link_validate_locked(link, states_locked);
 
-       if (states_locked) {
-               v4l2_subdev_unlock_state(sink_state);
-               v4l2_subdev_unlock_state(source_state);
-       }
+       if (states_locked)
+               v4l2_subdev_unlock_states(sink_state, source_state);
 
        return ret;
 }
index 1af16b16f0bf7242dc9a6b371e0b598e74920790..e22c50ce7e05f9460d5114d88bd932c9f3a97574 100644 (file)
@@ -1724,6 +1724,46 @@ static inline void v4l2_subdev_unlock_state(struct v4l2_subdev_state *state)
        mutex_unlock(state->lock);
 }
 
+/**
+ * v4l2_subdev_lock_states - Lock two sub-device states
+ * @state1: One subdevice state
+ * @state2: The other subdevice state
+ *
+ * Locks the state of two sub-devices.
+ *
+ * The states must be unlocked with v4l2_subdev_unlock_states() after use.
+ *
+ * This differs from calling v4l2_subdev_lock_state() on both states so that if
+ * the states share the same lock, the lock is acquired only once (so no
+ * deadlock occurs). The caller is responsible for ensuring the locks will
+ * always be acquired in the same order.
+ */
+static inline void v4l2_subdev_lock_states(struct v4l2_subdev_state *state1,
+                                          struct v4l2_subdev_state *state2)
+{
+       mutex_lock(state1->lock);
+       if (state1->lock != state2->lock)
+               mutex_lock(state2->lock);
+}
+
+/**
+ * v4l2_subdev_unlock_states() - Unlock two sub-device states
+ * @state1: One subdevice state
+ * @state2: The other subdevice state
+ *
+ * Unlocks the state of two sub-devices.
+ *
+ * This differs from calling v4l2_subdev_unlock_state() on both states so that
+ * if the states share the same lock, the lock is released only once.
+ */
+static inline void v4l2_subdev_unlock_states(struct v4l2_subdev_state *state1,
+                                            struct v4l2_subdev_state *state2)
+{
+       mutex_unlock(state1->lock);
+       if (state1->lock != state2->lock)
+               mutex_unlock(state2->lock);
+}
+
 /**
  * v4l2_subdev_get_unlocked_active_state() - Checks that the active subdev state
  *                                          is unlocked and returns it