All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sergey Ryazanov <ryazanov.s.a@gmail.com>
To: Loic Poulain <loic.poulain@oss.qualcomm.com>,
	Slark Xiao <slark_xiao@163.com>
Cc: Johannes Berg <johannes@sipsolutions.net>,
	Andrew Lunn <andrew+netdev@lunn.ch>,
	Eric Dumazet <edumazet@google.com>,
	"David S . Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	netdev@vger.kernel.org, Daniele Palmas <dnlplm@gmail.com>
Subject: Re: [RFC PATCH v5 2/7] net: wwan: core: explicit WWAN device reference counting
Date: Thu, 15 Jan 2026 08:52:08 +0200	[thread overview]
Message-ID: <F9203EE2-8486-4CAD-8DD0-36971F3E9DA0@gmail.com> (raw)
In-Reply-To: <CAFEp6-3n=125v7RDbbJaT2XPyt+adGfgY-pgXguymYVy+oxuaw@mail.gmail.com>

On January 14, 2026 11:31:45 PM, Loic Poulain <loic.poulain@oss.qualcomm.com> wrote:
>On Fri, Jan 9, 2026 at 2:09 AM Sergey Ryazanov <ryazanov.s.a@gmail.com> wrote:
>>
>> We need information about existing WWAN device children since we remove
>> the device after removing the last child. Previously, we tracked users
>> implicitly by checking whether ops was registered and existence of a
>> child device of the wwan_class class. Upcoming GNSS (NMEA) port type
>> support breaks this approach by introducing a child device of the
>> gnss_class class.
>>
>> And a modem driver can easily trigger a kernel Oops by removing regular
>> (e.g., MBIM, AT) ports first and then removing a GNSS port. The WWAN
>> device will be unregistered on removal of a last regular WWAN port. And
>> subsequent GNSS port removal will cause NULL pointer dereference in
>> simple_recursive_removal().
>>
>> In order to support ports of classes other than wwan_class, switch to
>> explicit references counting. Introduce a dedicated counter to the WWAN
>> device struct, increment it on every wwan_create_dev() call, decrement
>> on wwan_remove_dev(), and actually unregister the WWAN device when there
>> are no more references.
>>
>> Run tested with wwan_hwsim with NMEA support patches applied and
>> different port removing sequences.
>>
>> Reported-by: Daniele Palmas <dnlplm@gmail.com>
>> Closes: https://lore.kernel.org/netdev/CAGRyCJE28yf-rrfkFbzu44ygLEvoUM7fecK1vnrghjG_e9UaRA@mail.gmail.com/
>> Suggested-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
>> Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
>> ---
>> Changes:
>> * RFCv2->RFCv5: new patch to address modem disconnection / system
>>   shutdown issues
>> ---
>>  drivers/net/wwan/wwan_core.c | 37 ++++++++++++++++++------------------
>>  1 file changed, 18 insertions(+), 19 deletions(-)
>>
>> diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c
>> index ade8bbffc93e..33f7a140fba9 100644
>> --- a/drivers/net/wwan/wwan_core.c
>> +++ b/drivers/net/wwan/wwan_core.c
>> @@ -42,6 +42,9 @@ static struct dentry *wwan_debugfs_dir;
>>   * struct wwan_device - The structure that defines a WWAN device
>>   *
>>   * @id: WWAN device unique ID.
>> + * @refcount: Reference count of this WWAN device. When this refcount reaches
>> + * zero, the device is deleted. NB: access is protected by global
>> + * wwan_register_lock mutex.
>>   * @dev: Underlying device.
>>   * @ops: wwan device ops
>>   * @ops_ctxt: context to pass to ops
>> @@ -49,6 +52,7 @@ static struct dentry *wwan_debugfs_dir;
>>   */
>>  struct wwan_device {
>>         unsigned int id;
>> +       int refcount;
>>         struct device dev;
>>         const struct wwan_ops *ops;
>>         void *ops_ctxt;
>> @@ -222,8 +226,10 @@ static struct wwan_device *wwan_create_dev(struct device *parent)
>>
>>         /* If wwandev already exists, return it */
>>         wwandev = wwan_dev_get_by_parent(parent);
>> -       if (!IS_ERR(wwandev))
>> +       if (!IS_ERR(wwandev)) {
>> +               wwandev->refcount++;
>>                 goto done_unlock;
>> +       }
>>
>>         id = ida_alloc(&wwan_dev_ids, GFP_KERNEL);
>>         if (id < 0) {
>> @@ -242,6 +248,7 @@ static struct wwan_device *wwan_create_dev(struct device *parent)
>>         wwandev->dev.class = &wwan_class;
>>         wwandev->dev.type = &wwan_dev_type;
>>         wwandev->id = id;
>> +       wwandev->refcount = 1;
>>         dev_set_name(&wwandev->dev, "wwan%d", wwandev->id);
>>
>>         err = device_register(&wwandev->dev);
>> @@ -263,30 +270,21 @@ static struct wwan_device *wwan_create_dev(struct device *parent)
>>         return wwandev;
>>  }
>>
>> -static int is_wwan_child(struct device *dev, void *data)
>> -{
>> -       return dev->class == &wwan_class;
>> -}
>> -
>>  static void wwan_remove_dev(struct wwan_device *wwandev)
>>  {
>> -       int ret;
>> -
>>         /* Prevent concurrent picking from wwan_create_dev */
>>         mutex_lock(&wwan_register_lock);
>
>FYI, you can use guarded mutex:
>guard(mutex)(&wwan_register_lock);
>This ensures the lock is 'automatically' released when leaving the
>scope/function, and would save the below goto/out_unlock.

Sounds curious. Will keep in my mind for a future development. I would rather keep this patch as simple and clear as possible.

>> -       /* WWAN device is created and registered (get+add) along with its first
>> -        * child port, and subsequent port registrations only grab a reference
>> -        * (get). The WWAN device must then be unregistered (del+put) along with
>> -        * its last port, and reference simply dropped (put) otherwise. In the
>> -        * same fashion, we must not unregister it when the ops are still there.
>> -        */
>> -       if (wwandev->ops)
>> -               ret = 1;
>> -       else
>> -               ret = device_for_each_child(&wwandev->dev, NULL, is_wwan_child);
>> +       if (--wwandev->refcount <= 0) {
>> +               struct device *child = device_find_any_child(&wwandev->dev);
>> +
>> +               if (WARN_ON(wwandev->ops))      /* Paranoid */
>
>You may keep a reference to child (if existing)
>
>> +                       goto out_unlock;
>> +               if (WARN_ON(child)) {           /* Paranoid */
>> +                       put_device(child);
>> +                       goto out_unlock;
>> +               }
>
>Maybe you can simplify that with:
>```
>struct device *child = device_find_any_child(&wwandev->dev);
>put_device(child) /* NULL param is ok */
>if (WARN_ON(child || wwandev->ops))
>    return; /* or goto */
>```

Good point.

Slark, could you adjust this in your future submission or do you want me to send another RFC series?

>>
>> -       if (!ret) {
>>  #ifdef CONFIG_WWAN_DEBUGFS
>>                 debugfs_remove_recursive(wwandev->debugfs_dir);
>>  #endif
>> @@ -295,6 +293,7 @@ static void wwan_remove_dev(struct wwan_device *wwandev)
>>                 put_device(&wwandev->dev);
>>         }
>>
>> +out_unlock:
>>         mutex_unlock(&wwan_register_lock);
>>  }

--
Sergey

Hi Loic,

  reply	other threads:[~2026-01-15  6:52 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-09  1:09 [RFC PATCH v5 0/7] net: wwan: add NMEA port type support Sergey Ryazanov
2026-01-09  1:09 ` [RFC PATCH v5 1/7] net: wwan: core: remove unused port_id field Sergey Ryazanov
2026-01-09  1:09 ` [RFC PATCH v5 2/7] net: wwan: core: explicit WWAN device reference counting Sergey Ryazanov
2026-01-14 21:31   ` Loic Poulain
2026-01-15  6:52     ` Sergey Ryazanov [this message]
2026-01-15  8:08       ` Slark Xiao
2026-01-09  1:09 ` [RFC PATCH v5 3/7] net: wwan: core: split port creation and registration Sergey Ryazanov
2026-01-09  1:09 ` [RFC PATCH v5 4/7] net: wwan: core: split port unregister and stop Sergey Ryazanov
2026-01-09  1:09 ` [RFC PATCH v5 5/7] net: wwan: add NMEA port support Sergey Ryazanov
2026-01-09  1:09 ` [RFC PATCH v5 6/7] net: wwan: hwsim: refactor to support more port types Sergey Ryazanov
2026-01-09  1:09 ` [RFC PATCH v5 7/7] net: wwan: hwsim: support NMEA port emulation Sergey Ryazanov
2026-01-15 13:16   ` kernel test robot
2026-01-15 14:56   ` kernel test robot
2026-01-09  3:21 ` Re:[RFC PATCH v5 0/7] net: wwan: add NMEA port type support Slark Xiao
2026-01-09  7:11   ` Sergey Ryazanov
2026-01-13  2:03     ` Slark Xiao
2026-01-13  6:59       ` Sergey Ryazanov
2026-01-14  2:42         ` Slark Xiao
2026-01-14 19:59           ` [RFC " Sergey Ryazanov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=F9203EE2-8486-4CAD-8DD0-36971F3E9DA0@gmail.com \
    --to=ryazanov.s.a@gmail.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=dnlplm@gmail.com \
    --cc=edumazet@google.com \
    --cc=johannes@sipsolutions.net \
    --cc=kuba@kernel.org \
    --cc=loic.poulain@oss.qualcomm.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=slark_xiao@163.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.