This patchset try to solve one deadlock problem which might be caused
by memory allocation with block I/O during runtime PM and block device
error handling path. Traditionly, the problem is addressed by passing
GFP_NOIO statically to mm, but that is not a effective solution, see
detailed description in patch 1's commit log.
This patch set introduces one process flag and trys to fix the deadlock
problem on block device/network device during runtime PM or usb bus reset.
The 1st one is the change on include/sched.h and mm.
The 2nd patch introduces the flag of memalloc_noio on 'dev_pm_info',
and pm_runtime_set_memalloc_noio(), so that PM Core can teach mm to not
allocate mm with GFP_IOFS during the runtime_resume callback only on
device with the flag set.
The following 2 patches apply the introduced pm_runtime_set_memalloc_noio()
to mark all devices as memalloc_noio_resume in the path from the block or
network device to the root device in device tree.
The last 2 patches are applied again PM and USB subsystem to demonstrate
how to use the introduced mechanism to fix the deadlock problem.
Change logs:
V4:
- patches from the 2nd to the 6th changed
- call pm_runtime_set_memalloc_noio() after device_add() as pointed
by Alan
- set PF_MEMALLOC_NOIO during runtime_suspend()
V3:
- patch 2/6 and 5/6 changed, see their commit log
- remove RFC from title since several guys have expressed that
it is a reasonable solution
V2:
- remove changes on 'may_writepage' and 'may_swap'(1/6)
- unset GFP_IOFS in try_to_free_pages() path(1/6)
- introduce pm_runtime_set_memalloc_noio()
- only apply the meachnism on block/network device and its ancestors
for runtime resume context
V1:
- take Minchan's change to avoid the check in alloc_page hot path
- change the helpers' style into save/restore as suggested by Alan
- memory allocation with no io in usb bus reset path for all devices
as suggested by Greg and Oliver
block/genhd.c | 9 +++++
drivers/base/power/runtime.c | 89 +++++++++++++++++++++++++++++++++++++++++-
drivers/usb/core/hub.c | 13 ++++++
include/linux/pm.h | 1 +
include/linux/pm_runtime.h | 3 ++
include/linux/sched.h | 10 +++++
mm/page_alloc.c | 10 ++++-
mm/vmscan.c | 12 ++++++
net/core/net-sysfs.c | 5 +++
Thanks,
--
Ming Lei
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
This patch introduces PF_MEMALLOC_NOIO on process flag('flags' field of
'struct task_struct'), so that the flag can be set by one task
to avoid doing I/O inside memory allocation in the task's context.
The patch trys to solve one deadlock problem caused by block device,
and the problem may happen at least in the below situations:
- during block device runtime resume, if memory allocation with
GFP_KERNEL is called inside runtime resume callback of any one
of its ancestors(or the block device itself), the deadlock may be
triggered inside the memory allocation since it might not complete
until the block device becomes active and the involed page I/O finishes.
The situation is pointed out first by Alan Stern. It is not a good
approach to convert all GFP_KERNEL[1] in the path into GFP_NOIO because
several subsystems may be involved(for example, PCI, USB and SCSI may
be involved for usb mass stoarage device, network devices involved too
in the iSCSI case)
- during block device runtime suspend, because runtime resume need
to wait for completion of concurrent runtime suspend.
- during error handling of usb mass storage deivce, USB bus reset
will be put on the device, so there shouldn't have any
memory allocation with GFP_KERNEL during USB bus reset, otherwise
the deadlock similar with above may be triggered. Unfortunately, any
usb device may include one mass storage interface in theory, so it
requires all usb interface drivers to handle the situation. In fact,
most usb drivers don't know how to handle bus reset on the device
and don't provide .pre_set() and .post_reset() callback at all, so
USB core has to unbind and bind driver for these devices. So it
is still not practical to resort to GFP_NOIO for solving the problem.
Also the introduced solution can be used by block subsystem or block
drivers too, for example, set the PF_MEMALLOC_NOIO flag before doing
actual I/O transfer.
It is not a good idea to convert all these GFP_KERNEL in the
affected path into GFP_NOIO because these functions doing that may be
implemented as library and will be called in many other contexts.
In fact, memalloc_noio() can convert some of current static GFP_NOIO
allocation into GFP_KERNEL back in other non-affected contexts, at least
almost all GFP_NOIO in USB subsystem can be converted into GFP_KERNEL
after applying the approach and make allocation with GFP_IO
only happen in runtime resume/bus reset/block I/O transfer contexts
generally.
[1], several GFP_KERNEL allocation examples in runtime resume path
- pci subsystem
acpi_os_allocate
<-acpi_ut_allocate
<-ACPI_ALLOCATE_ZEROED
<-acpi_evaluate_object
<-__acpi_bus_set_power
<-acpi_bus_set_power
<-acpi_pci_set_power_state
<-platform_pci_set_power_state
<-pci_platform_power_transition
<-__pci_complete_power_transition
<-pci_set_power_state
<-pci_restore_standard_config
<-pci_pm_runtime_resume
- usb subsystem
usb_get_status
<-finish_port_resume
<-usb_port_resume
<-generic_resume
<-usb_resume_device
<-usb_resume_both
<-usb_runtime_resume
- some individual usb drivers
usblp, uvc, gspca, most of dvb-usb-v2 media drivers, cpia2, az6007, ....
That is just what I have found. Unfortunately, this allocation can
only be found by human being now, and there should be many not found
since any function in the resume path(call tree) may allocate memory
with GFP_KERNEL.
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Oliver Neukum <redacted>
Cc: Jiri Kosina <redacted>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Mel Gorman <redacted>
Cc: KAMEZAWA Hiroyuki <redacted>
Cc: Michal Hocko <redacted>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: "Rafael J. Wysocki" <redacted>
Signed-off-by: Minchan Kim <minchan@kernel.org>
Signed-off-by: Ming Lei <redacted>
---
v4:
- fix comment
v3:
- no change
v2:
- remove changes on 'may_writepage' and 'may_swap' because that
isn't related with the patchset, and can't introduce I/O in
allocation path if GFP_IOFS is unset, so handing 'may_swap'
and may_writepage on GFP_NOIO or GFP_NOFS should be a
mm internal thing, and let mm guys deal with that, :-).
Looks clearing the two may_XXX flag only excludes dirty pages
and anon pages for relaiming, and the behaviour should be decided
by GFP FLAG, IMO.
- unset GFP_IOFS in try_to_free_pages() path since
alloc_page_buffers()
and dma_alloc_from_contiguous may drop into the path, as
pointed by KAMEZAWA Hiroyuki
v1:
- take Minchan's change to avoid the check in alloc_page hot
path
- change the helpers' style into save/restore as suggested by
Alan Stern
---
include/linux/sched.h | 10 ++++++++++
mm/page_alloc.c | 10 +++++++++-
mm/vmscan.c | 12 ++++++++++++
3 files changed, 31 insertions(+), 1 deletion(-)
@@ -2304,6 +2304,12 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,.gfp_mask=sc.gfp_mask,};+if(unlikely(memalloc_noio())){+gfp_mask&=~GFP_IOFS;+sc.gfp_mask=gfp_mask;+shrink.gfp_mask=sc.gfp_mask;+}+throttle_direct_reclaim(gfp_mask,zonelist,nodemask);/*
@@ -3304,6 +3310,12 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)};unsignedlongnr_slab_pages0,nr_slab_pages1;+if(unlikely(memalloc_noio())){+gfp_mask&=~GFP_IOFS;+sc.gfp_mask=gfp_mask;+shrink.gfp_mask=sc.gfp_mask;+}+cond_resched();/**WeneedtobeabletoallocatefromthereservesforRECLAIM_SWAP
--
1.7.9.5
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
The patch introduces the flag of memalloc_noio in 'struct dev_pm_info'
to help PM core to teach mm not allocating memory with GFP_KERNEL
flag for avoiding probable deadlock.
As explained in the comment, any GFP_KERNEL allocation inside
runtime_resume() or runtime_suspend() on any one of device in
the path from one block or network device to the root device
in the device tree may cause deadlock, the introduced
pm_runtime_set_memalloc_noio() sets or clears the flag on
device in the path recursively.
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: "Rafael J. Wysocki" <redacted>
Signed-off-by: Ming Lei <redacted>
---
v4:
- rename memalloc_noio_resume as memalloc_noio
- remove pm_runtime_get_memalloc_noio()
- add comments on pm_runtime_set_memalloc_noio
v3:
- introduce pm_runtime_get_memalloc_noio()
- hold one global lock on pm_runtime_set_memalloc_noio
- hold device power lock when accessing memalloc_noio_resume
flag suggested by Alan Stern
- implement pm_runtime_set_memalloc_noio without recursion
suggested by Alan Stern
v2:
- introduce pm_runtime_set_memalloc_noio()
---
drivers/base/power/runtime.c | 57 ++++++++++++++++++++++++++++++++++++++++++
include/linux/pm.h | 1 +
include/linux/pm_runtime.h | 3 +++
3 files changed, 61 insertions(+)
@@ -124,6 +124,63 @@ unsigned long pm_runtime_autosuspend_expiration(struct device *dev)}EXPORT_SYMBOL_GPL(pm_runtime_autosuspend_expiration);+staticintdev_memalloc_noio(structdevice*dev,void*data)+{+returndev->power.memalloc_noio;+}++/*+*pm_runtime_set_memalloc_noio-Setadevice'smemalloc_noioflag.+*@dev:Devicetohandle.+*@enable:TrueforsettingtheflagandFalseforclearingtheflag.+*+*Settheflagforalldevicesinthepathfromthedevicetothe+*rootdeviceinthedevicetreeif@enableistrue,otherwiseclear+*theflagfordevicesinthepathwhosesiblingsdon'tsettheflag.+*+*Thefunctionshouldonlybecalledbyblockdevice,ornetwork+*devicedriverforsolvingthedeadlockproblemduringruntime+*resume/suspend:+*ifmemoryallocationwithGFP_KERNELiscalledinsideruntime+*resume/suspendcallbackofanyoneofitsancestors(orthe+*blockdeviceitself),thedeadlockmaybetriggeredinsidethe+*memoryallocationsinceitmightnotcompleteuntiltheblock+*devicebecomesactiveandtheinvoledpageI/Ofinishes.The+*situationispointedoutfirstbyAlanStern.Networkdevice+*areinvolvediniSCSIkindofsituation.+*+*Thelockofdev_hotplug_mutexisheldinthefunctionforhandling+*hotplugracebecausepm_runtime_set_memalloc_noio()maybecalled+*inasyncprobe().+*+*Thefunctionshouldbecalledbetweendevice_add()anddevice_del()+*ontheaffecteddevice(block/networkdevice).+*/+voidpm_runtime_set_memalloc_noio(structdevice*dev,boolenable)+{+staticDEFINE_MUTEX(dev_hotplug_mutex);++mutex_lock(&dev_hotplug_mutex);+for(;;){+/* hold power lock since bitfield is not SMP-safe. */+spin_lock_irq(&dev->power.lock);+dev->power.memalloc_noio=enable;+spin_unlock_irq(&dev->power.lock);++dev=dev->parent;++/* only clear the flag for one device if all+*childrenofthedevicedon'tsettheflag.+*/+if(!dev||(!enable&&+device_for_each_child(dev,NULL,+dev_memalloc_noio)))+break;+}+mutex_unlock(&dev_hotplug_mutex);+}+EXPORT_SYMBOL_GPL(pm_runtime_set_memalloc_noio);+/***rpm_check_suspend_allowed-Testwhetheradevicemaybesuspended.*@dev:Devicetotest.
--
1.7.9.5
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
This patch applyes the introduced pm_runtime_set_memalloc_noio on
block device so that PM core will teach mm to not allocate memory with
GFP_IOFS when calling the runtime_resume and runtime_suspend callback
for block devices and its ancestors.
Cc: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Ming Lei <redacted>
---
v4:
- call pm_runtime_set_memalloc_noio(ddev, true) after device_add
---
block/genhd.c | 9 +++++++++
1 file changed, 9 insertions(+)
--
1.7.9.5
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
Deadlock might be caused by allocating memory with GFP_KERNEL in
runtime_resume and runtime_suspend callback of network devices in
iSCSI situation, so mark network devices and its ancestor as
'memalloc_noio' with the introduced pm_runtime_set_memalloc_noio().
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Eric Dumazet <redacted>
Cc: David Decotigny <redacted>
Cc: Tom Herbert <redacted>
Cc: Ingo Molnar <redacted>
Signed-off-by: Ming Lei <redacted>
---
v4:
- call pm_runtime_set_memalloc_noio(ddev, true) after
device_add
---
net/core/net-sysfs.c | 5 +++++
1 file changed, 5 insertions(+)
@@ -1421,6 +1424,8 @@ int netdev_register_kobject(struct net_device *net)returnerror;}+pm_runtime_set_memalloc_noio(dev,true);+returnerror;}
--
1.7.9.5
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
This patch applies the introduced memalloc_noio_save() and
memalloc_noio_restore() to force memory allocation with no I/O
during runtime_resume/runtime_suspend callback on device with
the flag of 'memalloc_noio' set.
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Oliver Neukum <redacted>
Cc: Rafael J. Wysocki <redacted>
Signed-off-by: Ming Lei <redacted>
---
v4:
- runtime_suspend need this too because rpm_resume may wait for
completion of concurrent runtime_suspend, so deadlock still may
be triggered in runtime_suspend path.
---
drivers/base/power/runtime.c | 32 ++++++++++++++++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)
@@ -368,6 +368,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)int(*callback)(structdevice*);structdevice*parent=NULL;intretval;+unsignedintnoio_flag;trace_rpm_suspend(dev,rpmflags);
@@ -477,7 +478,20 @@ static int rpm_suspend(struct device *dev, int rpmflags)if(!callback&&dev->driver&&dev->driver->pm)callback=dev->driver->pm->runtime_suspend;-retval=rpm_callback(callback,dev);+/*+*DeadlockmightbecausedifmemoryallocationwithGFP_KERNEL+*happensinsideruntime_suspendcallbackofoneblockdevice's+*ancestorortheblockdeviceitself.Networkdevicemightbe+*thoughtaspartofiSCSIblockdevice,sonetworkdeviceand+*itsancestorshouldbemarkedasmemalloc_noio.+*/+if(dev->power.memalloc_noio){+memalloc_noio_save(noio_flag);+retval=rpm_callback(callback,dev);+memalloc_noio_restore(noio_flag);+}else{+retval=rpm_callback(callback,dev);+}if(retval)gotofail;
@@ -560,6 +574,7 @@ static int rpm_resume(struct device *dev, int rpmflags)int(*callback)(structdevice*);structdevice*parent=NULL;intretval=0;+unsignedintnoio_flag;trace_rpm_resume(dev,rpmflags);
@@ -709,7 +724,20 @@ static int rpm_resume(struct device *dev, int rpmflags)if(!callback&&dev->driver&&dev->driver->pm)callback=dev->driver->pm->runtime_resume;-retval=rpm_callback(callback,dev);+/*+*DeadlockmightbecausedifmemoryallocationwithGFP_KERNEL+*happensinsideruntime_resumecallbackofoneblockdevice's+*ancestorortheblockdeviceitself.Networkdevicemightbe+*thoughtaspartofiSCSIblockdevice,sonetworkdeviceand+*itsancestorshouldbemarkedasmemalloc_noio.+*/+if(dev->power.memalloc_noio){+memalloc_noio_save(noio_flag);+retval=rpm_callback(callback,dev);+memalloc_noio_restore(noio_flag);+}else{+retval=rpm_callback(callback,dev);+}if(retval){__update_runtime_status(dev,RPM_SUSPENDED);pm_runtime_cancel_pending(dev);
--
1.7.9.5
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
If one storage interface or usb network interface(iSCSI case)
exists in current configuration, memory allocation with
GFP_KERNEL during usb_device_reset() might trigger I/O transfer
on the storage interface itself and cause deadlock because
the 'us->dev_mutex' is held in .pre_reset() and the storage
interface can't do I/O transfer when the reset is triggered
by other interface, or the error handling can't be completed
if the reset is triggered by the storage itself(error handling path).
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Oliver Neukum <redacted>
Signed-off-by: Ming Lei <redacted>
---
v4:
- mark current memalloc_noio for every usb device reset
---
drivers/usb/core/hub.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
@@ -5044,6 +5044,7 @@ int usb_reset_device(struct usb_device *udev){intret;inti;+unsignedintnoio_flag;structusb_host_config*config=udev->actconfig;if(udev->state==USB_STATE_NOTATTACHED||
@@ -5053,6 +5054,17 @@ int usb_reset_device(struct usb_device *udev)return-EINVAL;}+/*+*Don'tallocatememorywithGFP_KERNELincurrent+*contexttoavoidpossibledeadlockifusbmass+*storageinterfaceorusbnetinterface(iSCSIcase)+*isincludedincurrentconfiguration.Theeasist+*approachistodoitforeverydevicereset,+*becausethedevice'memalloc_noio'flagmayhave+*notbeensetbeforeresetingtheusbdevice.+*/+memalloc_noio_save(noio_flag);+/* Prevent autosuspend during the reset */usb_autoresume_device(udev);
@@ -5097,6 +5109,7 @@ int usb_reset_device(struct usb_device *udev)}usb_autosuspend_device(udev);+memalloc_noio_restore(noio_flag);returnret;}EXPORT_SYMBOL_GPL(usb_reset_device);
--
1.7.9.5
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Andrew Morton <akpm@linux-foundation.org> Date: 2012-11-06 23:23:08
On Sat, 3 Nov 2012 16:35:08 +0800
Ming Lei [off-list ref] wrote:
This patchset try to solve one deadlock problem which might be caused
by memory allocation with block I/O during runtime PM and block device
error handling path. Traditionly, the problem is addressed by passing
GFP_NOIO statically to mm, but that is not a effective solution, see
detailed description in patch 1's commit log.
It generally looks OK to me. I have a few comments and I expect to grab
v5.
Rafael, your thoughts?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Andrew Morton <akpm@linux-foundation.org> Date: 2012-11-06 23:23:58
On Sat, 3 Nov 2012 16:35:09 +0800
Ming Lei [off-list ref] wrote:
This patch introduces PF_MEMALLOC_NOIO on process flag('flags' field of
'struct task_struct'), so that the flag can be set by one task
to avoid doing I/O inside memory allocation in the task's context.
The patch trys to solve one deadlock problem caused by block device,
and the problem may happen at least in the below situations:
- during block device runtime resume, if memory allocation with
GFP_KERNEL is called inside runtime resume callback of any one
of its ancestors(or the block device itself), the deadlock may be
triggered inside the memory allocation since it might not complete
until the block device becomes active and the involed page I/O finishes.
The situation is pointed out first by Alan Stern. It is not a good
approach to convert all GFP_KERNEL[1] in the path into GFP_NOIO because
several subsystems may be involved(for example, PCI, USB and SCSI may
be involved for usb mass stoarage device, network devices involved too
in the iSCSI case)
- during block device runtime suspend, because runtime resume need
to wait for completion of concurrent runtime suspend.
- during error handling of usb mass storage deivce, USB bus reset
will be put on the device, so there shouldn't have any
memory allocation with GFP_KERNEL during USB bus reset, otherwise
the deadlock similar with above may be triggered. Unfortunately, any
usb device may include one mass storage interface in theory, so it
requires all usb interface drivers to handle the situation. In fact,
most usb drivers don't know how to handle bus reset on the device
and don't provide .pre_set() and .post_reset() callback at all, so
USB core has to unbind and bind driver for these devices. So it
is still not practical to resort to GFP_NOIO for solving the problem.
Also the introduced solution can be used by block subsystem or block
drivers too, for example, set the PF_MEMALLOC_NOIO flag before doing
actual I/O transfer.
It is not a good idea to convert all these GFP_KERNEL in the
affected path into GFP_NOIO because these functions doing that may be
implemented as library and will be called in many other contexts.
In fact, memalloc_noio() can convert some of current static GFP_NOIO
allocation into GFP_KERNEL back in other non-affected contexts, at least
almost all GFP_NOIO in USB subsystem can be converted into GFP_KERNEL
after applying the approach and make allocation with GFP_IO
only happen in runtime resume/bus reset/block I/O transfer contexts
generally.
It's unclear from the description why we're also clearing __GFP_FS in
this situation.
If we can avoid doing this then there will be a very small gain: there
are some situations in which a filesystem can clean pagecache without
performing I/O.
It doesn't appear that the patch will add overhead to the alloc/free
hotpaths, which is good.
Again with the ghastly macros. Please, do this properly in regular old
C, as previously discussed. It really doesn't matter what daft things
local_irq_save() did 20 years ago. Just do it right!
Also, you can probably put the unlikely() inside memalloc_noio() and
avoid repeating it at all the callsites.
And it might be neater to do:
/*
* Nice comment goes here
*/
static inline gfp_t memalloc_noio_flags(gfp_t flags)
{
if (unlikely(current->flags & PF_MEMALLOC_NOIO))
flags &= ~GFP_IOFS;
return flags;
}
quoted hunk
* task->jobctl flags
*/
...
@@ -2304,6 +2304,12 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order, .gfp_mask = sc.gfp_mask, };+ if (unlikely(memalloc_noio())) {+ gfp_mask &= ~GFP_IOFS;+ sc.gfp_mask = gfp_mask;+ shrink.gfp_mask = sc.gfp_mask;+ }
We can avoid writing to shrink.gfp_mask twice. And maybe sc.gfp_mask
as well. Unclear, I didn't think about it too hard ;)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Andrew Morton <akpm@linux-foundation.org> Date: 2012-11-06 23:24:22
On Sat, 3 Nov 2012 16:35:10 +0800
Ming Lei [off-list ref] wrote:
The patch introduces the flag of memalloc_noio in 'struct dev_pm_info'
to help PM core to teach mm not allocating memory with GFP_KERNEL
flag for avoiding probable deadlock.
As explained in the comment, any GFP_KERNEL allocation inside
runtime_resume() or runtime_suspend() on any one of device in
the path from one block or network device to the root device
in the device tree may cause deadlock, the introduced
pm_runtime_set_memalloc_noio() sets or clears the flag on
device in the path recursively.
checkpatch finds a number of problems with this patch, all of which
should be fixed. Please always use checkpatch.
@@ -124,6 +124,63 @@ unsigned long pm_runtime_autosuspend_expiration(struct device *dev)}EXPORT_SYMBOL_GPL(pm_runtime_autosuspend_expiration);+staticintdev_memalloc_noio(structdevice*dev,void*data)+{+returndev->power.memalloc_noio;+}++/*+*pm_runtime_set_memalloc_noio-Setadevice'smemalloc_noioflag.+*@dev:Devicetohandle.+*@enable:TrueforsettingtheflagandFalseforclearingtheflag.+*+*Settheflagforalldevicesinthepathfromthedevicetothe+*rootdeviceinthedevicetreeif@enableistrue,otherwiseclear+*theflagfordevicesinthepathwhosesiblingsdon'tsettheflag.+*+*Thefunctionshouldonlybecalledbyblockdevice,ornetwork+*devicedriverforsolvingthedeadlockproblemduringruntime+*resume/suspend:+*ifmemoryallocationwithGFP_KERNELiscalledinsideruntime+*resume/suspendcallbackofanyoneofitsancestors(orthe+*blockdeviceitself),thedeadlockmaybetriggeredinsidethe+*memoryallocationsinceitmightnotcompleteuntiltheblock+*devicebecomesactiveandtheinvoledpageI/Ofinishes.The+*situationispointedoutfirstbyAlanStern.Networkdevice+*areinvolvediniSCSIkindofsituation.+*+*Thelockofdev_hotplug_mutexisheldinthefunctionforhandling+*hotplugracebecausepm_runtime_set_memalloc_noio()maybecalled+*inasyncprobe().+*+*Thefunctionshouldbecalledbetweendevice_add()anddevice_del()+*ontheaffecteddevice(block/networkdevice).+*/+voidpm_runtime_set_memalloc_noio(structdevice*dev,boolenable)+{+staticDEFINE_MUTEX(dev_hotplug_mutex);++mutex_lock(&dev_hotplug_mutex);+for(;;){+/* hold power lock since bitfield is not SMP-safe. */+spin_lock_irq(&dev->power.lock);+dev->power.memalloc_noio=enable;+spin_unlock_irq(&dev->power.lock);++dev=dev->parent;++/* only clear the flag for one device if all+*childrenofthedevicedon'tsettheflag.+*/
Such a comment is usually laid out as
/*
* Only ...
More significantly, the comment describes what the code is doing but
not why the code is doing it. The former is (usually) obvious from
reading the C, and the latter is what good code comments address.
And it's needed in this case. Why does the code do this?
Also, can a device have more than one child? If so, the code doesn't
do what the comment says it does.
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
From: Andrew Morton <akpm@linux-foundation.org> Date: 2012-11-06 23:24:33
On Sat, 3 Nov 2012 16:35:11 +0800
Ming Lei [off-list ref] wrote:
quoted hunk
This patch applyes the introduced pm_runtime_set_memalloc_noio on
block device so that PM core will teach mm to not allocate memory with
GFP_IOFS when calling the runtime_resume and runtime_suspend callback
for block devices and its ancestors.
...
Again, please fix the comment style. Take a look at the rest of this file!
+ * GFP_KERNEL in runtime_resume callback of its all ancestor
+ * deivces
typo
+ */
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
On Wed, Nov 7, 2012 at 7:23 AM, Andrew Morton [off-list ref] wrote:
It's unclear from the description why we're also clearing __GFP_FS in
this situation.
If we can avoid doing this then there will be a very small gain: there
are some situations in which a filesystem can clean pagecache without
performing I/O.
Firstly, the patch follows the policy in the system suspend/resume situation,
in which the __GFP_FS is cleared, and basically the problem is very similar
with that in system PM path.
Secondly, inside shrink_page_list(), pageout() may be triggered on dirty anon
page if __GFP_FS is set.
IMO, if performing I/O can be completely avoided when __GFP_FS is set, the
flag can be kept, otherwise it is better to clear it in the situation.
It doesn't appear that the patch will add overhead to the alloc/free
hotpaths, which is good.
Again with the ghastly macros. Please, do this properly in regular old
C, as previously discussed. It really doesn't matter what daft things
local_irq_save() did 20 years ago. Just do it right!
OK, I will take inline function in -v5.
Also, you can probably put the unlikely() inside memalloc_noio() and
avoid repeating it at all the callsites.
And it might be neater to do:
/*
* Nice comment goes here
*/
static inline gfp_t memalloc_noio_flags(gfp_t flags)
{
if (unlikely(current->flags & PF_MEMALLOC_NOIO))
flags &= ~GFP_IOFS;
return flags;
}
But without the check in callsites, some local variables will be write
two times,
so it is better to not do it.
quoted
* task->jobctl flags
*/
...
@@ -2304,6 +2304,12 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order, .gfp_mask = sc.gfp_mask, };+ if (unlikely(memalloc_noio())) {+ gfp_mask &= ~GFP_IOFS;+ sc.gfp_mask = gfp_mask;+ shrink.gfp_mask = sc.gfp_mask;+ }
We can avoid writing to shrink.gfp_mask twice. And maybe sc.gfp_mask
as well. Unclear, I didn't think about it too hard ;)
Yes, we can do it by initializing 'shrink' local variable just after the branch,
so one writing is enough. Will do it in -v5.
Thanks,
--
Ming Lei
On Wed, Nov 7, 2012 at 7:24 AM, Andrew Morton [off-list ref] wrote:
checkpatch finds a number of problems with this patch, all of which
should be fixed. Please always use checkpatch.
Sorry for missing the check.
quoted
+ /* only clear the flag for one device if all
+ * children of the device don't set the flag.
+ */
Such a comment is usually laid out as
/*
* Only ...
Will do it in -v5.
More significantly, the comment describes what the code is doing but
not why the code is doing it. The former is (usually) obvious from
reading the C, and the latter is what good code comments address.
And it's needed in this case. Why does the code do this?
Suppose both two usb scsi disks which share the same usb
configuration(device) set the device memalloc_noio flag, and
its ancestors' memalloc_noio flag should be cleared only after
both the two usb scsi disk's flags have been cleared.
OK, we'll add comment on clearing flag.
Also, can a device have more than one child? If so, the code doesn't
do what the comment says it does.
It should do that because device_for_each_child() returns true immediately
only if dev_memalloc_noio() for one child returns true.
On Wed, Nov 7, 2012 at 7:23 AM, Andrew Morton [off-list ref] wrote:
It generally looks OK to me. I have a few comments and I expect to grab
v5.
Andrew, thanks for your review, and I will prepare -v5 later.
Thanks,
--
Ming Lei
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: Andrew Morton <akpm@linux-foundation.org> Date: 2012-11-07 03:49:05
On Wed, 7 Nov 2012 11:11:24 +0800 Ming Lei [off-list ref] wrote:
On Wed, Nov 7, 2012 at 7:23 AM, Andrew Morton [off-list ref] wrote:
quoted
It's unclear from the description why we're also clearing __GFP_FS in
this situation.
If we can avoid doing this then there will be a very small gain: there
are some situations in which a filesystem can clean pagecache without
performing I/O.
Firstly, the patch follows the policy in the system suspend/resume situation,
in which the __GFP_FS is cleared, and basically the problem is very similar
with that in system PM path.
I suspect that code is wrong. Or at least, suboptimal.
Secondly, inside shrink_page_list(), pageout() may be triggered on dirty anon
page if __GFP_FS is set.
pageout() should be called if GFP_FS is set or if GFP_IO is set and the
IO is against swap.
And that's what we want to happen: we want to enter the fs to try to
turn dirty pagecache into clean pagecache without doing IO. If we in
fact enter the device drivers when GFP_IO was not set then that's a bug
which we should fix.
IMO, if performing I/O can be completely avoided when __GFP_FS is set, the
flag can be kept, otherwise it is better to clear it in the situation.
yup.
quoted
Also, you can probably put the unlikely() inside memalloc_noio() and
avoid repeating it at all the callsites.
And it might be neater to do:
/*
* Nice comment goes here
*/
static inline gfp_t memalloc_noio_flags(gfp_t flags)
{
if (unlikely(current->flags & PF_MEMALLOC_NOIO))
flags &= ~GFP_IOFS;
return flags;
}
But without the check in callsites, some local variables will be write
two times,
so it is better to not do it.
I don't see why - we just modify the incoming gfp_t at the start of the
function, then use it.
It gets a bit tricky with those struct initialisations. Things like
struct foo bar {
.a = a1,
.b = b1,
};
should not be turned into
struct foo bar {
.a = a1,
};
bar.b = b1;
and we don't want to do
struct foo bar { };
bar.a = a1;
bar.b = b1;
either, because these are indeed a double-write. But we can do
struct foo bar {
.flags = (flags = memalloc_noio_flags(flags)),
.b = b1,
};
which is a bit arcane but not toooo bad. Have a think about it...
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
On Wed, Nov 7, 2012 at 11:48 AM, Andrew Morton
[off-list ref] wrote:
quoted
Firstly, the patch follows the policy in the system suspend/resume situation,
in which the __GFP_FS is cleared, and basically the problem is very similar
with that in system PM path.
I suspect that code is wrong. Or at least, suboptimal.
quoted
Secondly, inside shrink_page_list(), pageout() may be triggered on dirty anon
page if __GFP_FS is set.
pageout() should be called if GFP_FS is set or if GFP_IO is set and the
IO is against swap.
And that's what we want to happen: we want to enter the fs to try to
turn dirty pagecache into clean pagecache without doing IO. If we in
fact enter the device drivers when GFP_IO was not set then that's a bug
which we should fix.
OK, I got it, and I'll not clear GFP_FS in -v5.
quoted
IMO, if performing I/O can be completely avoided when __GFP_FS is set, the
flag can be kept, otherwise it is better to clear it in the situation.
yup.
quoted
quoted
Also, you can probably put the unlikely() inside memalloc_noio() and
avoid repeating it at all the callsites.
And it might be neater to do:
/*
* Nice comment goes here
*/
static inline gfp_t memalloc_noio_flags(gfp_t flags)
{
if (unlikely(current->flags & PF_MEMALLOC_NOIO))
flags &= ~GFP_IOFS;
return flags;
}
But without the check in callsites, some local variables will be write
two times,
so it is better to not do it.
I don't see why - we just modify the incoming gfp_t at the start of the
function, then use it.
It gets a bit tricky with those struct initialisations. Things like
struct foo bar {
.a = a1,
.b = b1,
};
should not be turned into
struct foo bar {
.a = a1,
};
bar.b = b1;
and we don't want to do
struct foo bar { };
bar.a = a1;
bar.b = b1;
either, because these are indeed a double-write. But we can do
struct foo bar {
.flags = (flags = memalloc_noio_flags(flags)),
.b = b1,
};
which is a bit arcane but not toooo bad. Have a think about it...
Got it, looks memalloc_noio_flags() neater, and I will take it in v5.
Thanks,
--
Ming Lei
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>