diff mbox series

usb: roles: Fix a false positive recursive locking complaint

Message ID 20240904201839.2901330-1-bvanassche@acm.org (mailing list archive)
State New
Headers show
Series usb: roles: Fix a false positive recursive locking complaint | expand

Commit Message

Bart Van Assche Sept. 4, 2024, 8:18 p.m. UTC
Suppress the following lockdep complaint:

INFO: trying to register non-static key.
The code is fine but needs lockdep annotation, or maybe
you didn't initialize this object before use?
turning off the locking correctness validator.

Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Andy Shevchenko <andy.shevchenko@gmail.com>
Cc: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: stable@vger.kernel.org
Fixes: fde0aa6c175a ("usb: common: Small class for USB role switches")
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
 drivers/usb/roles/class.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

Comments

Badhri Jagan Sridharan Sept. 4, 2024, 9 p.m. UTC | #1
HI Bart,

On Wed, Sep 4, 2024 at 1:19 PM Bart Van Assche <bvanassche@acm.org> wrote:
>
> Suppress the following lockdep complaint:
>
> INFO: trying to register non-static key.
> The code is fine but needs lockdep annotation, or maybe
> you didn't initialize this object before use?
> turning off the locking correctness validator.
>
> Cc: Hans de Goede <hdegoede@redhat.com>
> Cc: Andy Shevchenko <andy.shevchenko@gmail.com>
> Cc: Heikki Krogerus <heikki.krogerus@linux.intel.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: stable@vger.kernel.org
> Fixes: fde0aa6c175a ("usb: common: Small class for USB role switches")
> Signed-off-by: Bart Van Assche <bvanassche@acm.org>
> ---
>  drivers/usb/roles/class.c | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
> index d7aa913ceb8a..f648ce3dd9b5 100644
> --- a/drivers/usb/roles/class.c
> +++ b/drivers/usb/roles/class.c
> @@ -21,6 +21,7 @@ static const struct class role_class = {
>
>  struct usb_role_switch {
>         struct device dev;
> +       struct lock_class_key key;
>         struct mutex lock; /* device lock*/
>         struct module *module; /* the module this device depends on */
>         enum usb_role role;
> @@ -326,6 +327,8 @@ static void usb_role_switch_release(struct device *dev)
>  {
>         struct usb_role_switch *sw = to_role_switch(dev);
>
> +       mutex_destroy(&sw->lock);
> +       lockdep_unregister_key(&sw->key);
>         kfree(sw);
>  }
>
> @@ -364,7 +367,8 @@ usb_role_switch_register(struct device *parent,
>         if (!sw)
>                 return ERR_PTR(-ENOMEM);
>
> -       mutex_init(&sw->lock);
> +       lockdep_register_key(&sw->key);
> +       __mutex_init(&sw->lock, "usb_role_switch_desc::lock", &sw->key);

https://lore.kernel.org/all/ZsiYRAJST%2F2hAju1@kuha.fi.intel.com/ was
already accepted and is perhaps better than what you are suggesting as
it does not use the internal methods of mutex_init(). CCing Amit as
well so that his patch can be submitted to stable trees as well.

>
>         sw->allow_userspace_control = desc->allow_userspace_control;
>         sw->usb2_port = desc->usb2_port;
>

Thanks,
Badhri
Bart Van Assche Sept. 4, 2024, 9:15 p.m. UTC | #2
On 9/4/24 2:00 PM, Badhri Jagan Sridharan wrote:
> https://lore.kernel.org/all/ZsiYRAJST%2F2hAju1@kuha.fi.intel.com/ was
> already accepted

Thanks, I hadn't noticed this yet.

> and is perhaps better than what you are suggesting as
> it does not use the internal methods of mutex_init().

Although I do not have a strong opinion about which patch is sent to
Linus, I think my patch has multiple advantages compared to the patch
mentioned above:
- Cleaner. lockdep_set_class() is not used. Hence, it is not possible
   that the wrong lockdep key is used (the one assigned by
   mutex_init()).
- The lock_class_key declaration occurs close to the sw->lock
   declaration.
- The lockdep_register_key() call occurs close to __mutex_init() call
   that uses the registered key.
- Needs less memory in debug kernels. The advantage of __mutex_init()
   compared to mutex_init() is that it does not allocate (static) memory
   for a lockdep key.

Thanks,

Bart.
Amit Sunil Dhamne Sept. 4, 2024, 10:34 p.m. UTC | #3
Hi Bart,

On 9/4/24 2:15 PM, Bart Van Assche wrote:
> On 9/4/24 2:00 PM, Badhri Jagan Sridharan wrote:
>> https://lore.kernel.org/all/ZsiYRAJST%2F2hAju1@kuha.fi.intel.com/ was
>> already accepted
>
> Thanks, I hadn't noticed this yet.
>
>> and is perhaps better than what you are suggesting as
>> it does not use the internal methods of mutex_init().
>
> Although I do not have a strong opinion about which patch is sent to
> Linus, I think my patch has multiple advantages compared to the patch
> mentioned above:
> - Cleaner. lockdep_set_class() is not used. Hence, it is not possible
>   that the wrong lockdep key is used (the one assigned by
>   mutex_init()).
> - The lock_class_key declaration occurs close to the sw->lock
>   declaration.
> - The lockdep_register_key() call occurs close to __mutex_init() call
>   that uses the registered key.
> - Needs less memory in debug kernels. The advantage of __mutex_init()
>   compared to mutex_init() is that it does not allocate (static) memory
>   for a lockdep key.
>
Thanks for the patch.

While I agree on (1) & (4), *may* be a good reason to reconsider.
However, I have seen almost 30+ instances of the prior
method 
(https://lore.kernel.org/all/20240822223717.253433-1-amitsd@google.com/)
of registering lockdep key, which is what I followed.
However, if that's is not the right way, it brings into question the purpose
of lockdep_set_class() considering I would always and unconditionally use
__mutex_init()  if I want to manage the lockdep class keys myself or
mutex_init() if I didn't.


Thanks,

Amit

> Thanks,
>
> Bart.
>
Bart Van Assche Sept. 5, 2024, 3:01 p.m. UTC | #4
On 9/4/24 3:34 PM, Amit Sunil Dhamne wrote:
> However, I have seen almost 30+ instances of the prior
> method 
> (https://lore.kernel.org/all/20240822223717.253433-1-amitsd@google.com/)
> of registering lockdep key, which is what I followed.

Many of these examples are for spinlocks. It would be good to have a
variant of spin_lock_init() that does not instantiate a struct
lock_class_key and instead accepts a lock_class_key pointer as argument.

> However, if that's is not the right way, it brings into question the 
> purpose
> of lockdep_set_class() considering I would always and unconditionally use
> __mutex_init()  if I want to manage the lockdep class keys myself or
> mutex_init() if I didn't.
What I'm proposing is not a new pattern. There are multiple examples
in the kernel tree of lockdep_register_key() calls followed by a
__mutex_init() call:

$ git grep -wB3 __mutex_init | grep lockdep_register_key | wc -l
5

Thanks,

Bart.
Andy Shevchenko Sept. 5, 2024, 6:13 p.m. UTC | #5
On Thu, Sep 5, 2024 at 6:01 PM Bart Van Assche <bvanassche@acm.org> wrote:
> On 9/4/24 3:34 PM, Amit Sunil Dhamne wrote:
> > However, I have seen almost 30+ instances of the prior
> > method
> > (https://lore.kernel.org/all/20240822223717.253433-1-amitsd@google.com/)
> > of registering lockdep key, which is what I followed.
>
> Many of these examples are for spinlocks. It would be good to have a
> variant of spin_lock_init() that does not instantiate a struct
> lock_class_key and instead accepts a lock_class_key pointer as argument.
>
> > However, if that's is not the right way, it brings into question the
> > purpose
> > of lockdep_set_class() considering I would always and unconditionally use
> > __mutex_init()  if I want to manage the lockdep class keys myself or
> > mutex_init() if I didn't.
> What I'm proposing is not a new pattern. There are multiple examples
> in the kernel tree of lockdep_register_key() calls followed by a
> __mutex_init() call:
>
> $ git grep -wB3 __mutex_init | grep lockdep_register_key | wc -l
> 5

I see pros and cons for both approaches, but I take Bart's as the simpler one.
However, since it might be confusing, what I would suggest is to add a
respective wrapper to mutex.h and have a non-__ named macro for this
case.
Andy Shevchenko Sept. 5, 2024, 6:14 p.m. UTC | #6
On Thu, Sep 5, 2024 at 9:13 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Thu, Sep 5, 2024 at 6:01 PM Bart Van Assche <bvanassche@acm.org> wrote:
> > On 9/4/24 3:34 PM, Amit Sunil Dhamne wrote:
> > > However, I have seen almost 30+ instances of the prior
> > > method
> > > (https://lore.kernel.org/all/20240822223717.253433-1-amitsd@google.com/)
> > > of registering lockdep key, which is what I followed.
> >
> > Many of these examples are for spinlocks. It would be good to have a
> > variant of spin_lock_init() that does not instantiate a struct
> > lock_class_key and instead accepts a lock_class_key pointer as argument.
> >
> > > However, if that's is not the right way, it brings into question the
> > > purpose
> > > of lockdep_set_class() considering I would always and unconditionally use
> > > __mutex_init()  if I want to manage the lockdep class keys myself or
> > > mutex_init() if I didn't.
> > What I'm proposing is not a new pattern. There are multiple examples
> > in the kernel tree of lockdep_register_key() calls followed by a
> > __mutex_init() call:
> >
> > $ git grep -wB3 __mutex_init | grep lockdep_register_key | wc -l
> > 5
>
> I see pros and cons for both approaches, but I take Bart's as the simpler one.
> However, since it might be confusing, what I would suggest is to add a
> respective wrapper to mutex.h and have a non-__ named macro for this
> case.

To be clear, something like

#define mutex_init_with_lockdep(...)
do {
  ...
  __mutex_init();
} while (0)

in the mutex.h.
Bart Van Assche Sept. 5, 2024, 6:22 p.m. UTC | #7
On 9/5/24 11:14 AM, Andy Shevchenko wrote:
> To be clear, something like
> 
> #define mutex_init_with_lockdep(...)
> do {
>    ...
>    __mutex_init();
> } while (0)
> 
> in the mutex.h.

How about using the name "mutex_init_with_key()" since the name
"lockdep" refers to the lock dependency infrastructure and the
additional argument will have type struct lock_class_key *?

Amit, do you want me to add your Signed-off-by to my patch since
your patch was posted first on the linux-usb mailing list?

Thanks,

Bart.
Amit Sunil Dhamne Sept. 5, 2024, 7:23 p.m. UTC | #8
Hi,

On 9/5/24 11:22 AM, Bart Van Assche wrote:
> On 9/5/24 11:14 AM, Andy Shevchenko wrote:
>> To be clear, something like
>>
>> #define mutex_init_with_lockdep(...)
>> do {
>>    ...
>>    __mutex_init();
>> } while (0)
>>
>> in the mutex.h.
>
> How about using the name "mutex_init_with_key()" since the name
> "lockdep" refers to the lock dependency infrastructure and the
> additional argument will have type struct lock_class_key *?
>
> Amit, do you want me to add your Signed-off-by to my patch since
> your patch was posted first on the linux-usb mailing list?
>
Yes, thank you :) .

Also, thanks for the clarification on my previous questions Bart and for 
your suggestions Andy!

-

Amit

> Thanks,
>
> Bart.
>
Andy Shevchenko Sept. 5, 2024, 7:24 p.m. UTC | #9
On Thu, Sep 5, 2024 at 9:23 PM Bart Van Assche <bvanassche@acm.org> wrote:
> On 9/5/24 11:14 AM, Andy Shevchenko wrote:
> > To be clear, something like
> >
> > #define mutex_init_with_lockdep(...)
> > do {
> >    ...
> >    __mutex_init();
> > } while (0)
> >
> > in the mutex.h.
>
> How about using the name "mutex_init_with_key()" since the name
> "lockdep" refers to the lock dependency infrastructure and the
> additional argument will have type struct lock_class_key *?

LGTM, go for it!
diff mbox series

Patch

diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
index d7aa913ceb8a..f648ce3dd9b5 100644
--- a/drivers/usb/roles/class.c
+++ b/drivers/usb/roles/class.c
@@ -21,6 +21,7 @@  static const struct class role_class = {
 
 struct usb_role_switch {
 	struct device dev;
+	struct lock_class_key key;
 	struct mutex lock; /* device lock*/
 	struct module *module; /* the module this device depends on */
 	enum usb_role role;
@@ -326,6 +327,8 @@  static void usb_role_switch_release(struct device *dev)
 {
 	struct usb_role_switch *sw = to_role_switch(dev);
 
+	mutex_destroy(&sw->lock);
+	lockdep_unregister_key(&sw->key);
 	kfree(sw);
 }
 
@@ -364,7 +367,8 @@  usb_role_switch_register(struct device *parent,
 	if (!sw)
 		return ERR_PTR(-ENOMEM);
 
-	mutex_init(&sw->lock);
+	lockdep_register_key(&sw->key);
+	__mutex_init(&sw->lock, "usb_role_switch_desc::lock", &sw->key);
 
 	sw->allow_userspace_control = desc->allow_userspace_control;
 	sw->usb2_port = desc->usb2_port;