public inbox for linux-usb@vger.kernel.org
 help / color / mirror / Atom feed
From: Greg KH <gregkh@linuxfoundation.org>
To: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Cc: Xu Yang <xu.yang_2@nxp.com>,
	Alan Stern <stern@rowland.harvard.edu>,
	"benjamin.tissoires@redhat.com" <benjamin.tissoires@redhat.com>,
	"hdegoede@redhat.com" <hdegoede@redhat.com>,
	"ivan.orlov0322@gmail.com" <ivan.orlov0322@gmail.com>,
	"linux-usb@vger.kernel.org" <linux-usb@vger.kernel.org>,
	dl-linux-imx <linux-imx@nxp.com>, Jun Li <jun.li@nxp.com>
Subject: Re: [EXT] Re: [PATCH] usb: roles: try to get/put all relevant modules
Date: Thu, 18 Jan 2024 15:54:16 +0100	[thread overview]
Message-ID: <2024011842-harpist-password-b965@gregkh> (raw)
In-Reply-To: <Zakb4lHpiS7ty+aF@kuha.fi.intel.com>

On Thu, Jan 18, 2024 at 02:38:58PM +0200, Heikki Krogerus wrote:
> Hi Greg,
> 
> On Thu, Jan 18, 2024 at 10:53:34AM +0100, Greg KH wrote:
> > On Thu, Jan 18, 2024 at 11:22:06AM +0200, Heikki Krogerus wrote:
> > > Hi,
> > > 
> > > On Wed, Jan 17, 2024 at 05:57:02AM +0000, Xu Yang wrote:
> > > > Hi Alan,
> > > > 
> > > > > 
> > > > > On Tue, Jan 16, 2024 at 05:44:47AM +0000, Xu Yang wrote:
> > > > > > Hi Alan,
> > > > > >
> > > > > > >
> > > > > > > Those of us unfamiliar with this code need you to explain a lot more
> > > > > > > about what's going on.
> > > > > > >
> > > > > > > On Mon, Jan 15, 2024 at 03:02:06AM +0000, Xu Yang wrote:
> > > > > > > > Taking below diagram as example:
> > > > > > > >
> > > > > > > >      ci_hdrc.0        register   usb    get     tcpm_port
> > > > > > > >   (driver: ci_hdrc)  --------->  role  <----  (driver: tcpm)
> > > > > > > >          ^  ^                    switch           |   ^
> > > > > > > >          |  |                                     |   |
> > > > > > > >        +1|  |           +1                        |   |+1
> > > > > > > >          |  +-------------------------------------+   |
> > > > > > > >          |                                            |
> > > > > > > >      4c200000.usb                                   1-0050
> > > > > > > > (driver: ci_hdrc_imx)                            (driver: tcpci)
> > > > > > > >
> > > > > > > > 1. Driver ci_hdrc_imx and tcpci are built as module at least.
> > > > > > > > 2. When module ci_hdrc_imx is loaded, it will register ci_hdrc.0 device
> > > > > > > >    and try to get ci_hdrc module's reference.
> > > > > > >
> > > > > > > This is very confusing.  Normally, a device is registered by the parent
> > > > > > > module and its driver belongs in the child module.  When the child
> > > > > > > module is loaded it automatically gets a reference to the parent module,
> > > > > > > because it calls functions that are defined in the parent.  I don't know
> > > > > > > of any cases where a parent module takes a reference to one of its
> > > > > > > children -- this would make it impossible to unload the child module!
> > > > > > >
> > > > > > > In your diagram I can't tell whether ci_hdrc is the parent module and
> > > > > > > ci_hdrc_imx is the child, or vice versa.  I'll guess that ci_hdrc_imx is
> > > > > > > the child, since it the one which gets a reference to the other.  But
> > > > > > > now we have the ci_hdrc.0 device being registered by the child module
> > > > > > > and its driver belonging to the parent module, which is backward!
> > > > > > >
> > > > > > > Very difficult to understand.  Please explain more fully.
> > > > > >
> > > > > > I checked again and let me correct the words.
> > > > > >
> > > > > > 2. When module ci_hdrc_imx is loaded, it will register ci_hdrc.0 device.
> > > > > >    At the same time, the reference of module ci_hdrc is added by 1
> > > > > >    automatically due to ci_hdrc_imx calls some functions in module ci_hdrc.
> > > > > >    ci_hdrc will register usb-role-switch device.
> > > > > >
> > > > > > Therefore, module ci_hdrc_imx depends on module ci_hdrc. Device ci_hdrc.0
> > > > > > is a child of 4c200000.usb.
> > > > > 
> > > > > And ci_hdrc_imx is a child module of ci_hdrc.  Got it.
> > > > > 
> > > > > > > >  ci_hdrc will register
> > > > > > > >    usb-role-switch device.
> > > > > > > > 3. When module tcpci is loaded, it will register tcpm port device and try
> > > > > > > >    to get tcpm module's reference. The tcpm module will get usb-role-switch
> > > > > > > >    which is registered by ci_hdrc.
> > > > > > >
> > > > > > > What do you mean by "will get"?  Do you mean that tcpm will become the
> > > > > > > driver for the usb_role_switch device?  Or do you mean that it simply
> > > > > > > calls get_device(&usb_role_switch)?
> > > > > > >
> > > > > > > If the latter is the case, how does the tcpm driver learn the address of
> > > > > > > usb_role_switch in the first place?
> > > > > >
> > > > > > Via
> > > > > > port->role_sw = usb_role_switch_get(port->dev)
> > > > > > or
> > > > > > port->role_sw = fwnode_usb_role_switch_get(tcpc->fwnode).
> > > > > >
> > > > > > The usb controller will register usb-role-swtich device to the global list
> > > > > > of usb_role class. The fwnode of usb-role-swtich device is also set to usb
> > > > > > controller's fwnode. Initially, a fwnode graph between usb controller of
> > > > > > node and tcpm connector node had already been established. These two
> > > > > > functions will find usb-role-swtich device based on this fwnode graph
> > > > > > and fwnode matching.
> > > > > 
> > > > > If usb_role_switch_get() gives away references to the usb_role_switch
> > > > > device, it should have a way to take those references back.  But I guess
> > > > > it doesn't.
> > > > > 
> > > > > >  After usb-role-switce device is found, these two
> > > > > > functions will call: try_module_get(sw->dev.parent->driver->owner).
> > > > > 
> > > > > You mean usb_role_switch_get() and fwnode_usb_role_switch_get() do this?
> > > > 
> > > > Yes.
> > > > 
> > > > > 
> > > > > > Here sw->dev.parent is device ci_hdrc.0. sw->dev.parent->driver is ci_hdrc.
> > > > > >
> > > > > > >
> > > > > > > >  In current design, tcpm will also try to
> > > > > > > >    get ci_hdrc module's reference after get usb-role-switch.
> > > > > > >
> > > > > > > This might be a bug.  There should not be any need for the tcpm driver
> > > > > > > to take a reference to the ci_hdrc module.  But there should be a way
> > > > > > > for the ci_hdrc driver to notify tcpm when the usb_role_switch device is
> > > > > > > about to be unregistered.  If tcpm is usb_role_switch's driver then this
> > > > > > > notification happens automatically, by means of the .remove() callback.
> > > > > >
> > > > > > I'm not the designer of usb_role class driver. Not sure if this is needed to get
> > > > > > module reference of its parent device's driver. Maybe need @heikki's input.
> > > > > >
> > > > > > @heikki.krogerus, can you give some explanations?
> > > > > 
> > > > > Yes, please, some additional explanation would help.
> > > > > 
> > > > > > > > 4. Due to no modules depend on ci_hdrc_imx, ci_hdrc_imx can be manually
> > > > > > > >    unloaded. Then device ci_hdrc.0 will be removed by ci_hdrc_imx and
> > > > > > > >    device usb-role-switch is also unregistered.
> > > > > > >
> > > > > > > At this point, tcpm should learn that it has to drop all its references
> > > > > > > to usb_role_swich.  Since the module which registered usb_role_switch
> > > > > > > isn't tcpm's ancestor, tcpm must not keep _any_ references to the device
> > > > > > > after it is unregistered.
> > > > > >
> > > > > > Yes, I also think so.
> > > > > >
> > > > > > >
> > > > > > > Well, strictly speaking that's not true.  By misusing the driver model,
> > > > > > > tcpm could keep a reference to the ci_hdrc module until it was finished
> > > > > > > using usb_role_switch.  Is that what you are trying to do?
> > > > > >
> > > > > > No, I'm trying to get module reference of ci_hdrc_imx too. Then,
> > > > > > ci_hdrc_imx can't be unloaded before tcpci module unloaded.
> > > > > 
> > > > > You shouldn't do this.  Users should be able to unload ci_hdrc_imx
> > > > > whenever they want, even if tcpci is still loaded.
> > > > 
> > > > Okay. Understand.
> > > > 
> > > > > 
> > > > > > > > 5. Then, if I try to unload module tcpci, "NULL pointer dereference"
> > > > > > > >    will be shown due to below code:
> > > > > > > >
> > > > > > > >    module_put(sw->dev.parent->driver->owner);
> > > > > 
> > > > > I forgot to ask: What function makes this call?  Is it part of the
> > > > > usb_role class driver?
> > > > 
> > > > usb_role_switch_put() do this.
> > > > Yes, it's a function of usb_role class driver.
> > > > 
> > > > > 
> > > > > > > >    parent->driver is NULL at this time.
> > > > > > >
> > > > > > > What is dev at this point?  And what is dev.parent?  And what did
> > > > > > > dev.parent->driver used to be before it was set to NULL?
> > > > > >
> > > > > > Here sw->dev is usb-role-switch device. sw->dev.parent is ci_hdrc.0 device.
> > > > > > sw->dev.parent->driver was ci_hdrc.
> > > > > 
> > > > > Which is now gone, right.  I understand.
> > > > > 
> > > > > Let's see what Heikki has to say.
> > > > > 
> > > > > However, assuming he wants to continue misusing the driver model in this
> > > > > way, what you should do is add a new field to sw, where you will store
> > > > > sw->dev.parent->driver.owner at the time of the try_module_get() call
> > > > > (but only if the call succeeds!).  Then when the module_put() call runs,
> > > > > have it use the value stored in this new field instead of dereferencing
> > > > > sw->dev.parent->driver.owner.
> > > > 
> > > > It sounds like a better solution. 
> > > > Thanks for the suggestion!
> > > 
> > > If there is a better way of doing this, then let's use it. I'm happy
> > > with what ever works.
> > > 
> > > The only requirement here is that we have some way of preventing the
> > > role switch provider from being unloaded while it's being used.
> > 
> > Why?  What defines "being used"?
> 
> It is "being used" when something (user) acquires reference to the
> role switch that it provides. The "user" is in most cases USB Type-C
> port driver - what ever knows the role the port needs to be in.
> 
> USB role switch is meant to act as a "resource" like any other. So
> when you acquire for example a GPIO, the gpiodev driver is pinned down
> by calling module_get() just like this driver is doing to the switch
> provider.

So again, if the hardware is present in the system, the module reference
count will always be increased and can never be removed no matter what a
user does?  That feels wrong if so.

> > Any module should be able to be removed any time, unless there is a
> > "code" requirement of it being present.  The driver model structures
> > should make this possible if used properly.  Trying to much around in
> > various parent devices and the drivers bound to parents should NEVER be
> > done as happens here, sorry I missed that in the review process.
> 
> If this is not something that this kind of device class should be
> doing, then let's remove the whole thing. But if that is the case,
> then shouldn't we remove that from all the other bus and device class
> drivers as well?

I started to remove it many years ago, but then something prevented that
as there was actually some valid uses, but I can't remember at the
moment.  Try taking it out and see what happens!  :)

Sorry, I don't have the time in the near future to work on this...

greg k-h

  reply	other threads:[~2024-01-18 14:54 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-12  8:01 [PATCH] usb: roles: try to get/put all relevant modules Xu Yang
2024-01-12  8:24 ` Greg KH
2024-01-12  8:26   ` Greg KH
2024-01-12  9:28     ` [EXT] " Xu Yang
2024-01-12 13:52       ` Greg KH
2024-01-15  3:02         ` Xu Yang
2024-01-15  6:54           ` Greg KH
2024-01-15 16:31           ` Alan Stern
2024-01-16  5:44             ` Xu Yang
2024-01-16 16:03               ` Alan Stern
2024-01-17  5:57                 ` Xu Yang
2024-01-18  9:22                   ` Heikki Krogerus
2024-01-18  9:53                     ` Greg KH
2024-01-18 12:38                       ` Heikki Krogerus
2024-01-18 14:54                         ` Greg KH [this message]
2024-01-18 15:28                           ` Alan Stern
2024-01-18 15:52                             ` Xu Yang
2024-01-18 19:21                               ` Alan Stern
2024-01-19  8:18                                 ` Xu Yang
2024-01-19 13:21                                   ` Heikki Krogerus
2024-01-19 14:53                                   ` Alan Stern
2024-01-19 11:13                           ` Xu Yang
2024-01-19 15:00                             ` Alan Stern
2024-01-19 15:23                               ` Xu Yang
2024-01-19 16:22                                 ` Alan Stern
2024-01-22  2:32                                   ` Xu Yang
2024-01-18 15:29                     ` Xu Yang
2024-01-14 12:25 ` Greg KH
2024-01-14 23:06 ` kernel test robot
2024-01-15  2:12 ` kernel test robot

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=2024011842-harpist-password-b965@gregkh \
    --to=gregkh@linuxfoundation.org \
    --cc=benjamin.tissoires@redhat.com \
    --cc=hdegoede@redhat.com \
    --cc=heikki.krogerus@linux.intel.com \
    --cc=ivan.orlov0322@gmail.com \
    --cc=jun.li@nxp.com \
    --cc=linux-imx@nxp.com \
    --cc=linux-usb@vger.kernel.org \
    --cc=stern@rowland.harvard.edu \
    --cc=xu.yang_2@nxp.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox