diff mbox

[v2] PM / sleep: prohibit devices probing during suspend/hibernation

Message ID 1445288064-25299-1-git-send-email-grygorii.strashko@ti.com (mailing list archive)
State Changes Requested, archived
Headers show

Commit Message

Grygorii Strashko Oct. 19, 2015, 8:54 p.m. UTC
It is unsafe [1] if probing of devices will happen during suspend or
hibernation and system behavior will be unpredictable in this case
(for example: after successful probe the device potentially has a different
 set of PM callbacks than before [2]).
So, let's prohibit device's probing in dpm_prepare() and defer their
probes instead. The normal behavior will be restored in dpm_complete().

This patch introduces new DD core APIs:
 device_defer_all_probes_enable()
   It will disable probing of devices and defer their probes.
 device_defer_all_probes_disable()
   It will restore normal behavior and trigger re-probing of deferred
   devices.

[1] https://lkml.org/lkml/2015/9/11/554
[2] https://lkml.org/lkml/2015/9/15/1039
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
Cc: Thierry Reding <thierry.reding@gmail.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
Changes in v2:
- DD core API device_defer_all_probes(bool enable) split on two
  void device_defer_all_probes_enable(void);
  void device_defer_all_probes_disable(void);
- more comments added

Link on v1:
- https://lkml.org/lkml/2015/10/8/681

 drivers/base/base.h       |  2 ++
 drivers/base/dd.c         | 48 ++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/base/power/main.c | 17 +++++++++++++++++
 3 files changed, 66 insertions(+), 1 deletion(-)

Comments

Rafael J. Wysocki Nov. 2, 2015, 1:25 a.m. UTC | #1
On Monday, October 19, 2015 11:54:24 PM Grygorii Strashko wrote:
> It is unsafe [1] if probing of devices will happen during suspend or
> hibernation and system behavior will be unpredictable in this case
> (for example: after successful probe the device potentially has a different
>  set of PM callbacks than before [2]).
> So, let's prohibit device's probing in dpm_prepare() and defer their
> probes instead. The normal behavior will be restored in dpm_complete().
> 
> This patch introduces new DD core APIs:
>  device_defer_all_probes_enable()
>    It will disable probing of devices and defer their probes.
>  device_defer_all_probes_disable()
>    It will restore normal behavior and trigger re-probing of deferred
>    devices.
> 
> [1] https://lkml.org/lkml/2015/9/11/554
> [2] https://lkml.org/lkml/2015/9/15/1039
> Cc: Alan Stern <stern@rowland.harvard.edu>
> Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>

Greg, any objections against this one?

> ---
> Changes in v2:
> - DD core API device_defer_all_probes(bool enable) split on two
>   void device_defer_all_probes_enable(void);
>   void device_defer_all_probes_disable(void);
> - more comments added
> 
> Link on v1:
> - https://lkml.org/lkml/2015/10/8/681
> 
>  drivers/base/base.h       |  2 ++
>  drivers/base/dd.c         | 48 ++++++++++++++++++++++++++++++++++++++++++++++-
>  drivers/base/power/main.c | 17 +++++++++++++++++
>  3 files changed, 66 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/base/base.h b/drivers/base/base.h
> index 1782f3a..c332b68 100644
> --- a/drivers/base/base.h
> +++ b/drivers/base/base.h
> @@ -131,6 +131,8 @@ extern void device_remove_groups(struct device *dev,
>  extern char *make_class_name(const char *name, struct kobject *kobj);
>  
>  extern int devres_release_all(struct device *dev);
> +extern void device_defer_all_probes_enable(void);
> +extern void device_defer_all_probes_disable(void);
>  
>  /* /sys/devices directory */
>  extern struct kset *devices_kset;
> diff --git a/drivers/base/dd.c b/drivers/base/dd.c
> index be0eb46..b8d9e70 100644
> --- a/drivers/base/dd.c
> +++ b/drivers/base/dd.c
> @@ -55,6 +55,13 @@ static struct workqueue_struct *deferred_wq;
>  static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
>  
>  /*
> + * In some cases, like suspend to RAM or hibernation, It might be reasonable
> + * to prohibit probing of devices as it could be unsafe.
> + * Once defer_all_probes is true all drivers probes will be forcibly deferred.
> + */
> +static bool defer_all_probes;
> +
> +/*
>   * deferred_probe_work_func() - Retry probing devices in the active list.
>   */
>  static void deferred_probe_work_func(struct work_struct *work)
> @@ -172,6 +179,30 @@ static void driver_deferred_probe_trigger(void)
>  }
>  
>  /**
> + * device_defer_all_probes_enable() - Enable deferring of device's probes
> + *
> + *	It will disable probing of devices and defer their probes.
> + */
> +void device_defer_all_probes_enable(void)
> +{
> +	defer_all_probes = true;
> +	/* sync with probes to avoid races. */
> +	wait_for_device_probe();
> +}
> +
> +/**
> + * device_defer_all_probes_disable() - Disable deferring of device's probes
> + *
> + *	It will restore normal behavior and trigger re-probing of deferred
> + * devices.
> + */
> +void device_defer_all_probes_disable(void)
> +{
> +	defer_all_probes = false;
> +	driver_deferred_probe_trigger();
> +}
> +
> +/**
>   * deferred_probe_initcall() - Enable probing of deferred devices
>   *
>   * We don't want to get in the way when the bulk of drivers are getting probed.
> @@ -277,9 +308,20 @@ static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
>  
>  static int really_probe(struct device *dev, struct device_driver *drv)
>  {
> -	int ret = 0;
> +	int ret = -EPROBE_DEFER;
>  	int local_trigger_count = atomic_read(&deferred_trigger_count);
>  
> +	if (defer_all_probes) {
> +		/*
> +		 * Value of defer_all_probes can be set only by
> +		 * device_defer_all_probes_enable() which, in turn, will call
> +		 * wait_for_device_probe() right after that to avoid any races.
> +		 */
> +		dev_dbg(dev, "Driver %s force probe deferral\n", drv->name);
> +		driver_deferred_probe_add(dev);
> +		return ret;
> +	}
> +
>  	atomic_inc(&probe_count);
>  	pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
>  		 drv->bus->name, __func__, drv->name, dev_name(dev));
> @@ -391,6 +433,10 @@ int driver_probe_done(void)
>   */
>  void wait_for_device_probe(void)
>  {
> +	/* wait for the deferred probe workqueue to finish */
> +	if (driver_deferred_probe_enable)
> +		flush_workqueue(deferred_wq);
> +
>  	/* wait for the known devices to complete their probing */
>  	wait_event(probe_waitqueue, atomic_read(&probe_count) == 0);
>  	async_synchronize_full();
> diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
> index 1710c26..eeb2bb7 100644
> --- a/drivers/base/power/main.c
> +++ b/drivers/base/power/main.c
> @@ -963,6 +963,9 @@ void dpm_complete(pm_message_t state)
>  	}
>  	list_splice(&list, &dpm_list);
>  	mutex_unlock(&dpm_list_mtx);
> +
> +	/* Allow device probing and trigger re-probing of deferred devices */
> +	device_defer_all_probes_disable();
>  	trace_suspend_resume(TPS("dpm_complete"), state.event, false);
>  }
>  
> @@ -1624,6 +1627,20 @@ int dpm_prepare(pm_message_t state)
>  	trace_suspend_resume(TPS("dpm_prepare"), state.event, true);
>  	might_sleep();
>  
> +	/*
> +	 * Give a chance for the known devices to complete their probes, before
> +	 * disable probing of devices. This sync point is important at least
> +	 * at boot time + hibernation restore.
> +	 */
> +	wait_for_device_probe();
> +	/*
> +	 * It is unsafe if probing of devices will happen during suspend or
> +	 * hibernation and system behavior will be unpredictable in this case.
> +	 * So, let's prohibit device's probing here and defer their probes
> +	 * instead. The normal behavior will be restored in dpm_complete().
> +	 */
> +	device_defer_all_probes_enable();
> +
>  	mutex_lock(&dpm_list_mtx);
>  	while (!list_empty(&dpm_list)) {
>  		struct device *dev = to_device(dpm_list.next);
> 

Thanks,
Rafael

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Pavel Machek Nov. 5, 2015, 10:19 p.m. UTC | #2
On Mon 2015-10-19 23:54:24, Grygorii Strashko wrote:
> It is unsafe [1] if probing of devices will happen during suspend or
> hibernation and system behavior will be unpredictable in this case
> (for example: after successful probe the device potentially has a different
>  set of PM callbacks than before [2]).
> So, let's prohibit device's probing in dpm_prepare() and defer their
> probes instead. The normal behavior will be restored in dpm_complete().
> 
> This patch introduces new DD core APIs:
>  device_defer_all_probes_enable()
>    It will disable probing of devices and defer their probes.
>  device_defer_all_probes_disable()
>    It will restore normal behavior and trigger re-probing of deferred
>    devices.
> 
> [1] https://lkml.org/lkml/2015/9/11/554
> [2] https://lkml.org/lkml/2015/9/15/1039
> Cc: Alan Stern <stern@rowland.harvard.edu>
> Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
> ---
> Changes in v2:
> - DD core API device_defer_all_probes(bool enable) split on two
>   void device_defer_all_probes_enable(void);
>   void device_defer_all_probes_disable(void);
> - more comments added
> 
> Link on v1:
> - https://lkml.org/lkml/2015/10/8/681
> 
>  drivers/base/base.h       |  2 ++
>  drivers/base/dd.c         | 48 ++++++++++++++++++++++++++++++++++++++++++++++-
>  drivers/base/power/main.c | 17 +++++++++++++++++
>  3 files changed, 66 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/base/base.h b/drivers/base/base.h
> index 1782f3a..c332b68 100644
> --- a/drivers/base/base.h
> +++ b/drivers/base/base.h
> @@ -131,6 +131,8 @@ extern void device_remove_groups(struct device *dev,
>  extern char *make_class_name(const char *name, struct kobject *kobj);
>  
>  extern int devres_release_all(struct device *dev);
> +extern void device_defer_all_probes_enable(void);
> +extern void device_defer_all_probes_disable(void);
>  
>  /* /sys/devices directory */
>  extern struct kset *devices_kset;
> diff --git a/drivers/base/dd.c b/drivers/base/dd.c
> index be0eb46..b8d9e70 100644
> --- a/drivers/base/dd.c
> +++ b/drivers/base/dd.c
> @@ -55,6 +55,13 @@ static struct workqueue_struct *deferred_wq;
>  static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
>  
>  /*
> + * In some cases, like suspend to RAM or hibernation, It might be reasonable
> + * to prohibit probing of devices as it could be unsafe.
> + * Once defer_all_probes is true all drivers probes will be forcibly deferred.
> + */
> +static bool defer_all_probes;
> +
> +/*
>   * deferred_probe_work_func() - Retry probing devices in the active list.
>   */
>  static void deferred_probe_work_func(struct work_struct *work)
> @@ -172,6 +179,30 @@ static void driver_deferred_probe_trigger(void)
>  }
>  
>  /**
> + * device_defer_all_probes_enable() - Enable deferring of device's probes
> + *
> + *	It will disable probing of devices and defer their probes.
> + */
> +void device_defer_all_probes_enable(void)
> +{
> +	defer_all_probes = true;
> +	/* sync with probes to avoid races. */
> +	wait_for_device_probe();
> +}

device_pause_probing()?

> +/**
> + * device_defer_all_probes_disable() - Disable deferring of device's probes
> + *
> + *	It will restore normal behavior and trigger re-probing of deferred
> + * devices.
> + */

Hmm. This is not quite a double negative... but it sounds like one.

device_restart_probing()?

Thanks,
									Pavel
Rafael J. Wysocki Nov. 5, 2015, 10:38 p.m. UTC | #3
On Monday, November 02, 2015 02:25:00 AM Rafael J. Wysocki wrote:
> On Monday, October 19, 2015 11:54:24 PM Grygorii Strashko wrote:
> > It is unsafe [1] if probing of devices will happen during suspend or
> > hibernation and system behavior will be unpredictable in this case
> > (for example: after successful probe the device potentially has a different
> >  set of PM callbacks than before [2]).
> > So, let's prohibit device's probing in dpm_prepare() and defer their
> > probes instead. The normal behavior will be restored in dpm_complete().
> > 
> > This patch introduces new DD core APIs:
> >  device_defer_all_probes_enable()
> >    It will disable probing of devices and defer their probes.
> >  device_defer_all_probes_disable()
> >    It will restore normal behavior and trigger re-probing of deferred
> >    devices.
> > 
> > [1] https://lkml.org/lkml/2015/9/11/554
> > [2] https://lkml.org/lkml/2015/9/15/1039
> > Cc: Alan Stern <stern@rowland.harvard.edu>
> > Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
> > Cc: Thierry Reding <thierry.reding@gmail.com>
> > Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
> 
> Greg, any objections against this one?

Greg, if this isn't problematic, I'd still like to take it for v4.4.

Any chance you can have a look at it?

> > ---
> > Changes in v2:
> > - DD core API device_defer_all_probes(bool enable) split on two
> >   void device_defer_all_probes_enable(void);
> >   void device_defer_all_probes_disable(void);
> > - more comments added
> > 
> > Link on v1:
> > - https://lkml.org/lkml/2015/10/8/681
> > 
> >  drivers/base/base.h       |  2 ++
> >  drivers/base/dd.c         | 48 ++++++++++++++++++++++++++++++++++++++++++++++-
> >  drivers/base/power/main.c | 17 +++++++++++++++++
> >  3 files changed, 66 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/base/base.h b/drivers/base/base.h
> > index 1782f3a..c332b68 100644
> > --- a/drivers/base/base.h
> > +++ b/drivers/base/base.h
> > @@ -131,6 +131,8 @@ extern void device_remove_groups(struct device *dev,
> >  extern char *make_class_name(const char *name, struct kobject *kobj);
> >  
> >  extern int devres_release_all(struct device *dev);
> > +extern void device_defer_all_probes_enable(void);
> > +extern void device_defer_all_probes_disable(void);
> >  
> >  /* /sys/devices directory */
> >  extern struct kset *devices_kset;
> > diff --git a/drivers/base/dd.c b/drivers/base/dd.c
> > index be0eb46..b8d9e70 100644
> > --- a/drivers/base/dd.c
> > +++ b/drivers/base/dd.c
> > @@ -55,6 +55,13 @@ static struct workqueue_struct *deferred_wq;
> >  static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
> >  
> >  /*
> > + * In some cases, like suspend to RAM or hibernation, It might be reasonable
> > + * to prohibit probing of devices as it could be unsafe.
> > + * Once defer_all_probes is true all drivers probes will be forcibly deferred.
> > + */
> > +static bool defer_all_probes;
> > +
> > +/*
> >   * deferred_probe_work_func() - Retry probing devices in the active list.
> >   */
> >  static void deferred_probe_work_func(struct work_struct *work)
> > @@ -172,6 +179,30 @@ static void driver_deferred_probe_trigger(void)
> >  }
> >  
> >  /**
> > + * device_defer_all_probes_enable() - Enable deferring of device's probes
> > + *
> > + *	It will disable probing of devices and defer their probes.
> > + */
> > +void device_defer_all_probes_enable(void)
> > +{
> > +	defer_all_probes = true;
> > +	/* sync with probes to avoid races. */
> > +	wait_for_device_probe();
> > +}
> > +
> > +/**
> > + * device_defer_all_probes_disable() - Disable deferring of device's probes
> > + *
> > + *	It will restore normal behavior and trigger re-probing of deferred
> > + * devices.
> > + */
> > +void device_defer_all_probes_disable(void)
> > +{
> > +	defer_all_probes = false;
> > +	driver_deferred_probe_trigger();
> > +}
> > +
> > +/**
> >   * deferred_probe_initcall() - Enable probing of deferred devices
> >   *
> >   * We don't want to get in the way when the bulk of drivers are getting probed.
> > @@ -277,9 +308,20 @@ static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
> >  
> >  static int really_probe(struct device *dev, struct device_driver *drv)
> >  {
> > -	int ret = 0;
> > +	int ret = -EPROBE_DEFER;
> >  	int local_trigger_count = atomic_read(&deferred_trigger_count);
> >  
> > +	if (defer_all_probes) {
> > +		/*
> > +		 * Value of defer_all_probes can be set only by
> > +		 * device_defer_all_probes_enable() which, in turn, will call
> > +		 * wait_for_device_probe() right after that to avoid any races.
> > +		 */
> > +		dev_dbg(dev, "Driver %s force probe deferral\n", drv->name);
> > +		driver_deferred_probe_add(dev);
> > +		return ret;
> > +	}
> > +
> >  	atomic_inc(&probe_count);
> >  	pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
> >  		 drv->bus->name, __func__, drv->name, dev_name(dev));
> > @@ -391,6 +433,10 @@ int driver_probe_done(void)
> >   */
> >  void wait_for_device_probe(void)
> >  {
> > +	/* wait for the deferred probe workqueue to finish */
> > +	if (driver_deferred_probe_enable)
> > +		flush_workqueue(deferred_wq);
> > +
> >  	/* wait for the known devices to complete their probing */
> >  	wait_event(probe_waitqueue, atomic_read(&probe_count) == 0);
> >  	async_synchronize_full();
> > diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
> > index 1710c26..eeb2bb7 100644
> > --- a/drivers/base/power/main.c
> > +++ b/drivers/base/power/main.c
> > @@ -963,6 +963,9 @@ void dpm_complete(pm_message_t state)
> >  	}
> >  	list_splice(&list, &dpm_list);
> >  	mutex_unlock(&dpm_list_mtx);
> > +
> > +	/* Allow device probing and trigger re-probing of deferred devices */
> > +	device_defer_all_probes_disable();
> >  	trace_suspend_resume(TPS("dpm_complete"), state.event, false);
> >  }
> >  
> > @@ -1624,6 +1627,20 @@ int dpm_prepare(pm_message_t state)
> >  	trace_suspend_resume(TPS("dpm_prepare"), state.event, true);
> >  	might_sleep();
> >  
> > +	/*
> > +	 * Give a chance for the known devices to complete their probes, before
> > +	 * disable probing of devices. This sync point is important at least
> > +	 * at boot time + hibernation restore.
> > +	 */
> > +	wait_for_device_probe();
> > +	/*
> > +	 * It is unsafe if probing of devices will happen during suspend or
> > +	 * hibernation and system behavior will be unpredictable in this case.
> > +	 * So, let's prohibit device's probing here and defer their probes
> > +	 * instead. The normal behavior will be restored in dpm_complete().
> > +	 */
> > +	device_defer_all_probes_enable();
> > +
> >  	mutex_lock(&dpm_list_mtx);
> >  	while (!list_empty(&dpm_list)) {
> >  		struct device *dev = to_device(dpm_list.next);
> > 
> 

Thanks,
Rafael

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Greg Kroah-Hartman Nov. 6, 2015, 12:09 a.m. UTC | #4
On Thu, Nov 05, 2015 at 11:38:23PM +0100, Rafael J. Wysocki wrote:
> On Monday, November 02, 2015 02:25:00 AM Rafael J. Wysocki wrote:
> > On Monday, October 19, 2015 11:54:24 PM Grygorii Strashko wrote:
> > > It is unsafe [1] if probing of devices will happen during suspend or
> > > hibernation and system behavior will be unpredictable in this case
> > > (for example: after successful probe the device potentially has a different
> > >  set of PM callbacks than before [2]).
> > > So, let's prohibit device's probing in dpm_prepare() and defer their
> > > probes instead. The normal behavior will be restored in dpm_complete().
> > > 
> > > This patch introduces new DD core APIs:
> > >  device_defer_all_probes_enable()
> > >    It will disable probing of devices and defer their probes.
> > >  device_defer_all_probes_disable()
> > >    It will restore normal behavior and trigger re-probing of deferred
> > >    devices.
> > > 
> > > [1] https://lkml.org/lkml/2015/9/11/554
> > > [2] https://lkml.org/lkml/2015/9/15/1039
> > > Cc: Alan Stern <stern@rowland.harvard.edu>
> > > Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
> > > Cc: Thierry Reding <thierry.reding@gmail.com>
> > > Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
> > 
> > Greg, any objections against this one?
> 
> Greg, if this isn't problematic, I'd still like to take it for v4.4.

What?  The merge window for new stuff closed a few weeks ago, how can
you add this for 4.4 when it needs to be in linux-next for a while
first?

I don't have any real objection to it, but I don't see how defering
probing until "later" really solves anything, no one should be "changing
pm callbacks" after some other probe succeeds, that sounds like someone
just wants to have a broken system.

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki Nov. 6, 2015, 12:13 a.m. UTC | #5
On Thursday, November 05, 2015 11:19:03 PM Pavel Machek wrote:
> On Mon 2015-10-19 23:54:24, Grygorii Strashko wrote:
> > It is unsafe [1] if probing of devices will happen during suspend or
> > hibernation and system behavior will be unpredictable in this case
> > (for example: after successful probe the device potentially has a different
> >  set of PM callbacks than before [2]).
> > So, let's prohibit device's probing in dpm_prepare() and defer their
> > probes instead. The normal behavior will be restored in dpm_complete().
> > 
> > This patch introduces new DD core APIs:
> >  device_defer_all_probes_enable()
> >    It will disable probing of devices and defer their probes.
> >  device_defer_all_probes_disable()
> >    It will restore normal behavior and trigger re-probing of deferred
> >    devices.
> > 
> > [1] https://lkml.org/lkml/2015/9/11/554
> > [2] https://lkml.org/lkml/2015/9/15/1039
> > Cc: Alan Stern <stern@rowland.harvard.edu>
> > Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
> > Cc: Thierry Reding <thierry.reding@gmail.com>
> > Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
> > ---
> > Changes in v2:
> > - DD core API device_defer_all_probes(bool enable) split on two
> >   void device_defer_all_probes_enable(void);
> >   void device_defer_all_probes_disable(void);
> > - more comments added
> > 
> > Link on v1:
> > - https://lkml.org/lkml/2015/10/8/681
> > 
> >  drivers/base/base.h       |  2 ++
> >  drivers/base/dd.c         | 48 ++++++++++++++++++++++++++++++++++++++++++++++-
> >  drivers/base/power/main.c | 17 +++++++++++++++++
> >  3 files changed, 66 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/base/base.h b/drivers/base/base.h
> > index 1782f3a..c332b68 100644
> > --- a/drivers/base/base.h
> > +++ b/drivers/base/base.h
> > @@ -131,6 +131,8 @@ extern void device_remove_groups(struct device *dev,
> >  extern char *make_class_name(const char *name, struct kobject *kobj);
> >  
> >  extern int devres_release_all(struct device *dev);
> > +extern void device_defer_all_probes_enable(void);
> > +extern void device_defer_all_probes_disable(void);
> >  
> >  /* /sys/devices directory */
> >  extern struct kset *devices_kset;
> > diff --git a/drivers/base/dd.c b/drivers/base/dd.c
> > index be0eb46..b8d9e70 100644
> > --- a/drivers/base/dd.c
> > +++ b/drivers/base/dd.c
> > @@ -55,6 +55,13 @@ static struct workqueue_struct *deferred_wq;
> >  static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
> >  
> >  /*
> > + * In some cases, like suspend to RAM or hibernation, It might be reasonable
> > + * to prohibit probing of devices as it could be unsafe.
> > + * Once defer_all_probes is true all drivers probes will be forcibly deferred.
> > + */
> > +static bool defer_all_probes;
> > +
> > +/*
> >   * deferred_probe_work_func() - Retry probing devices in the active list.
> >   */
> >  static void deferred_probe_work_func(struct work_struct *work)
> > @@ -172,6 +179,30 @@ static void driver_deferred_probe_trigger(void)
> >  }
> >  
> >  /**
> > + * device_defer_all_probes_enable() - Enable deferring of device's probes
> > + *
> > + *	It will disable probing of devices and defer their probes.
> > + */
> > +void device_defer_all_probes_enable(void)
> > +{
> > +	defer_all_probes = true;
> > +	/* sync with probes to avoid races. */
> > +	wait_for_device_probe();
> > +}
> 
> device_pause_probing()?
> 
> > +/**
> > + * device_defer_all_probes_disable() - Disable deferring of device's probes
> > + *
> > + *	It will restore normal behavior and trigger re-probing of deferred
> > + * devices.
> > + */
> 
> Hmm. This is not quite a double negative... but it sounds like one.
> 
> device_restart_probing()?

I _start/_stop would be fine by me too.

Thanks,
Rafael

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki Nov. 6, 2015, 2:04 a.m. UTC | #6
On Thursday, November 05, 2015 04:09:57 PM Greg Kroah-Hartman wrote:
> On Thu, Nov 05, 2015 at 11:38:23PM +0100, Rafael J. Wysocki wrote:
> > On Monday, November 02, 2015 02:25:00 AM Rafael J. Wysocki wrote:
> > > On Monday, October 19, 2015 11:54:24 PM Grygorii Strashko wrote:
> > > > It is unsafe [1] if probing of devices will happen during suspend or
> > > > hibernation and system behavior will be unpredictable in this case
> > > > (for example: after successful probe the device potentially has a different
> > > >  set of PM callbacks than before [2]).
> > > > So, let's prohibit device's probing in dpm_prepare() and defer their
> > > > probes instead. The normal behavior will be restored in dpm_complete().
> > > > 
> > > > This patch introduces new DD core APIs:
> > > >  device_defer_all_probes_enable()
> > > >    It will disable probing of devices and defer their probes.
> > > >  device_defer_all_probes_disable()
> > > >    It will restore normal behavior and trigger re-probing of deferred
> > > >    devices.
> > > > 
> > > > [1] https://lkml.org/lkml/2015/9/11/554
> > > > [2] https://lkml.org/lkml/2015/9/15/1039
> > > > Cc: Alan Stern <stern@rowland.harvard.edu>
> > > > Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
> > > > Cc: Thierry Reding <thierry.reding@gmail.com>
> > > > Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
> > > 
> > > Greg, any objections against this one?
> > 
> > Greg, if this isn't problematic, I'd still like to take it for v4.4.
> 
> What?  The merge window for new stuff closed a few weeks ago, how can
> you add this for 4.4 when it needs to be in linux-next for a while
> first?

Well, it's not really scary and it was posted way before the merge window,
but no one has had the time to look at it since then, apparently.

Of course, I can queue it up for the next release too.

> I don't have any real objection to it, but I don't see how defering
> probing until "later" really solves anything, no one should be "changing
> pm callbacks" after some other probe succeeds, that sounds like someone
> just wants to have a broken system.

This really is about preventing things from being probed during system
suspend/resume, because (successful) probing effectively changes the
set of PM callbacks for the probed device (the ones provided by the
driver are now available), so allowing it to happen during suspend/resume
is a bad idea (as you said).

This is just a safety measure to provide certain guarantee ("your callbacks
are not going to change in the middle of a suspend/resume sequence").

Thanks,
Rafael

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Greg Kroah-Hartman Nov. 6, 2015, 2:07 a.m. UTC | #7
On Fri, Nov 06, 2015 at 03:04:10AM +0100, Rafael J. Wysocki wrote:
> On Thursday, November 05, 2015 04:09:57 PM Greg Kroah-Hartman wrote:
> > On Thu, Nov 05, 2015 at 11:38:23PM +0100, Rafael J. Wysocki wrote:
> > > On Monday, November 02, 2015 02:25:00 AM Rafael J. Wysocki wrote:
> > > > On Monday, October 19, 2015 11:54:24 PM Grygorii Strashko wrote:
> > > > > It is unsafe [1] if probing of devices will happen during suspend or
> > > > > hibernation and system behavior will be unpredictable in this case
> > > > > (for example: after successful probe the device potentially has a different
> > > > >  set of PM callbacks than before [2]).
> > > > > So, let's prohibit device's probing in dpm_prepare() and defer their
> > > > > probes instead. The normal behavior will be restored in dpm_complete().
> > > > > 
> > > > > This patch introduces new DD core APIs:
> > > > >  device_defer_all_probes_enable()
> > > > >    It will disable probing of devices and defer their probes.
> > > > >  device_defer_all_probes_disable()
> > > > >    It will restore normal behavior and trigger re-probing of deferred
> > > > >    devices.
> > > > > 
> > > > > [1] https://lkml.org/lkml/2015/9/11/554
> > > > > [2] https://lkml.org/lkml/2015/9/15/1039
> > > > > Cc: Alan Stern <stern@rowland.harvard.edu>
> > > > > Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
> > > > > Cc: Thierry Reding <thierry.reding@gmail.com>
> > > > > Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
> > > > 
> > > > Greg, any objections against this one?
> > > 
> > > Greg, if this isn't problematic, I'd still like to take it for v4.4.
> > 
> > What?  The merge window for new stuff closed a few weeks ago, how can
> > you add this for 4.4 when it needs to be in linux-next for a while
> > first?
> 
> Well, it's not really scary and it was posted way before the merge window,
> but no one has had the time to look at it since then, apparently.
> 
> Of course, I can queue it up for the next release too.

That would be best, thanks.

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Grygorii Strashko Nov. 6, 2015, 9:58 a.m. UTC | #8
On 11/06/2015 02:13 AM, Rafael J. Wysocki wrote:
> On Thursday, November 05, 2015 11:19:03 PM Pavel Machek wrote:
>> On Mon 2015-10-19 23:54:24, Grygorii Strashko wrote:
>>> It is unsafe [1] if probing of devices will happen during suspend or
>>> hibernation and system behavior will be unpredictable in this case
>>> (for example: after successful probe the device potentially has a different
>>>   set of PM callbacks than before [2]).
>>> So, let's prohibit device's probing in dpm_prepare() and defer their
>>> probes instead. The normal behavior will be restored in dpm_complete().
>>>
>>> This patch introduces new DD core APIs:
>>>   device_defer_all_probes_enable()
>>>     It will disable probing of devices and defer their probes.
>>>   device_defer_all_probes_disable()
>>>     It will restore normal behavior and trigger re-probing of deferred
>>>     devices.
>>>
>>> [1] https://lkml.org/lkml/2015/9/11/554
>>> [2] https://lkml.org/lkml/2015/9/15/1039
>>> Cc: Alan Stern <stern@rowland.harvard.edu>
>>> Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
>>> Cc: Thierry Reding <thierry.reding@gmail.com>
>>> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
>>> ---
>>> Changes in v2:
>>> - DD core API device_defer_all_probes(bool enable) split on two
>>>    void device_defer_all_probes_enable(void);
>>>    void device_defer_all_probes_disable(void);
>>> - more comments added
>>>
>>> Link on v1:
>>> - https://lkml.org/lkml/2015/10/8/681
>>>
>>>   drivers/base/base.h       |  2 ++
>>>   drivers/base/dd.c         | 48 ++++++++++++++++++++++++++++++++++++++++++++++-
>>>   drivers/base/power/main.c | 17 +++++++++++++++++
>>>   3 files changed, 66 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/base/base.h b/drivers/base/base.h
>>> index 1782f3a..c332b68 100644
>>> --- a/drivers/base/base.h
>>> +++ b/drivers/base/base.h
>>> @@ -131,6 +131,8 @@ extern void device_remove_groups(struct device *dev,
>>>   extern char *make_class_name(const char *name, struct kobject *kobj);
>>>
>>>   extern int devres_release_all(struct device *dev);
>>> +extern void device_defer_all_probes_enable(void);
>>> +extern void device_defer_all_probes_disable(void);
>>>
>>>   /* /sys/devices directory */
>>>   extern struct kset *devices_kset;
>>> diff --git a/drivers/base/dd.c b/drivers/base/dd.c
>>> index be0eb46..b8d9e70 100644
>>> --- a/drivers/base/dd.c
>>> +++ b/drivers/base/dd.c
>>> @@ -55,6 +55,13 @@ static struct workqueue_struct *deferred_wq;
>>>   static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
>>>
>>>   /*
>>> + * In some cases, like suspend to RAM or hibernation, It might be reasonable
>>> + * to prohibit probing of devices as it could be unsafe.
>>> + * Once defer_all_probes is true all drivers probes will be forcibly deferred.
>>> + */
>>> +static bool defer_all_probes;
>>> +
>>> +/*
>>>    * deferred_probe_work_func() - Retry probing devices in the active list.
>>>    */
>>>   static void deferred_probe_work_func(struct work_struct *work)
>>> @@ -172,6 +179,30 @@ static void driver_deferred_probe_trigger(void)
>>>   }
>>>
>>>   /**
>>> + * device_defer_all_probes_enable() - Enable deferring of device's probes
>>> + *
>>> + *	It will disable probing of devices and defer their probes.
>>> + */
>>> +void device_defer_all_probes_enable(void)
>>> +{
>>> +	defer_all_probes = true;
>>> +	/* sync with probes to avoid races. */
>>> +	wait_for_device_probe();
>>> +}
>>
>> device_pause_probing()?

device_stop_probing(). Right?

>>
>>> +/**
>>> + * device_defer_all_probes_disable() - Disable deferring of device's probes
>>> + *
>>> + *	It will restore normal behavior and trigger re-probing of deferred
>>> + * devices.
>>> + */

device_start_probing(). Right?

>>
>> Hmm. This is not quite a double negative... but it sounds like one.
>>
>> device_restart_probing()?
>
> I _start/_stop would be fine by me too.

Ok. So do I need rename/resend it again?
Probably, I'll need to wait for -rc1 before resending.
Rafael J. Wysocki Nov. 6, 2015, 10:44 p.m. UTC | #9
On Friday, November 06, 2015 11:58:40 AM Grygorii Strashko wrote:
> On 11/06/2015 02:13 AM, Rafael J. Wysocki wrote:
> > On Thursday, November 05, 2015 11:19:03 PM Pavel Machek wrote:
> >> On Mon 2015-10-19 23:54:24, Grygorii Strashko wrote:
> >>> It is unsafe [1] if probing of devices will happen during suspend or
> >>> hibernation and system behavior will be unpredictable in this case
> >>> (for example: after successful probe the device potentially has a different
> >>>   set of PM callbacks than before [2]).
> >>> So, let's prohibit device's probing in dpm_prepare() and defer their
> >>> probes instead. The normal behavior will be restored in dpm_complete().
> >>>
> >>> This patch introduces new DD core APIs:
> >>>   device_defer_all_probes_enable()
> >>>     It will disable probing of devices and defer their probes.
> >>>   device_defer_all_probes_disable()
> >>>     It will restore normal behavior and trigger re-probing of deferred
> >>>     devices.
> >>>
> >>> [1] https://lkml.org/lkml/2015/9/11/554
> >>> [2] https://lkml.org/lkml/2015/9/15/1039
> >>> Cc: Alan Stern <stern@rowland.harvard.edu>
> >>> Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
> >>> Cc: Thierry Reding <thierry.reding@gmail.com>
> >>> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
> >>> ---
> >>> Changes in v2:
> >>> - DD core API device_defer_all_probes(bool enable) split on two
> >>>    void device_defer_all_probes_enable(void);
> >>>    void device_defer_all_probes_disable(void);
> >>> - more comments added
> >>>
> >>> Link on v1:
> >>> - https://lkml.org/lkml/2015/10/8/681
> >>>
> >>>   drivers/base/base.h       |  2 ++
> >>>   drivers/base/dd.c         | 48 ++++++++++++++++++++++++++++++++++++++++++++++-
> >>>   drivers/base/power/main.c | 17 +++++++++++++++++
> >>>   3 files changed, 66 insertions(+), 1 deletion(-)
> >>>
> >>> diff --git a/drivers/base/base.h b/drivers/base/base.h
> >>> index 1782f3a..c332b68 100644
> >>> --- a/drivers/base/base.h
> >>> +++ b/drivers/base/base.h
> >>> @@ -131,6 +131,8 @@ extern void device_remove_groups(struct device *dev,
> >>>   extern char *make_class_name(const char *name, struct kobject *kobj);
> >>>
> >>>   extern int devres_release_all(struct device *dev);
> >>> +extern void device_defer_all_probes_enable(void);
> >>> +extern void device_defer_all_probes_disable(void);
> >>>
> >>>   /* /sys/devices directory */
> >>>   extern struct kset *devices_kset;
> >>> diff --git a/drivers/base/dd.c b/drivers/base/dd.c
> >>> index be0eb46..b8d9e70 100644
> >>> --- a/drivers/base/dd.c
> >>> +++ b/drivers/base/dd.c
> >>> @@ -55,6 +55,13 @@ static struct workqueue_struct *deferred_wq;
> >>>   static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
> >>>
> >>>   /*
> >>> + * In some cases, like suspend to RAM or hibernation, It might be reasonable
> >>> + * to prohibit probing of devices as it could be unsafe.
> >>> + * Once defer_all_probes is true all drivers probes will be forcibly deferred.
> >>> + */
> >>> +static bool defer_all_probes;
> >>> +
> >>> +/*
> >>>    * deferred_probe_work_func() - Retry probing devices in the active list.
> >>>    */
> >>>   static void deferred_probe_work_func(struct work_struct *work)
> >>> @@ -172,6 +179,30 @@ static void driver_deferred_probe_trigger(void)
> >>>   }
> >>>
> >>>   /**
> >>> + * device_defer_all_probes_enable() - Enable deferring of device's probes
> >>> + *
> >>> + *	It will disable probing of devices and defer their probes.
> >>> + */
> >>> +void device_defer_all_probes_enable(void)
> >>> +{
> >>> +	defer_all_probes = true;
> >>> +	/* sync with probes to avoid races. */
> >>> +	wait_for_device_probe();
> >>> +}
> >>
> >> device_pause_probing()?
> 
> device_stop_probing(). Right?

Or device_block_probing()

> >>
> >>> +/**
> >>> + * device_defer_all_probes_disable() - Disable deferring of device's probes
> >>> + *
> >>> + *	It will restore normal behavior and trigger re-probing of deferred
> >>> + * devices.
> >>> + */
> 
> device_start_probing(). Right?

and device_unblock_probing()

> 
> >>
> >> Hmm. This is not quite a double negative... but it sounds like one.
> >>
> >> device_restart_probing()?
> >
> > I _start/_stop would be fine by me too.
> 
> Ok. So do I need rename/resend it again?

Yes, please.

> Probably, I'll need to wait for -rc1 before resending.

No, you don't.  Please resend when you're ready.

Thanks,
Rafael

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki Nov. 6, 2015, 10:45 p.m. UTC | #10
On Thursday, November 05, 2015 06:07:45 PM Greg Kroah-Hartman wrote:
> On Fri, Nov 06, 2015 at 03:04:10AM +0100, Rafael J. Wysocki wrote:
> > On Thursday, November 05, 2015 04:09:57 PM Greg Kroah-Hartman wrote:
> > > On Thu, Nov 05, 2015 at 11:38:23PM +0100, Rafael J. Wysocki wrote:
> > > > On Monday, November 02, 2015 02:25:00 AM Rafael J. Wysocki wrote:
> > > > > On Monday, October 19, 2015 11:54:24 PM Grygorii Strashko wrote:
> > > > > > It is unsafe [1] if probing of devices will happen during suspend or
> > > > > > hibernation and system behavior will be unpredictable in this case
> > > > > > (for example: after successful probe the device potentially has a different
> > > > > >  set of PM callbacks than before [2]).
> > > > > > So, let's prohibit device's probing in dpm_prepare() and defer their
> > > > > > probes instead. The normal behavior will be restored in dpm_complete().
> > > > > > 
> > > > > > This patch introduces new DD core APIs:
> > > > > >  device_defer_all_probes_enable()
> > > > > >    It will disable probing of devices and defer their probes.
> > > > > >  device_defer_all_probes_disable()
> > > > > >    It will restore normal behavior and trigger re-probing of deferred
> > > > > >    devices.
> > > > > > 
> > > > > > [1] https://lkml.org/lkml/2015/9/11/554
> > > > > > [2] https://lkml.org/lkml/2015/9/15/1039
> > > > > > Cc: Alan Stern <stern@rowland.harvard.edu>
> > > > > > Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
> > > > > > Cc: Thierry Reding <thierry.reding@gmail.com>
> > > > > > Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
> > > > > 
> > > > > Greg, any objections against this one?
> > > > 
> > > > Greg, if this isn't problematic, I'd still like to take it for v4.4.
> > > 
> > > What?  The merge window for new stuff closed a few weeks ago, how can
> > > you add this for 4.4 when it needs to be in linux-next for a while
> > > first?
> > 
> > Well, it's not really scary and it was posted way before the merge window,
> > but no one has had the time to look at it since then, apparently.
> > 
> > Of course, I can queue it up for the next release too.
> 
> That would be best, thanks.

OK

--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/base/base.h b/drivers/base/base.h
index 1782f3a..c332b68 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -131,6 +131,8 @@  extern void device_remove_groups(struct device *dev,
 extern char *make_class_name(const char *name, struct kobject *kobj);
 
 extern int devres_release_all(struct device *dev);
+extern void device_defer_all_probes_enable(void);
+extern void device_defer_all_probes_disable(void);
 
 /* /sys/devices directory */
 extern struct kset *devices_kset;
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index be0eb46..b8d9e70 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -55,6 +55,13 @@  static struct workqueue_struct *deferred_wq;
 static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
 
 /*
+ * In some cases, like suspend to RAM or hibernation, It might be reasonable
+ * to prohibit probing of devices as it could be unsafe.
+ * Once defer_all_probes is true all drivers probes will be forcibly deferred.
+ */
+static bool defer_all_probes;
+
+/*
  * deferred_probe_work_func() - Retry probing devices in the active list.
  */
 static void deferred_probe_work_func(struct work_struct *work)
@@ -172,6 +179,30 @@  static void driver_deferred_probe_trigger(void)
 }
 
 /**
+ * device_defer_all_probes_enable() - Enable deferring of device's probes
+ *
+ *	It will disable probing of devices and defer their probes.
+ */
+void device_defer_all_probes_enable(void)
+{
+	defer_all_probes = true;
+	/* sync with probes to avoid races. */
+	wait_for_device_probe();
+}
+
+/**
+ * device_defer_all_probes_disable() - Disable deferring of device's probes
+ *
+ *	It will restore normal behavior and trigger re-probing of deferred
+ * devices.
+ */
+void device_defer_all_probes_disable(void)
+{
+	defer_all_probes = false;
+	driver_deferred_probe_trigger();
+}
+
+/**
  * deferred_probe_initcall() - Enable probing of deferred devices
  *
  * We don't want to get in the way when the bulk of drivers are getting probed.
@@ -277,9 +308,20 @@  static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
 
 static int really_probe(struct device *dev, struct device_driver *drv)
 {
-	int ret = 0;
+	int ret = -EPROBE_DEFER;
 	int local_trigger_count = atomic_read(&deferred_trigger_count);
 
+	if (defer_all_probes) {
+		/*
+		 * Value of defer_all_probes can be set only by
+		 * device_defer_all_probes_enable() which, in turn, will call
+		 * wait_for_device_probe() right after that to avoid any races.
+		 */
+		dev_dbg(dev, "Driver %s force probe deferral\n", drv->name);
+		driver_deferred_probe_add(dev);
+		return ret;
+	}
+
 	atomic_inc(&probe_count);
 	pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
 		 drv->bus->name, __func__, drv->name, dev_name(dev));
@@ -391,6 +433,10 @@  int driver_probe_done(void)
  */
 void wait_for_device_probe(void)
 {
+	/* wait for the deferred probe workqueue to finish */
+	if (driver_deferred_probe_enable)
+		flush_workqueue(deferred_wq);
+
 	/* wait for the known devices to complete their probing */
 	wait_event(probe_waitqueue, atomic_read(&probe_count) == 0);
 	async_synchronize_full();
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 1710c26..eeb2bb7 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -963,6 +963,9 @@  void dpm_complete(pm_message_t state)
 	}
 	list_splice(&list, &dpm_list);
 	mutex_unlock(&dpm_list_mtx);
+
+	/* Allow device probing and trigger re-probing of deferred devices */
+	device_defer_all_probes_disable();
 	trace_suspend_resume(TPS("dpm_complete"), state.event, false);
 }
 
@@ -1624,6 +1627,20 @@  int dpm_prepare(pm_message_t state)
 	trace_suspend_resume(TPS("dpm_prepare"), state.event, true);
 	might_sleep();
 
+	/*
+	 * Give a chance for the known devices to complete their probes, before
+	 * disable probing of devices. This sync point is important at least
+	 * at boot time + hibernation restore.
+	 */
+	wait_for_device_probe();
+	/*
+	 * It is unsafe if probing of devices will happen during suspend or
+	 * hibernation and system behavior will be unpredictable in this case.
+	 * So, let's prohibit device's probing here and defer their probes
+	 * instead. The normal behavior will be restored in dpm_complete().
+	 */
+	device_defer_all_probes_enable();
+
 	mutex_lock(&dpm_list_mtx);
 	while (!list_empty(&dpm_list)) {
 		struct device *dev = to_device(dpm_list.next);