F: drivers/platform/x86/acerhdf.c
ACER WMI LAPTOP EXTRAS
-M: Joey Lee <jlee@novell.com>
+M: "Lee, Chun-Yi" <jlee@suse.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/acer-wmi.c
S: Maintained
F: drivers/char/agp/
F: include/linux/agp*
+F: include/uapi/linux/agp*
AHA152X SCSI DRIVER
M: "Juergen E. Fischer" <fischer@norbit.de>
S: Odd fixes
F: arch/x86/kernel/apm_32.c
F: include/linux/apm_bios.h
+F: include/uapi/linux/apm_bios.h
F: drivers/char/apm-emulation.c
APPLE BCM5974 MULTITOUCH DRIVER
ARM SUB-ARCHITECTURES
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S: MAINTAINED
+S: Maintained
F: arch/arm/mach-*/
F: arch/arm/plat-*/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git
F: drivers/mmc/host/msm_sdcc.h
F: drivers/tty/serial/msm_serial.h
F: drivers/tty/serial/msm_serial.c
-F: drivers/platform/msm/
F: drivers/*/pm8???-*
F: include/linux/mfd/pm8xxx/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davidb/linux-msm.git
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
W: http://www.arm.linux.org.uk/
S: Maintained
-F: arch/arm/common/time-acorn.c
F: arch/arm/include/asm/hardware/entry-macro-iomd.S
F: arch/arm/include/asm/hardware/ioc.h
F: arch/arm/include/asm/hardware/iomd.h
S: Maintained
F: arch/arm/plat-samsung/
F: arch/arm/plat-s3c24xx/
-F: arch/arm/plat-s5p/
F: arch/arm/mach-s3c24*/
F: arch/arm/mach-s3c64xx/
F: drivers/*/*s3c2410*
L: linux-arm-kernel@lists.infradead.org
L: linux-media@vger.kernel.org
S: Maintained
-F: arch/arm/plat-s5p/dev-fimc*
F: arch/arm/plat-samsung/include/plat/*fimc*
F: drivers/media/platform/s5p-fimc/
L: linux-arm-kernel@lists.infradead.org
L: linux-media@vger.kernel.org
S: Maintained
-F: arch/arm/plat-s5p/dev-mfc.c
+F: arch/arm/plat-samsung/s5p-dev-mfc.c
F: drivers/media/platform/s5p-mfc/
ARM/SAMSUNG S5P SERIES TV SUBSYSTEM SUPPORT
F: drivers/video/wm8505fb*
F: drivers/video/wmt_ge_rops.*
F: drivers/tty/serial/vt8500_serial.c
-F: drivers/rtc/rtc-vt8500-c
+F: drivers/rtc/rtc-vt8500.c
F: drivers/mmc/host/wmt-sdmmc.c
ARM/ZIPIT Z2 SUPPORT
F: include/linux/async_tx.h
AT24 EEPROM DRIVER
-M: Wolfram Sang <w.sang@pengutronix.de>
+M: Wolfram Sang <wsa@the-dreams.de>
L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/misc/eeprom/at24.c
S: Supported
F: drivers/net/wireless/ath/ath9k/
+WILOCITY WIL6210 WIRELESS DRIVER
+M: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
+L: linux-wireless@vger.kernel.org
+L: wil6210@qca.qualcomm.com
+S: Supported
+W: http://wireless.kernel.org/en/users/Drivers/wil6210
+F: drivers/net/wireless/ath/wil6210/
+
CARL9170 LINUX COMMUNITY WIRELESS DRIVER
M: Christian Lamparter <chunkeey@googlemail.com>
L: linux-wireless@vger.kernel.org
S: Maintained
F: drivers/atm/
F: include/linux/atm*
+F: include/uapi/linux/atm*
ATMEL AT91 / AT32 MCI DRIVER
M: Ludovic Desroches <ludovic.desroches@atmel.com>
S: Supported
F: drivers/dma/at_hdmac.c
F: drivers/dma/at_hdmac_regs.h
-F: arch/arm/mach-at91/include/mach/at_hdmac.h
+F: include/linux/platform_data/dma-atmel.h
ATMEL ISI DRIVER
M: Josh Wu <josh.wu@atmel.com>
L: linux-media@vger.kernel.org
S: Supported
-F: drivers/media/platform/atmel-isi.c
+F: drivers/media/platform/soc_camera/atmel-isi.c
F: include/media/atmel-isi.h
ATMEL LCDFB DRIVER
T: git git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current.git
S: Maintained
F: include/linux/audit.h
+F: include/uapi/linux/audit.h
F: kernel/audit*
AUXILIARY DISPLAY DRIVERS
M: Haavard Skinnemoen <hskinnemoen@gmail.com>
M: Hans-Christian Egtvedt <egtvedt@samfundet.no>
W: http://www.atmel.com/products/AVR32/
-W: http://avr32linux.org/
+W: http://mirror.egtvedt.no/avr32linux.org/
W: http://avrfreaks.net/
S: Maintained
F: arch/avr32/
L: linux-hams@vger.kernel.org
W: http://www.linux-ax25.org/
S: Maintained
-F: include/linux/ax25.h
+F: include/uapi/linux/ax25.h
F: include/net/ax25.h
F: net/ax25/
S: Maintained
F: Documentation/filesystems/bfs.txt
F: fs/bfs/
-F: include/linux/bfs_fs.h
+F: include/uapi/linux/bfs_fs.h
BLACKFIN ARCHITECTURE
M: Mike Frysinger <vapier@gentoo.org>
W: http://sourceforge.net/projects/bonding/
S: Supported
F: drivers/net/bonding/
-F: include/linux/if_bonding.h
+F: include/uapi/linux/if_bonding.h
BROADCOM B44 10/100 ETHERNET DRIVER
M: Gary Zambrano <zambrano@broadcom.com>
S: Supported
F: block/bsg.c
F: include/linux/bsg.h
+F: include/uapi/linux/bsg.h
BT87X AUDIO DRIVER
M: Clemens Ladisch <clemens@ladisch.de>
S: Supported
F: Documentation/networking/caif/
F: drivers/net/caif/
-F: include/linux/caif/
+F: include/uapi/linux/caif/
F: include/net/caif/
F: net/caif/
T: git git://gitorious.org/linux-can/linux-can-next.git
S: Maintained
F: net/can/
-F: include/linux/can.h
F: include/linux/can/core.h
-F: include/linux/can/bcm.h
-F: include/linux/can/raw.h
-F: include/linux/can/gw.h
+F: include/uapi/linux/can.h
+F: include/uapi/linux/can/bcm.h
+F: include/uapi/linux/can/raw.h
+F: include/uapi/linux/can/gw.h
CAN NETWORK DRIVERS
M: Wolfgang Grandegger <wg@grandegger.com>
S: Maintained
F: drivers/net/can/
F: include/linux/can/dev.h
-F: include/linux/can/error.h
-F: include/linux/can/netlink.h
F: include/linux/can/platform/
+F: include/uapi/linux/can/error.h
+F: include/uapi/linux/can/netlink.h
CAPABILITIES
M: Serge Hallyn <serge.hallyn@canonical.com>
L: linux-security-module@vger.kernel.org
S: Supported
F: include/linux/capability.h
+F: include/uapi/linux/capability.h
F: security/capability.c
F: security/commoncap.c
F: kernel/capability.c
S: Supported
F: arch/powerpc/include/asm/cell*.h
F: arch/powerpc/include/asm/spu*.h
+F: arch/powerpc/include/uapi/asm/spu*.h
F: arch/powerpc/oprofile/*cell*
F: arch/powerpc/platforms/cell/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
S: Maintained
-F: include/linux/nl80211.h
+F: include/uapi/linux/nl80211.h
F: include/net/cfg80211.h
F: net/wireless/*
X: net/wireless/wext*
F: drivers/usb/host/ohci-ep93xx.c
CIRRUS LOGIC CS4270 SOUND DRIVER
-M: Timur Tabi <timur@freescale.com>
+M: Timur Tabi <timur@tabi.org>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
-S: Supported
+S: Odd Fixes
F: sound/soc/codecs/cs4270*
CLEANCACHE API
F: Documentation/filesystems/coda.txt
F: fs/coda/
F: include/linux/coda*.h
+F: include/uapi/linux/coda*.h
COMMON CLK FRAMEWORK
M: Mike Turquette <mturquette@linaro.org>
F: tools/power/cpupower
CPUSETS
- M: Paul Menage <paul@paulmenage.org>
+ M: Li Zefan <lizefan@huawei.com>
W: http://www.bullopensource.org/cpuset/
W: http://oss.sgi.com/projects/cpusets/
- S: Supported
+ S: Maintained
F: Documentation/cgroups/cpusets.txt
F: include/linux/cpuset.h
F: kernel/cpuset.c
S: Orphan
F: drivers/tty/cyclades.c
F: include/linux/cyclades.h
+F: include/uapi/linux/cyclades.h
CYCLADES PC300 DRIVER
W: http://www.cyclades.com/
W: http://www.linuxfoundation.org/collaborate/workgroups/networking/dccp
S: Maintained
F: include/linux/dccp.h
+F: include/uapi/linux/dccp.h
F: include/linux/tfrc.h
F: net/dccp/
W: http://www.debian.org/~dz/i8k/
S: Maintained
F: drivers/char/i8k.c
-F: include/linux/i8k.h
+F: include/uapi/linux/i8k.h
DELL SYSTEMS MANAGEMENT BASE DRIVER (dcdbas)
M: Doug Warzecha <Douglas_Warzecha@dell.com>
F: Documentation/filesystems/quota.txt
F: fs/quota/
F: include/linux/quota*.h
+F: include/uapi/linux/quota*.h
DISPLAYLINK USB 2.0 FRAMEBUFFER DRIVER (UDLFB)
M: Bernie Thompson <bernie@plugable.com>
S: Maintained
F: drivers/gpu/drm/
F: include/drm/
+F: include/uapi/drm/
INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
M: Daniel Vetter <daniel.vetter@ffwll.ch>
S: Supported
F: drivers/gpu/drm/i915
F: include/drm/i915*
+F: include/uapi/drm/i915*
DRM DRIVERS FOR EXYNOS
M: Inki Dae <inki.dae@samsung.com>
S: Supported
F: drivers/gpu/drm/exynos
F: include/drm/exynos*
+F: include/uapi/drm/exynos*
DRM DRIVERS FOR NVIDIA TEGRA
M: Thierry Reding <thierry.reding@avionic-design.de>
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/media_tree.git
S: Maintained
-F: drivers/media/usb/dvb-usb-v2/cxusb*
+F: drivers/media/usb/dvb-usb/cxusb*
DVB_USB_CYPRESS_FIRMWARE MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
W: http://ebtables.sourceforge.net/
S: Maintained
F: include/linux/netfilter_bridge/ebt_*.h
+F: include/uapi/linux/netfilter_bridge/ebt_*.h
F: net/bridge/netfilter/ebt*.c
EC100 MEDIA DRIVER
S: Maintained
F: drivers/media/rc/ene_ir.*
-EPSON 1355 FRAMEBUFFER DRIVER
-M: Christopher Hoover <ch@murgatroid.com>
-M: Christopher Hoover <ch@hpl.hp.com>
-S: Maintained
-F: drivers/video/epson1355fb.c
-
EPSON S1D13XXX FRAMEBUFFER DRIVER
M: Kristoffer Ericson <kristoffer.ericson@gmail.com>
S: Maintained
F: drivers/net/ethernet/i825xx/eexpress.*
ETHERNET BRIDGE
-M: Stephen Hemminger <shemminger@vyatta.com>
+M: Stephen Hemminger <stephen@networkplumber.org>
L: bridge@lists.linux-foundation.org
L: netdev@vger.kernel.org
W: http://www.linuxfoundation.org/en/Net:Bridge
S: Maintained
F: fs/notify/fanotify/
F: include/linux/fanotify.h
+F: include/uapi/linux/fanotify.h
FARSYNC SYNCHRONOUS DRIVER
M: Kevin Curtis <kevin.curtis@farsite.co.uk>
F: include/scsi/fc/
F: include/scsi/libfc.h
F: include/scsi/libfcoe.h
+F: include/uapi/scsi/fc/
FILE LOCKING (flock() and fcntl()/lockf())
M: Matthew Wilcox <matthew@wil.cx>
S: Maintained
F: include/linux/fcntl.h
F: include/linux/fs.h
+F: include/uapi/linux/fcntl.h
+F: include/uapi/linux/fs.h
F: fs/fcntl.c
F: fs/locks.c
F: drivers/video/
F: include/video/
F: include/linux/fb.h
+F: include/uapi/video/
+F: include/uapi/linux/fb.h
FREESCALE DIU FRAMEBUFFER DRIVER
-M: Timur Tabi <timur@freescale.com>
+M: Timur Tabi <timur@tabi.org>
L: linux-fbdev@vger.kernel.org
-S: Supported
+S: Maintained
F: drivers/video/fsl-diu-fb.*
FREESCALE DMA DRIVER
L: linux-fbdev@vger.kernel.org
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
-F: arch/arm/plat-mxc/include/mach/imxfb.h
+F: include/linux/platform_data/video-imxfb.h
F: drivers/video/imxfb.c
FREESCALE SOC FS_ENET DRIVER
F: include/linux/fs_enet_pd.h
FREESCALE QUICC ENGINE LIBRARY
-M: Timur Tabi <timur@freescale.com>
L: linuxppc-dev@lists.ozlabs.org
-S: Supported
+S: Orphan
F: arch/powerpc/sysdev/qe_lib/
F: arch/powerpc/include/asm/*qe.h
F: drivers/net/ethernet/freescale/ucc_geth*
FREESCALE QUICC ENGINE UCC UART DRIVER
-M: Timur Tabi <timur@freescale.com>
+M: Timur Tabi <timur@tabi.org>
L: linuxppc-dev@lists.ozlabs.org
-S: Supported
+S: Maintained
F: drivers/tty/serial/ucc_uart.c
FREESCALE SOC SOUND DRIVERS
-M: Timur Tabi <timur@freescale.com>
+M: Timur Tabi <timur@tabi.org>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
L: linuxppc-dev@lists.ozlabs.org
-S: Supported
+S: Maintained
F: sound/soc/fsl/fsl*
F: sound/soc/fsl/mpc8610_hpcd.c
F: fs/fscache/
F: include/linux/fscache*.h
+F2FS FILE SYSTEM
+M: Jaegeuk Kim <jaegeuk.kim@samsung.com>
+L: linux-f2fs-devel@lists.sourceforge.net
+W: http://en.wikipedia.org/wiki/F2FS
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git
+S: Maintained
+F: Documentation/filesystems/f2fs.txt
+F: fs/f2fs/
+F: include/linux/f2fs_fs.h
+
FUJITSU FR-V (FRV) PORT
M: David Howells <dhowells@redhat.com>
S: Maintained
W: http://fuse.sourceforge.net/
S: Maintained
F: fs/fuse/
-F: include/linux/fuse.h
+F: include/uapi/linux/fuse.h
FUTURE DOMAIN TMC-16x0 SCSI DRIVER (16-bit)
M: Rik Faith <faith@cs.unc.edu>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git
S: Maintained
F: include/asm-generic
+F: include/uapi/asm-generic
GENERIC UIO DRIVER FOR PCI DEVICES
M: "Michael S. Tsirkin" <mst@redhat.com>
S: Supported
F: Documentation/filesystems/gfs2*.txt
F: fs/gfs2/
-F: include/linux/gfs2_ondisk.h
+F: include/uapi/linux/gfs2_ondisk.h
GIGASET ISDN DRIVERS
M: Hansjoerg Lipp <hjlipp@web.de>
S: Maintained
F: Documentation/isdn/README.gigaset
F: drivers/isdn/gigaset/
-F: include/linux/gigaset_dev.h
+F: include/uapi/linux/gigaset_dev.h
GPIO SUBSYSTEM
M: Grant Likely <grant.likely@secretlab.ca>
F: Documentation/scsi/hpsa.txt
F: drivers/scsi/hpsa*.[ch]
F: include/linux/cciss*.h
+F: include/uapi/linux/cciss*.h
HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
M: Mike Miller <mike.miller@hp.com>
F: Documentation/blockdev/cciss.txt
F: drivers/block/cciss*
F: include/linux/cciss_ioctl.h
+F: include/uapi/linux/cciss_ioctl.h
HFS FILESYSTEM
L: linux-fsdevel@vger.kernel.org
S: Maintained
F: drivers/hid/
F: include/linux/hid*
+F: include/uapi/linux/hid*
HIGH-RESOLUTION TIMERS, CLOCKEVENTS, DYNTICKS
M: Thomas Gleixner <tglx@linutronix.de>
L: linux-hippi@sunsite.dk
S: Maintained
F: include/linux/hippidevice.h
-F: include/linux/if_hippi.h
+F: include/uapi/linux/if_hippi.h
F: net/802/hippi.c
F: drivers/net/hippi/
F: Documentation/timers/hpet.txt
F: drivers/char/hpet.c
F: include/linux/hpet.h
+F: include/uapi/linux/hpet.h
HPET: x86
M: "Venkatesh Pallipadi (Venki)" <venki@google.com>
F: drivers/i2c/i2c-stub.c
I2C SUBSYSTEM
-M: Wolfram Sang <w.sang@pengutronix.de>
+M: Wolfram Sang <wsa@the-dreams.de>
M: "Ben Dooks (embedded platforms)" <ben-linux@fluff.org>
L: linux-i2c@vger.kernel.org
W: http://i2c.wiki.kernel.org/
-T: quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-i2c/
-T: git git://git.pengutronix.de/git/wsa/linux.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
S: Maintained
F: Documentation/i2c/
F: drivers/i2c/
F: include/linux/i2c.h
F: include/linux/i2c-*.h
+F: include/uapi/linux/i2c.h
+F: include/uapi/linux/i2c-*.h
I2C-TAOS-EVM DRIVER
M: Jean Delvare <khali@linux-fr.org>
S: Maintained
F: net/ieee802154/
F: net/mac802154/
-F: drivers/ieee802154/
+F: drivers/net/ieee802154/
IGUANAWORKS USB IR TRANSCEIVER
M: Sean Young <sean@mess.org>
S: Supported
F: Documentation/infiniband/
F: drivers/infiniband/
-F: include/linux/if_infiniband.h
+F: include/uapi/linux/if_infiniband.h
INOTIFY
M: John McCutchan <john@johnmccutchan.com>
F: Documentation/filesystems/inotify.txt
F: fs/notify/inotify/
F: include/linux/inotify.h
+F: include/uapi/linux/inotify.h
INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS
M: Dmitry Torokhov <dmitry.torokhov@gmail.com>
S: Maintained
F: drivers/input/
F: include/linux/input.h
+F: include/uapi/linux/input.h
F: include/linux/input/
INPUT MULTITOUCH (MT) PROTOCOL
T: git git://git.code.sf.net/p/intel-sas/isci
S: Supported
F: drivers/scsi/isci/
-F: firmware/isci/
INTEL IDLE DRIVER
M: Len Brown <lenb@kernel.org>
F: Documentation/networking/ixgbevf.txt
F: drivers/net/ethernet/intel/
-INTEL MRST PMU DRIVER
-M: Len Brown <len.brown@intel.com>
-L: linux-pm@vger.kernel.org
-S: Supported
-F: arch/x86/platform/mrst/pmu.*
-
INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT
M: Stanislav Yakovlev <stas.yakovlev@gmail.com>
L: linux-wireless@vger.kernel.org
W: http://linuxwimax.org
F: Documentation/wimax/README.i2400m
F: drivers/net/wimax/i2400m/
-F: include/linux/wimax/i2400m.h
+F: include/uapi/linux/wimax/i2400m.h
INTEL WIRELESS 3945ABG/BG, 4965AGN (iwlegacy)
M: Stanislaw Gruszka <sgruszka@redhat.com>
M: Tomas Winkler <tomas.winkler@intel.com>
L: linux-kernel@vger.kernel.org
S: Supported
-F: include/linux/mei.h
+F: include/uapi/linux/mei.h
F: drivers/misc/mei/*
-F: Documentation/mei/*
+F: Documentation/misc-devices/mei/*
IOC3 ETHERNET DRIVER
M: Ralf Baechle <ralf@linux-mips.org>
F: Documentation/IPMI.txt
F: drivers/char/ipmi/
F: include/linux/ipmi*
+F: include/uapi/linux/ipmi*
IPS SCSI RAID DRIVER
M: Adaptec OEM Raid Solutions <aacraid@adaptec.com>
S: Maintained
F: Documentation/networking/ipvs-sysctl.txt
F: include/net/ip_vs.h
-F: include/linux/ip_vs.h
+F: include/uapi/linux/ip_vs.h
F: net/netfilter/ipvs/
IPWIRELESS DRIVER
M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
L: netdev@vger.kernel.org
S: Maintained
-F: include/linux/ipx.h
F: include/net/ipx.h
+F: include/uapi/linux/ipx.h
F: net/ipx/
IRDA SUBSYSTEM
F: drivers/isdn/
F: include/linux/isdn.h
F: include/linux/isdn/
+F: include/uapi/linux/isdn.h
+F: include/uapi/linux/isdn/
ISDN SUBSYSTEM (Eicon active card driver)
M: Armin Schindler <mac@melware.de>
S: Maintained
F: Documentation/video4linux/*.ivtv
F: drivers/media/pci/ivtv/
-F: include/linux/ivtv*
+F: include/uapi/linux/ivtv*
IX2505V MEDIA DRIVER
M: Malcolm Priestley <tvboxspy@gmail.com>
W: http://www.linux-mtd.infradead.org/doc/jffs2.html
S: Maintained
F: fs/jffs2/
-F: include/linux/jffs2.h
+F: include/uapi/linux/jffs2.h
JOURNALLING LAYER FOR BLOCK DEVICES (JBD)
M: Andrew Morton <akpm@linux-foundation.org>
S: Supported
F: fs/nfsd/
F: include/linux/nfsd/
+F: include/uapi/linux/nfsd/
F: fs/lockd/
F: fs/nfs_common/
F: net/sunrpc/
F: include/linux/lockd/
F: include/linux/sunrpc/
+F: include/uapi/linux/sunrpc/
KERNEL VIRTUAL MACHINE (KVM)
M: Marcelo Tosatti <mtosatti@redhat.com>
F: arch/*/kvm/
F: arch/*/include/asm/kvm*
F: include/linux/kvm*
+F: include/uapi/linux/kvm*
F: virt/kvm/
KERNEL VIRTUAL MACHINE (KVM) FOR AMD-V
L: kexec@lists.infradead.org
S: Maintained
F: include/linux/kexec.h
+F: include/uapi/linux/kexec.h
F: kernel/kexec.c
KEYS/KEYRINGS:
M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
S: Maintained
F: include/linux/llc.h
+F: include/uapi/linux/llc.h
F: include/net/llc*
F: net/llc/
MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2)
M: Mirko Lindner <mlindner@marvell.com>
-M: Stephen Hemminger <shemminger@vyatta.com>
+M: Stephen Hemminger <stephen@networkplumber.org>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/marvell/sk*
L: linux-fbdev@vger.kernel.org
S: Orphan
F: drivers/video/matrox/matroxfb_*
-F: include/linux/matroxfb.h
+F: include/uapi/linux/matroxfb.h
MAX16065 HARDWARE MONITOR DRIVER
M: Guenter Roeck <linux@roeck-us.net>
S: Maintained
F: drivers/mtd/
F: include/linux/mtd/
-F: include/mtd/
+F: include/uapi/mtd/
MICROBLAZE ARCHITECTURE
M: Michal Simek <monstr@monstr.eu>
F: drivers/media/pci/meye/
F: include/uapi/linux/meye.h
-MOTOROLA IMX MMC/SD HOST CONTROLLER INTERFACE DRIVER
-M: Pavel Pisa <ppisa@pikron.com>
-L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S: Maintained
-F: drivers/mmc/host/imxmmc.*
-
MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
M: Jiri Slaby <jirislaby@gmail.com>
S: Maintained
F: drivers/media/radio/radio-mr800.c
MSI LAPTOP SUPPORT
-M: "Lee, Chun-Yi" <jlee@novell.com>
+M: "Lee, Chun-Yi" <jlee@suse.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/msi-laptop.c
S: Maintained
F: drivers/mmc/
F: include/linux/mmc/
+F: include/uapi/linux/mmc/
MULTIMEDIA CARD (MMC) ETC. OVER SPI
S: Orphan
F: drivers/infiniband/hw/nes/
NETEM NETWORK EMULATOR
-M: Stephen Hemminger <shemminger@vyatta.com>
+M: Stephen Hemminger <stephen@networkplumber.org>
L: netem@lists.linux-foundation.org
S: Maintained
F: net/sched/sch_netem.c
F: include/linux/netfilter*
F: include/linux/netfilter/
F: include/net/netfilter/
+F: include/uapi/linux/netfilter*
+F: include/uapi/linux/netfilter/
F: net/*/netfilter.c
F: net/*/netfilter/
F: net/netfilter/
L: linux-hams@vger.kernel.org
W: http://www.linux-ax25.org/
S: Maintained
-F: include/linux/netrom.h
F: include/net/netrom.h
+F: include/uapi/linux/netrom.h
F: net/netrom/
NETWORK BLOCK DEVICE (NBD)
F: Documentation/blockdev/nbd.txt
F: drivers/block/nbd.c
F: include/linux/nbd.h
+F: include/uapi/linux/nbd.h
NETWORK DROP MONITOR
M: Neil Horman <nhorman@tuxdriver.com>
F: include/linux/in.h
F: include/linux/net.h
F: include/linux/netdevice.h
+F: include/uapi/linux/in.h
+F: include/uapi/linux/net.h
+F: include/uapi/linux/netdevice.h
NETWORKING [IPv4/IPv6]
M: "David S. Miller" <davem@davemloft.net>
F: net/wireless/
F: include/net/ieee80211*
F: include/linux/wireless.h
+F: include/uapi/linux/wireless.h
F: include/net/iw_handler.h
F: drivers/net/wireless/
F: include/linux/fddidevice.h
F: include/linux/hippidevice.h
F: include/linux/inetdevice.h
+F: include/uapi/linux/if_*
+F: include/uapi/linux/netdevice.h
NETXEN (1/10) GbE SUPPORT
M: Sony Chacko <sony.chacko@qlogic.com>
L: linux-nfc@lists.01.org (moderated for non-subscribers)
S: Maintained
F: net/nfc/
-F: include/linux/nfc.h
F: include/net/nfc/
+F: include/uapi/linux/nfc.h
F: drivers/nfc/
F: include/linux/platform_data/pn544.h
F: include/linux/lockd/
F: include/linux/nfs*
F: include/linux/sunrpc/
+F: include/uapi/linux/nfs*
+F: include/uapi/linux/sunrpc/
NI5010 NETWORK DRIVER
M: Jan-Pascal van Best <janpascal@vanbest.org>
M: Paul Walmsley <paul@pwsan.com>
L: linux-omap@vger.kernel.org
S: Maintained
-F: arch/arm/mach-omap2/omap_hwmod.c
-F: arch/arm/plat-omap/include/plat/omap_hwmod.h
+F: arch/arm/mach-omap2/omap_hwmod.*
OMAP HWMOD DATA FOR OMAP4-BASED DEVICES
M: Benoît Cousson <b-cousson@ti.com>
S: Maintained
F: drivers/char/pcmcia/cm4000_cs.c
F: include/linux/cm4000_cs.h
+F: include/uapi/linux/cm4000_cs.h
OMNIKEY CARDMAN 4040 DRIVER
M: Harald Welte <laforge@gnumonks.org>
F: drivers/parport/
F: include/linux/parport*.h
F: drivers/char/ppdev.c
-F: include/linux/ppdev.h
+F: include/uapi/linux/ppdev.h
PARAVIRT_OPS INTERFACE
M: Jeremy Fitzhardinge <jeremy@goop.org>
S: Maintained
F: drivers/i2c/muxes/i2c-mux-pca9541.c
-PCA9564/PCA9665 I2C BUS DRIVER
-M: Wolfram Sang <w.sang@pengutronix.de>
-L: linux-i2c@vger.kernel.org
-S: Maintained
-F: drivers/i2c/algos/i2c-algo-pca.c
-F: drivers/i2c/busses/i2c-pca-*
-F: include/linux/i2c-algo-pca.h
-F: include/linux/i2c-pca-platform.h
-
PCDP - PRIMARY CONSOLE AND DEBUG PORT
M: Khalid Aziz <khalid@gonehiking.org>
S: Maintained
S: Supported
F: kernel/events/*
F: include/linux/perf_event.h
+F: include/uapi/linux/perf_event.h
F: arch/*/kernel/perf_event*.c
F: arch/*/kernel/*/perf_event*.c
F: arch/*/kernel/*/*/perf_event*.c
F: arch/*/include/asm/perf_event.h
-F: arch/*/lib/perf_event*.c
F: arch/*/kernel/perf_callchain.c
F: tools/perf/
L: linux-abi-devel@lists.sourceforge.net
S: Maintained
F: include/linux/personality.h
+F: include/uapi/linux/personality.h
PHONET PROTOCOL
M: Remi Denis-Courmont <courmisch@gmail.com>
F: Documentation/networking/phonet.txt
F: include/linux/phonet.h
F: include/net/phonet/
+F: include/uapi/linux/phonet.h
F: net/phonet/
PHRAM MTD DRIVER
S: Maintained
F: drivers/block/pktcdvd.c
F: include/linux/pktcdvd.h
+F: include/uapi/linux/pktcdvd.h
PKUNITY SOC DRIVERS
M: Guan Xuetao <gxt@mprc.pku.edu.cn>
M: Mitchell Blank Jr <mitch@sfgoth.com>
S: Maintained
F: net/atm/pppoatm.c
-F: include/linux/atmppp.h
+F: include/uapi/linux/atmppp.h
PPP OVER ETHERNET
M: Michal Ostrowski <mostrows@earthlink.net>
S: Maintained
F: net/l2tp/l2tp_ppp.c
F: include/linux/if_pppol2tp.h
+F: include/uapi/linux/if_pppol2tp.h
PPS SUPPORT
M: Rodolfo Giometti <giometti@enneenne.com>
F: include/linux/ptrace.h
F: include/linux/regset.h
F: include/linux/tracehook.h
+F: include/uapi/linux/ptrace.h
F: kernel/ptrace.c
PVRUSB2 VIDEO4LINUX DRIVER
F: Documentation/pwm.txt
F: Documentation/devicetree/bindings/pwm/
F: include/linux/pwm.h
-F: include/linux/of_pwm.h
F: drivers/pwm/
F: drivers/video/backlight/pwm_bl.c
F: include/linux/pwm_backlight.h
W: http://www.alarsen.net/linux/qnx4fs/
S: Maintained
F: fs/qnx4/
-F: include/linux/qnx4_fs.h
-F: include/linux/qnxtypes.h
+F: include/uapi/linux/qnx4_fs.h
+F: include/uapi/linux/qnxtypes.h
QT1010 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-fbdev@vger.kernel.org
S: Maintained
F: drivers/video/aty/radeon*
-F: include/linux/radeonfb.h
+F: include/uapi/linux/radeonfb.h
RADIOSHARK RADIO DRIVER
M: Hans de Goede <hdegoede@redhat.com>
F: Documentation/rtc.txt
F: drivers/rtc/
F: include/linux/rtc.h
+F: include/uapi/linux/rtc.h
REISERFS FILE SYSTEM
L: reiserfs-devel@vger.kernel.org
L: linux-hams@vger.kernel.org
W: http://www.linux-ax25.org/
S: Maintained
-F: include/linux/rose.h
F: include/net/rose.h
+F: include/uapi/linux/rose.h
F: net/rose/
RTL2830 MEDIA DRIVER
F: include/media/s3c_camif.h
SERIAL DRIVERS
-M: Alan Cox <alan@linux.intel.com>
+M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
L: linux-serial@vger.kernel.org
S: Maintained
F: drivers/tty/serial
F: drivers/dma/dw_dmac.c
TIMEKEEPING, NTP
-M: John Stultz <johnstul@us.ibm.com>
+M: John Stultz <john.stultz@linaro.org>
M: Thomas Gleixner <tglx@linutronix.de>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
S: Supported
F: include/linux/clocksource.h
F: include/linux/time.h
F: include/linux/timex.h
+F: include/uapi/linux/time.h
+F: include/uapi/linux/timex.h
F: kernel/time/clocksource.c
F: kernel/time/time*.c
F: kernel/time/ntp.c
S: Maintained
F: kernel/sched/
F: include/linux/sched.h
+F: include/uapi/linux/sched.h
SCORE ARCHITECTURE
M: Chen Liqin <liqin.chen@sunplusct.com>
M: Jiri Slaby <jirislaby@gmail.com>
S: Maintained
F: drivers/misc/phantom.c
-F: include/linux/phantom.h
+F: include/uapi/linux/phantom.h
SERIAL ATA (SATA) SUBSYSTEM
M: Jeff Garzik <jgarzik@pobox.com>
S: Supported
F: drivers/md/
F: include/linux/raid/
+F: include/uapi/linux/raid/
SONIC NETWORK DRIVER
M: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
S: Maintained
F: Documentation/sound/
F: include/sound/
+F: include/uapi/sound/
F: sound/
SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
-M: Liam Girdwood <lrg@ti.com>
+M: Liam Girdwood <lgirdwood@gmail.com>
M: Mark Brown <broonie@opensource.wolfsonmicro.com>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
F: Documentation/spi/
F: drivers/spi/
F: include/linux/spi/
+F: include/uapi/linux/spi/
SPIDERNET NETWORK DRIVER for CELL
M: Ishizaki Kou <kou.ishizaki@toshiba.co.jp>
STAGING - SILICON MOTION SM7XX FRAME BUFFER DRIVER
M: Teddy Wang <teddy.wang@siliconmotion.com.cn>
S: Odd Fixes
-F: drivers/staging/sm7xx/
+F: drivers/staging/sm7xxfb/
STAGING - SOFTLOGIC 6x10 MPEG CODEC
M: Ben Collins <bcollins@bluecherry.net>
F: drivers/staging/speakup/
STAGING - TI DSP BRIDGE DRIVERS
-M: Omar Ramirez Luna <omar.ramirez@ti.com>
+M: Omar Ramirez Luna <omar.ramirez@copitl.com>
S: Odd Fixes
F: drivers/staging/tidspbridge/
M: Jamal Hadi Salim <jhs@mojatatu.com>
L: netdev@vger.kernel.org
S: Maintained
-F: include/linux/pkt_cls.h
F: include/net/pkt_cls.h
+F: include/uapi/linux/pkt_cls.h
F: net/sched/
TCP LOW PRIORITY MODULE
S: Supported
F: drivers/net/team/
F: include/linux/if_team.h
+F: include/uapi/linux/if_team.h
+
+TECHNOLOGIC SYSTEMS TS-5500 PLATFORM SUPPORT
+M: Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>
+S: Maintained
+F: arch/x86/platform/ts5500/
TECHNOTREND USB IR RECEIVER
M: Sean Young <sean@mess.org>
L: tipc-discussion@lists.sourceforge.net (user apps, general discussion)
W: http://tipc.sourceforge.net/
S: Maintained
-F: include/linux/tipc*.h
+F: include/uapi/linux/tipc*.h
F: net/tipc/
TILE ARCHITECTURE
S: Maintained
F: drivers/char/toshiba.c
F: include/linux/toshiba.h
+F: include/uapi/linux/toshiba.h
TMIO MMC DRIVER
M: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
F: include/linux/serial_core.h
F: include/linux/serial.h
F: include/linux/tty.h
+F: include/uapi/linux/serial_core.h
+F: include/uapi/linux/serial.h
+F: include/uapi/linux/tty.h
TUA9001 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-input@vger.kernel.org
S: Maintained
F: drivers/hid/uhid.c
-F: include/linux/uhid.h
+F: include/uapi/linux/uhid.h
ULTRA-WIDEBAND (UWB) SUBSYSTEM:
L: linux-usb@vger.kernel.org
F: Documentation/cdrom/
F: drivers/cdrom/cdrom.c
F: include/linux/cdrom.h
+F: include/uapi/linux/cdrom.h
UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER
M: Vinayak Holikatti <vinholikatti@gmail.com>
S: Maintained
F: drivers/mtd/ubi/
F: include/linux/mtd/ubi.h
-F: include/mtd/ubi-user.h
+F: include/uapi/mtd/ubi-user.h
UNSORTED BLOCK IMAGES (UBI) Fastmap
M: Richard Weinberger <richard@nod.at>
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/net/usb/cdc_*.c
-F: include/linux/usb/cdc.h
+F: include/uapi/linux/usb/cdc.h
USB CYPRESS C67X00 DRIVER
M: Peter Korsgaard <jacmet@sunsite.dk>
F: Documentation/vfio.txt
F: drivers/vfio/
F: include/linux/vfio.h
+F: include/uapi/linux/vfio.h
VIDEOBUF2 FRAMEWORK
M: Pawel Osciak <pawel@osciak.com>
S: Maintained
F: drivers/char/virtio_console.c
F: include/linux/virtio_console.h
+F: include/uapi/linux/virtio_console.h
VIRTIO CORE, NET AND BLOCK DRIVERS
M: Rusty Russell <rusty@rustcorp.com.au>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/vhost/
-F: include/linux/vhost.h
+F: include/uapi/linux/vhost.h
VIA RHINE NETWORK DRIVER
M: Roger Luethi <rl@hellgate.ch>
F: Documentation/watchdog/
F: drivers/watchdog/
F: include/linux/watchdog.h
+F: include/uapi/linux/watchdog.h
WD7000 SCSI DRIVER
M: Miroslav Zagorac <zaga@fly.cc.fer.hr>
S: Supported
W: http://linuxwimax.org
F: Documentation/wimax/README.wimax
-F: include/linux/wimax.h
F: include/linux/wimax/debug.h
F: include/net/wimax.h
+F: include/uapi/linux/wimax.h
F: net/wimax/
WISTRON LAPTOP BUTTON DRIVER
F: arch/x86/
X86 PLATFORM DRIVERS
-M: Matthew Garrett <mjg@redhat.com>
+M: Matthew Garrett <matthew.garrett@nebula.com>
L: platform-driver-x86@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86.git
S: Maintained
F: drivers/xen/
F: arch/x86/include/asm/xen/
F: include/xen/
+F: include/uapi/xen/
XEN HYPERVISOR ARM
M: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
#include <linux/workqueue.h>
#include <linux/cgroup.h>
- /*
- * Workqueue for cpuset related tasks.
- *
- * Using kevent workqueue may cause deadlock when memory_migrate
- * is set. So we create a separate workqueue thread for cpuset.
- */
- static struct workqueue_struct *cpuset_wq;
-
/*
* Tracks how many cpusets are currently defined in system.
* When there is only one cpuset (the root cpuset) we can
cpumask_var_t cpus_allowed; /* CPUs allowed to tasks in cpuset */
nodemask_t mems_allowed; /* Memory Nodes allowed to tasks */
- struct cpuset *parent; /* my parent */
-
struct fmeter fmeter; /* memory_pressure filter */
+ /*
+ * Tasks are being attached to this cpuset. Used to prevent
+ * zeroing cpus/mems_allowed between ->can_attach() and ->attach().
+ */
+ int attach_in_progress;
+
/* partition number for rebuild_sched_domains() */
int pn;
/* for custom sched domain */
int relax_domain_level;
- /* used for walking a cpuset hierarchy */
- struct list_head stack_list;
+ struct work_struct hotplug_work;
};
/* Retrieve the cpuset for a cgroup */
struct cpuset, css);
}
+ static inline struct cpuset *parent_cs(const struct cpuset *cs)
+ {
+ struct cgroup *pcgrp = cs->css.cgroup->parent;
+
+ if (pcgrp)
+ return cgroup_cs(pcgrp);
+ return NULL;
+ }
+
#ifdef CONFIG_NUMA
static inline bool task_has_mempolicy(struct task_struct *task)
{
/* bits in struct cpuset flags field */
typedef enum {
+ CS_ONLINE,
CS_CPU_EXCLUSIVE,
CS_MEM_EXCLUSIVE,
CS_MEM_HARDWALL,
CS_SPREAD_SLAB,
} cpuset_flagbits_t;
- /* the type of hotplug event */
- enum hotplug_event {
- CPUSET_CPU_OFFLINE,
- CPUSET_MEM_OFFLINE,
- };
-
/* convenient tests for these bits */
+ static inline bool is_cpuset_online(const struct cpuset *cs)
+ {
+ return test_bit(CS_ONLINE, &cs->flags);
+ }
+
static inline int is_cpu_exclusive(const struct cpuset *cs)
{
return test_bit(CS_CPU_EXCLUSIVE, &cs->flags);
}
static struct cpuset top_cpuset = {
- .flags = ((1 << CS_CPU_EXCLUSIVE) | (1 << CS_MEM_EXCLUSIVE)),
+ .flags = ((1 << CS_ONLINE) | (1 << CS_CPU_EXCLUSIVE) |
+ (1 << CS_MEM_EXCLUSIVE)),
};
+ /**
+ * cpuset_for_each_child - traverse online children of a cpuset
+ * @child_cs: loop cursor pointing to the current child
+ * @pos_cgrp: used for iteration
+ * @parent_cs: target cpuset to walk children of
+ *
+ * Walk @child_cs through the online children of @parent_cs. Must be used
+ * with RCU read locked.
+ */
+ #define cpuset_for_each_child(child_cs, pos_cgrp, parent_cs) \
+ cgroup_for_each_child((pos_cgrp), (parent_cs)->css.cgroup) \
+ if (is_cpuset_online(((child_cs) = cgroup_cs((pos_cgrp)))))
+
+ /**
+ * cpuset_for_each_descendant_pre - pre-order walk of a cpuset's descendants
+ * @des_cs: loop cursor pointing to the current descendant
+ * @pos_cgrp: used for iteration
+ * @root_cs: target cpuset to walk ancestor of
+ *
+ * Walk @des_cs through the online descendants of @root_cs. Must be used
+ * with RCU read locked. The caller may modify @pos_cgrp by calling
+ * cgroup_rightmost_descendant() to skip subtree.
+ */
+ #define cpuset_for_each_descendant_pre(des_cs, pos_cgrp, root_cs) \
+ cgroup_for_each_descendant_pre((pos_cgrp), (root_cs)->css.cgroup) \
+ if (is_cpuset_online(((des_cs) = cgroup_cs((pos_cgrp)))))
+
/*
- * There are two global mutexes guarding cpuset structures. The first
- * is the main control groups cgroup_mutex, accessed via
- * cgroup_lock()/cgroup_unlock(). The second is the cpuset-specific
- * callback_mutex, below. They can nest. It is ok to first take
- * cgroup_mutex, then nest callback_mutex. We also require taking
- * task_lock() when dereferencing a task's cpuset pointer. See "The
- * task_lock() exception", at the end of this comment.
- *
- * A task must hold both mutexes to modify cpusets. If a task
- * holds cgroup_mutex, then it blocks others wanting that mutex,
- * ensuring that it is the only task able to also acquire callback_mutex
- * and be able to modify cpusets. It can perform various checks on
- * the cpuset structure first, knowing nothing will change. It can
- * also allocate memory while just holding cgroup_mutex. While it is
- * performing these checks, various callback routines can briefly
- * acquire callback_mutex to query cpusets. Once it is ready to make
- * the changes, it takes callback_mutex, blocking everyone else.
+ * There are two global mutexes guarding cpuset structures - cpuset_mutex
+ * and callback_mutex. The latter may nest inside the former. We also
+ * require taking task_lock() when dereferencing a task's cpuset pointer.
+ * See "The task_lock() exception", at the end of this comment.
+ *
+ * A task must hold both mutexes to modify cpusets. If a task holds
+ * cpuset_mutex, then it blocks others wanting that mutex, ensuring that it
+ * is the only task able to also acquire callback_mutex and be able to
+ * modify cpusets. It can perform various checks on the cpuset structure
+ * first, knowing nothing will change. It can also allocate memory while
+ * just holding cpuset_mutex. While it is performing these checks, various
+ * callback routines can briefly acquire callback_mutex to query cpusets.
+ * Once it is ready to make the changes, it takes callback_mutex, blocking
+ * everyone else.
*
* Calls to the kernel memory allocator can not be made while holding
* callback_mutex, as that would risk double tripping on callback_mutex
* guidelines for accessing subsystem state in kernel/cgroup.c
*/
+ static DEFINE_MUTEX(cpuset_mutex);
static DEFINE_MUTEX(callback_mutex);
/*
static char cpuset_nodelist[CPUSET_NODELIST_LEN];
static DEFINE_SPINLOCK(cpuset_buffer_lock);
+ /*
+ * CPU / memory hotplug is handled asynchronously.
+ */
+ static struct workqueue_struct *cpuset_propagate_hotplug_wq;
+
+ static void cpuset_hotplug_workfn(struct work_struct *work);
+ static void cpuset_propagate_hotplug_workfn(struct work_struct *work);
+ static void schedule_cpuset_propagate_hotplug(struct cpuset *cs);
+
+ static DECLARE_WORK(cpuset_hotplug_work, cpuset_hotplug_workfn);
+
/*
* This is ugly, but preserves the userspace API for existing cpuset
* users. If someone tries to mount the "cpuset" filesystem, we
struct cpumask *pmask)
{
while (cs && !cpumask_intersects(cs->cpus_allowed, cpu_online_mask))
- cs = cs->parent;
+ cs = parent_cs(cs);
if (cs)
cpumask_and(pmask, cs->cpus_allowed, cpu_online_mask);
else
{
while (cs && !nodes_intersects(cs->mems_allowed,
node_states[N_MEMORY]))
- cs = cs->parent;
+ cs = parent_cs(cs);
if (cs)
nodes_and(*pmask, cs->mems_allowed,
node_states[N_MEMORY]);
/*
* update task's spread flag if cpuset's page/slab spread flag is set
*
- * Called with callback_mutex/cgroup_mutex held
+ * Called with callback_mutex/cpuset_mutex held
*/
static void cpuset_update_task_spread_flag(struct cpuset *cs,
struct task_struct *tsk)
*
* One cpuset is a subset of another if all its allowed CPUs and
* Memory Nodes are a subset of the other, and its exclusive flags
- * are only set if the other's are set. Call holding cgroup_mutex.
+ * are only set if the other's are set. Call holding cpuset_mutex.
*/
static int is_cpuset_subset(const struct cpuset *p, const struct cpuset *q)
* If we replaced the flag and mask values of the current cpuset
* (cur) with those values in the trial cpuset (trial), would
* our various subset and exclusive rules still be valid? Presumes
- * cgroup_mutex held.
+ * cpuset_mutex held.
*
* 'cur' is the address of an actual, in-use cpuset. Operations
* such as list traversal that depend on the actual address of the
{
struct cgroup *cont;
struct cpuset *c, *par;
+ int ret;
+
+ rcu_read_lock();
/* Each of our child cpusets must be a subset of us */
- list_for_each_entry(cont, &cur->css.cgroup->children, sibling) {
- if (!is_cpuset_subset(cgroup_cs(cont), trial))
- return -EBUSY;
- }
+ ret = -EBUSY;
+ cpuset_for_each_child(c, cont, cur)
+ if (!is_cpuset_subset(c, trial))
+ goto out;
/* Remaining checks don't apply to root cpuset */
+ ret = 0;
if (cur == &top_cpuset)
- return 0;
+ goto out;
- par = cur->parent;
+ par = parent_cs(cur);
/* We must be a subset of our parent cpuset */
+ ret = -EACCES;
if (!is_cpuset_subset(trial, par))
- return -EACCES;
+ goto out;
/*
* If either I or some sibling (!= me) is exclusive, we can't
* overlap
*/
- list_for_each_entry(cont, &par->css.cgroup->children, sibling) {
- c = cgroup_cs(cont);
+ ret = -EINVAL;
+ cpuset_for_each_child(c, cont, par) {
if ((is_cpu_exclusive(trial) || is_cpu_exclusive(c)) &&
c != cur &&
cpumask_intersects(trial->cpus_allowed, c->cpus_allowed))
- return -EINVAL;
+ goto out;
if ((is_mem_exclusive(trial) || is_mem_exclusive(c)) &&
c != cur &&
nodes_intersects(trial->mems_allowed, c->mems_allowed))
- return -EINVAL;
+ goto out;
}
- /* Cpusets with tasks can't have empty cpus_allowed or mems_allowed */
- if (cgroup_task_count(cur->css.cgroup)) {
- if (cpumask_empty(trial->cpus_allowed) ||
- nodes_empty(trial->mems_allowed)) {
- return -ENOSPC;
- }
- }
+ /*
+ * Cpusets with tasks - existing or newly being attached - can't
+ * have empty cpus_allowed or mems_allowed.
+ */
+ ret = -ENOSPC;
+ if ((cgroup_task_count(cur->css.cgroup) || cur->attach_in_progress) &&
+ (cpumask_empty(trial->cpus_allowed) ||
+ nodes_empty(trial->mems_allowed)))
+ goto out;
- return 0;
+ ret = 0;
+ out:
+ rcu_read_unlock();
+ return ret;
}
#ifdef CONFIG_SMP
return;
}
- static void
- update_domain_attr_tree(struct sched_domain_attr *dattr, struct cpuset *c)
+ static void update_domain_attr_tree(struct sched_domain_attr *dattr,
+ struct cpuset *root_cs)
{
- LIST_HEAD(q);
-
- list_add(&c->stack_list, &q);
- while (!list_empty(&q)) {
- struct cpuset *cp;
- struct cgroup *cont;
- struct cpuset *child;
-
- cp = list_first_entry(&q, struct cpuset, stack_list);
- list_del(q.next);
+ struct cpuset *cp;
+ struct cgroup *pos_cgrp;
- if (cpumask_empty(cp->cpus_allowed))
+ rcu_read_lock();
+ cpuset_for_each_descendant_pre(cp, pos_cgrp, root_cs) {
+ /* skip the whole subtree if @cp doesn't have any CPU */
+ if (cpumask_empty(cp->cpus_allowed)) {
+ pos_cgrp = cgroup_rightmost_descendant(pos_cgrp);
continue;
+ }
if (is_sched_load_balance(cp))
update_domain_attr(dattr, cp);
-
- list_for_each_entry(cont, &cp->css.cgroup->children, sibling) {
- child = cgroup_cs(cont);
- list_add_tail(&child->stack_list, &q);
- }
}
+ rcu_read_unlock();
}
/*
* domains when operating in the severe memory shortage situations
* that could cause allocation failures below.
*
- * Must be called with cgroup_lock held.
+ * Must be called with cpuset_mutex held.
*
* The three key local variables below are:
* q - a linked-list queue of cpuset pointers, used to implement a
static int generate_sched_domains(cpumask_var_t **domains,
struct sched_domain_attr **attributes)
{
- LIST_HEAD(q); /* queue of cpusets to be scanned */
struct cpuset *cp; /* scans q */
struct cpuset **csa; /* array of all cpuset ptrs */
int csn; /* how many cpuset ptrs in csa so far */
struct sched_domain_attr *dattr; /* attributes for custom domains */
int ndoms = 0; /* number of sched domains in result */
int nslot; /* next empty doms[] struct cpumask slot */
+ struct cgroup *pos_cgrp;
doms = NULL;
dattr = NULL;
goto done;
csn = 0;
- list_add(&top_cpuset.stack_list, &q);
- while (!list_empty(&q)) {
- struct cgroup *cont;
- struct cpuset *child; /* scans child cpusets of cp */
-
- cp = list_first_entry(&q, struct cpuset, stack_list);
- list_del(q.next);
-
- if (cpumask_empty(cp->cpus_allowed))
- continue;
-
+ rcu_read_lock();
+ cpuset_for_each_descendant_pre(cp, pos_cgrp, &top_cpuset) {
/*
- * All child cpusets contain a subset of the parent's cpus, so
- * just skip them, and then we call update_domain_attr_tree()
- * to calc relax_domain_level of the corresponding sched
- * domain.
+ * Continue traversing beyond @cp iff @cp has some CPUs and
+ * isn't load balancing. The former is obvious. The
+ * latter: All child cpusets contain a subset of the
+ * parent's cpus, so just skip them, and then we call
+ * update_domain_attr_tree() to calc relax_domain_level of
+ * the corresponding sched domain.
*/
- if (is_sched_load_balance(cp)) {
- csa[csn++] = cp;
+ if (!cpumask_empty(cp->cpus_allowed) &&
+ !is_sched_load_balance(cp))
continue;
- }
- list_for_each_entry(cont, &cp->css.cgroup->children, sibling) {
- child = cgroup_cs(cont);
- list_add_tail(&child->stack_list, &q);
- }
- }
+ if (is_sched_load_balance(cp))
+ csa[csn++] = cp;
+
+ /* skip @cp's subtree */
+ pos_cgrp = cgroup_rightmost_descendant(pos_cgrp);
+ }
+ rcu_read_unlock();
for (i = 0; i < csn; i++)
csa[i]->pn = i;
/*
* Rebuild scheduler domains.
*
- * Call with neither cgroup_mutex held nor within get_online_cpus().
- * Takes both cgroup_mutex and get_online_cpus().
+ * If the flag 'sched_load_balance' of any cpuset with non-empty
+ * 'cpus' changes, or if the 'cpus' allowed changes in any cpuset
+ * which has that flag enabled, or if any cpuset with a non-empty
+ * 'cpus' is removed, then call this routine to rebuild the
+ * scheduler's dynamic sched domains.
*
- * Cannot be directly called from cpuset code handling changes
- * to the cpuset pseudo-filesystem, because it cannot be called
- * from code that already holds cgroup_mutex.
+ * Call with cpuset_mutex held. Takes get_online_cpus().
*/
- static void do_rebuild_sched_domains(struct work_struct *unused)
+ static void rebuild_sched_domains_locked(void)
{
struct sched_domain_attr *attr;
cpumask_var_t *doms;
int ndoms;
+ lockdep_assert_held(&cpuset_mutex);
get_online_cpus();
/* Generate domain masks and attrs */
- cgroup_lock();
ndoms = generate_sched_domains(&doms, &attr);
- cgroup_unlock();
/* Have scheduler rebuild the domains */
partition_sched_domains(ndoms, doms, attr);
put_online_cpus();
}
#else /* !CONFIG_SMP */
- static void do_rebuild_sched_domains(struct work_struct *unused)
+ static void rebuild_sched_domains_locked(void)
{
}
}
#endif /* CONFIG_SMP */
- static DECLARE_WORK(rebuild_sched_domains_work, do_rebuild_sched_domains);
-
- /*
- * Rebuild scheduler domains, asynchronously via workqueue.
- *
- * If the flag 'sched_load_balance' of any cpuset with non-empty
- * 'cpus' changes, or if the 'cpus' allowed changes in any cpuset
- * which has that flag enabled, or if any cpuset with a non-empty
- * 'cpus' is removed, then call this routine to rebuild the
- * scheduler's dynamic sched domains.
- *
- * The rebuild_sched_domains() and partition_sched_domains()
- * routines must nest cgroup_lock() inside get_online_cpus(),
- * but such cpuset changes as these must nest that locking the
- * other way, holding cgroup_lock() for much of the code.
- *
- * So in order to avoid an ABBA deadlock, the cpuset code handling
- * these user changes delegates the actual sched domain rebuilding
- * to a separate workqueue thread, which ends up processing the
- * above do_rebuild_sched_domains() function.
- */
- static void async_rebuild_sched_domains(void)
- {
- queue_work(cpuset_wq, &rebuild_sched_domains_work);
- }
-
- /*
- * Accomplishes the same scheduler domain rebuild as the above
- * async_rebuild_sched_domains(), however it directly calls the
- * rebuild routine synchronously rather than calling it via an
- * asynchronous work thread.
- *
- * This can only be called from code that is not holding
- * cgroup_mutex (not nested in a cgroup_lock() call.)
- */
void rebuild_sched_domains(void)
{
- do_rebuild_sched_domains(NULL);
+ mutex_lock(&cpuset_mutex);
+ rebuild_sched_domains_locked();
+ mutex_unlock(&cpuset_mutex);
}
/**
* @tsk: task to test
* @scan: struct cgroup_scanner contained in its struct cpuset_hotplug_scanner
*
- * Call with cgroup_mutex held. May take callback_mutex during call.
+ * Call with cpuset_mutex held. May take callback_mutex during call.
* Called for each task in a cgroup by cgroup_scan_tasks().
* Return nonzero if this tasks's cpus_allowed mask should be changed (in other
* words, if its mask is not equal to its cpuset's mask).
* cpus_allowed mask needs to be changed.
*
* We don't need to re-check for the cgroup/cpuset membership, since we're
- * holding cgroup_lock() at this point.
+ * holding cpuset_mutex at this point.
*/
static void cpuset_change_cpumask(struct task_struct *tsk,
struct cgroup_scanner *scan)
* @cs: the cpuset in which each task's cpus_allowed mask needs to be changed
* @heap: if NULL, defer allocating heap memory to cgroup_scan_tasks()
*
- * Called with cgroup_mutex held
+ * Called with cpuset_mutex held
*
* The cgroup_scan_tasks() function will scan all the tasks in a cgroup,
* calling callback functions for each.
heap_free(&heap);
if (is_load_balanced)
- async_rebuild_sched_domains();
+ rebuild_sched_domains_locked();
return 0;
}
* Temporarilly set tasks mems_allowed to target nodes of migration,
* so that the migration code can allocate pages on these nodes.
*
- * Call holding cgroup_mutex, so current's cpuset won't change
+ * Call holding cpuset_mutex, so current's cpuset won't change
* during this call, as manage_mutex holds off any cpuset_attach()
* calls. Therefore we don't need to take task_lock around the
* call to guarantee_online_mems(), as we know no one is changing
/*
* Update task's mems_allowed and rebind its mempolicy and vmas' mempolicy
* of it to cpuset's new mems_allowed, and migrate pages to new nodes if
- * memory_migrate flag is set. Called with cgroup_mutex held.
+ * memory_migrate flag is set. Called with cpuset_mutex held.
*/
static void cpuset_change_nodemask(struct task_struct *p,
struct cgroup_scanner *scan)
struct cpuset *cs;
int migrate;
const nodemask_t *oldmem = scan->data;
- static nodemask_t newmems; /* protected by cgroup_mutex */
+ static nodemask_t newmems; /* protected by cpuset_mutex */
cs = cgroup_cs(scan->cg);
guarantee_online_mems(cs, &newmems);
* @oldmem: old mems_allowed of cpuset cs
* @heap: if NULL, defer allocating heap memory to cgroup_scan_tasks()
*
- * Called with cgroup_mutex held
+ * Called with cpuset_mutex held
* No return value. It's guaranteed that cgroup_scan_tasks() always returns 0
* if @heap != NULL.
*/
* take while holding tasklist_lock. Forks can happen - the
* mpol_dup() cpuset_being_rebound check will catch such forks,
* and rebind their vma mempolicies too. Because we still hold
- * the global cgroup_mutex, we know that no other rebind effort
+ * the global cpuset_mutex, we know that no other rebind effort
* will be contending for the global variable cpuset_being_rebound.
* It's ok if we rebind the same mm twice; mpol_rebind_mm()
* is idempotent. Also migrate pages in each mm to new nodes.
* mempolicies and if the cpuset is marked 'memory_migrate',
* migrate the tasks pages to the new memory.
*
- * Call with cgroup_mutex held. May take callback_mutex during call.
+ * Call with cpuset_mutex held. May take callback_mutex during call.
* Will take tasklist_lock, scan tasklist for tasks in cpuset cs,
* lock each such tasks mm->mmap_sem, scan its vma's and rebind
* their mempolicies to the cpusets new mems_allowed.
cs->relax_domain_level = val;
if (!cpumask_empty(cs->cpus_allowed) &&
is_sched_load_balance(cs))
- async_rebuild_sched_domains();
+ rebuild_sched_domains_locked();
}
return 0;
* Called by cgroup_scan_tasks() for each task in a cgroup.
*
* We don't need to re-check for the cgroup/cpuset membership, since we're
- * holding cgroup_lock() at this point.
+ * holding cpuset_mutex at this point.
*/
static void cpuset_change_flag(struct task_struct *tsk,
struct cgroup_scanner *scan)
* @cs: the cpuset in which each task's spread flags needs to be changed
* @heap: if NULL, defer allocating heap memory to cgroup_scan_tasks()
*
- * Called with cgroup_mutex held
+ * Called with cpuset_mutex held
*
* The cgroup_scan_tasks() function will scan all the tasks in a cgroup,
* calling callback functions for each.
* cs: the cpuset to update
* turning_on: whether the flag is being set or cleared
*
- * Call with cgroup_mutex held.
+ * Call with cpuset_mutex held.
*/
static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs,
mutex_unlock(&callback_mutex);
if (!cpumask_empty(trialcs->cpus_allowed) && balance_flag_changed)
- async_rebuild_sched_domains();
+ rebuild_sched_domains_locked();
if (spread_flag_changed)
update_tasks_flags(cs, &heap);
return val;
}
- /*
- * Protected by cgroup_lock. The nodemasks must be stored globally because
- * dynamically allocating them is not allowed in can_attach, and they must
- * persist until attach.
- */
- static cpumask_var_t cpus_attach;
- static nodemask_t cpuset_attach_nodemask_from;
- static nodemask_t cpuset_attach_nodemask_to;
-
- /* Called by cgroups to determine if a cpuset is usable; cgroup_mutex held */
+ /* Called by cgroups to determine if a cpuset is usable; cpuset_mutex held */
static int cpuset_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
{
struct cpuset *cs = cgroup_cs(cgrp);
struct task_struct *task;
int ret;
+ mutex_lock(&cpuset_mutex);
+
+ ret = -ENOSPC;
if (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))
- return -ENOSPC;
+ goto out_unlock;
cgroup_taskset_for_each(task, cgrp, tset) {
/*
* set_cpus_allowed_ptr() on all attached tasks before
* cpus_allowed may be changed.
*/
+ ret = -EINVAL;
if (task->flags & PF_THREAD_BOUND)
- return -EINVAL;
- if ((ret = security_task_setscheduler(task)))
- return ret;
+ goto out_unlock;
+ ret = security_task_setscheduler(task);
+ if (ret)
+ goto out_unlock;
}
- /* prepare for attach */
- if (cs == &top_cpuset)
- cpumask_copy(cpus_attach, cpu_possible_mask);
- else
- guarantee_online_cpus(cs, cpus_attach);
-
- guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
+ /*
+ * Mark attach is in progress. This makes validate_change() fail
+ * changes which zero cpus/mems_allowed.
+ */
+ cs->attach_in_progress++;
+ ret = 0;
+ out_unlock:
+ mutex_unlock(&cpuset_mutex);
+ return ret;
+ }
- return 0;
+ static void cpuset_cancel_attach(struct cgroup *cgrp,
+ struct cgroup_taskset *tset)
+ {
+ mutex_lock(&cpuset_mutex);
+ cgroup_cs(cgrp)->attach_in_progress--;
+ mutex_unlock(&cpuset_mutex);
}
+ /*
+ * Protected by cpuset_mutex. cpus_attach is used only by cpuset_attach()
+ * but we can't allocate it dynamically there. Define it global and
+ * allocate from cpuset_init().
+ */
+ static cpumask_var_t cpus_attach;
+
static void cpuset_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
{
+ /* static bufs protected by cpuset_mutex */
+ static nodemask_t cpuset_attach_nodemask_from;
+ static nodemask_t cpuset_attach_nodemask_to;
struct mm_struct *mm;
struct task_struct *task;
struct task_struct *leader = cgroup_taskset_first(tset);
struct cpuset *cs = cgroup_cs(cgrp);
struct cpuset *oldcs = cgroup_cs(oldcgrp);
+ mutex_lock(&cpuset_mutex);
+
+ /* prepare for attach */
+ if (cs == &top_cpuset)
+ cpumask_copy(cpus_attach, cpu_possible_mask);
+ else
+ guarantee_online_cpus(cs, cpus_attach);
+
+ guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
+
cgroup_taskset_for_each(task, cgrp, tset) {
/*
* can_attach beforehand should guarantee that this doesn't
&cpuset_attach_nodemask_to);
mmput(mm);
}
+
+ cs->attach_in_progress--;
+
+ /*
+ * We may have raced with CPU/memory hotunplug. Trigger hotplug
+ * propagation if @cs doesn't have any CPU or memory. It will move
+ * the newly added tasks to the nearest parent which can execute.
+ */
+ if (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed))
+ schedule_cpuset_propagate_hotplug(cs);
+
+ mutex_unlock(&cpuset_mutex);
}
/* The various types of files and directories in a cpuset file system */
static int cpuset_write_u64(struct cgroup *cgrp, struct cftype *cft, u64 val)
{
- int retval = 0;
struct cpuset *cs = cgroup_cs(cgrp);
cpuset_filetype_t type = cft->private;
+ int retval = -ENODEV;
- if (!cgroup_lock_live_group(cgrp))
- return -ENODEV;
+ mutex_lock(&cpuset_mutex);
+ if (!is_cpuset_online(cs))
+ goto out_unlock;
switch (type) {
case FILE_CPU_EXCLUSIVE:
retval = -EINVAL;
break;
}
- cgroup_unlock();
+ out_unlock:
+ mutex_unlock(&cpuset_mutex);
return retval;
}
static int cpuset_write_s64(struct cgroup *cgrp, struct cftype *cft, s64 val)
{
- int retval = 0;
struct cpuset *cs = cgroup_cs(cgrp);
cpuset_filetype_t type = cft->private;
+ int retval = -ENODEV;
- if (!cgroup_lock_live_group(cgrp))
- return -ENODEV;
+ mutex_lock(&cpuset_mutex);
+ if (!is_cpuset_online(cs))
+ goto out_unlock;
switch (type) {
case FILE_SCHED_RELAX_DOMAIN_LEVEL:
retval = -EINVAL;
break;
}
- cgroup_unlock();
+ out_unlock:
+ mutex_unlock(&cpuset_mutex);
return retval;
}
static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft,
const char *buf)
{
- int retval = 0;
struct cpuset *cs = cgroup_cs(cgrp);
struct cpuset *trialcs;
+ int retval = -ENODEV;
- if (!cgroup_lock_live_group(cgrp))
- return -ENODEV;
+ /*
+ * CPU or memory hotunplug may leave @cs w/o any execution
+ * resources, in which case the hotplug code asynchronously updates
+ * configuration and transfers all tasks to the nearest ancestor
+ * which can execute.
+ *
+ * As writes to "cpus" or "mems" may restore @cs's execution
+ * resources, wait for the previously scheduled operations before
+ * proceeding, so that we don't end up keep removing tasks added
+ * after execution capability is restored.
+ *
+ * Flushing cpuset_hotplug_work is enough to synchronize against
+ * hotplug hanlding; however, cpuset_attach() may schedule
+ * propagation work directly. Flush the workqueue too.
+ */
+ flush_work(&cpuset_hotplug_work);
+ flush_workqueue(cpuset_propagate_hotplug_wq);
+
+ mutex_lock(&cpuset_mutex);
+ if (!is_cpuset_online(cs))
+ goto out_unlock;
trialcs = alloc_trial_cpuset(cs);
if (!trialcs) {
retval = -ENOMEM;
- goto out;
+ goto out_unlock;
}
switch (cft->private) {
}
free_trial_cpuset(trialcs);
- out:
- cgroup_unlock();
+ out_unlock:
+ mutex_unlock(&cpuset_mutex);
return retval;
}
static struct cgroup_subsys_state *cpuset_css_alloc(struct cgroup *cont)
{
- struct cgroup *parent_cg = cont->parent;
- struct cgroup *tmp_cg;
- struct cpuset *parent, *cs;
+ struct cpuset *cs;
- if (!parent_cg)
+ if (!cont->parent)
return &top_cpuset.css;
- parent = cgroup_cs(parent_cg);
- cs = kmalloc(sizeof(*cs), GFP_KERNEL);
+ cs = kzalloc(sizeof(*cs), GFP_KERNEL);
if (!cs)
return ERR_PTR(-ENOMEM);
if (!alloc_cpumask_var(&cs->cpus_allowed, GFP_KERNEL)) {
return ERR_PTR(-ENOMEM);
}
- cs->flags = 0;
- if (is_spread_page(parent))
- set_bit(CS_SPREAD_PAGE, &cs->flags);
- if (is_spread_slab(parent))
- set_bit(CS_SPREAD_SLAB, &cs->flags);
set_bit(CS_SCHED_LOAD_BALANCE, &cs->flags);
cpumask_clear(cs->cpus_allowed);
nodes_clear(cs->mems_allowed);
fmeter_init(&cs->fmeter);
+ INIT_WORK(&cs->hotplug_work, cpuset_propagate_hotplug_workfn);
cs->relax_domain_level = -1;
- cs->parent = parent;
+ return &cs->css;
+ }
+
+ static int cpuset_css_online(struct cgroup *cgrp)
+ {
+ struct cpuset *cs = cgroup_cs(cgrp);
+ struct cpuset *parent = parent_cs(cs);
+ struct cpuset *tmp_cs;
+ struct cgroup *pos_cg;
+
+ if (!parent)
+ return 0;
+
+ mutex_lock(&cpuset_mutex);
+
+ set_bit(CS_ONLINE, &cs->flags);
+ if (is_spread_page(parent))
+ set_bit(CS_SPREAD_PAGE, &cs->flags);
+ if (is_spread_slab(parent))
+ set_bit(CS_SPREAD_SLAB, &cs->flags);
+
number_of_cpusets++;
- if (!test_bit(CGRP_CPUSET_CLONE_CHILDREN, &cont->flags))
- goto skip_clone;
+ if (!test_bit(CGRP_CPUSET_CLONE_CHILDREN, &cgrp->flags))
+ goto out_unlock;
/*
* Clone @parent's configuration if CGRP_CPUSET_CLONE_CHILDREN is
* changed to grant parent->cpus_allowed-sibling_cpus_exclusive
* (and likewise for mems) to the new cgroup.
*/
- list_for_each_entry(tmp_cg, &parent_cg->children, sibling) {
- struct cpuset *tmp_cs = cgroup_cs(tmp_cg);
-
- if (is_mem_exclusive(tmp_cs) || is_cpu_exclusive(tmp_cs))
- goto skip_clone;
+ rcu_read_lock();
+ cpuset_for_each_child(tmp_cs, pos_cg, parent) {
+ if (is_mem_exclusive(tmp_cs) || is_cpu_exclusive(tmp_cs)) {
+ rcu_read_unlock();
+ goto out_unlock;
+ }
}
+ rcu_read_unlock();
mutex_lock(&callback_mutex);
cs->mems_allowed = parent->mems_allowed;
cpumask_copy(cs->cpus_allowed, parent->cpus_allowed);
mutex_unlock(&callback_mutex);
- skip_clone:
- return &cs->css;
+ out_unlock:
+ mutex_unlock(&cpuset_mutex);
+ return 0;
+ }
+
+ static void cpuset_css_offline(struct cgroup *cgrp)
+ {
+ struct cpuset *cs = cgroup_cs(cgrp);
+
+ mutex_lock(&cpuset_mutex);
+
+ if (is_sched_load_balance(cs))
+ update_flag(CS_SCHED_LOAD_BALANCE, cs, 0);
+
+ number_of_cpusets--;
+ clear_bit(CS_ONLINE, &cs->flags);
+
+ mutex_unlock(&cpuset_mutex);
}
/*
* If the cpuset being removed has its flag 'sched_load_balance'
* enabled, then simulate turning sched_load_balance off, which
- * will call async_rebuild_sched_domains().
+ * will call rebuild_sched_domains_locked().
*/
static void cpuset_css_free(struct cgroup *cont)
{
struct cpuset *cs = cgroup_cs(cont);
- if (is_sched_load_balance(cs))
- update_flag(CS_SCHED_LOAD_BALANCE, cs, 0);
-
- number_of_cpusets--;
free_cpumask_var(cs->cpus_allowed);
kfree(cs);
}
struct cgroup_subsys cpuset_subsys = {
.name = "cpuset",
.css_alloc = cpuset_css_alloc,
+ .css_online = cpuset_css_online,
+ .css_offline = cpuset_css_offline,
.css_free = cpuset_css_free,
.can_attach = cpuset_can_attach,
+ .cancel_attach = cpuset_cancel_attach,
.attach = cpuset_attach,
.subsys_id = cpuset_subsys_id,
.base_cftypes = files,
{
struct cgroup *new_cgroup = scan->data;
+ cgroup_lock();
cgroup_attach_task(new_cgroup, tsk);
+ cgroup_unlock();
}
/**
* @from: cpuset in which the tasks currently reside
* @to: cpuset to which the tasks will be moved
*
- * Called with cgroup_mutex held
+ * Called with cpuset_mutex held
* callback_mutex must not be held, as cpuset_attach() will take it.
*
* The cgroup_scan_tasks() function will scan all the tasks in a cgroup,
* removing that CPU or node from all cpusets. If this removes the
* last CPU or node from a cpuset, then move the tasks in the empty
* cpuset to its next-highest non-empty parent.
- *
- * Called with cgroup_mutex held
- * callback_mutex must not be held, as cpuset_attach() will take it.
*/
static void remove_tasks_in_empty_cpuset(struct cpuset *cs)
{
struct cpuset *parent;
- /*
- * The cgroup's css_sets list is in use if there are tasks
- * in the cpuset; the list is empty if there are none;
- * the cs->css.refcnt seems always 0.
- */
- if (list_empty(&cs->css.cgroup->css_sets))
- return;
-
/*
* Find its next-highest non-empty parent, (top cpuset
* has online cpus, so can't be empty).
*/
- parent = cs->parent;
+ parent = parent_cs(cs);
while (cpumask_empty(parent->cpus_allowed) ||
nodes_empty(parent->mems_allowed))
- parent = parent->parent;
+ parent = parent_cs(parent);
move_member_tasks_to_cpuset(cs, parent);
}
- /*
- * Helper function to traverse cpusets.
- * It can be used to walk the cpuset tree from top to bottom, completing
- * one layer before dropping down to the next (thus always processing a
- * node before any of its children).
+ /**
+ * cpuset_propagate_hotplug_workfn - propagate CPU/memory hotplug to a cpuset
+ * @cs: cpuset in interest
+ *
+ * Compare @cs's cpu and mem masks against top_cpuset and if some have gone
+ * offline, update @cs accordingly. If @cs ends up with no CPU or memory,
+ * all its tasks are moved to the nearest ancestor with both resources.
*/
- static struct cpuset *cpuset_next(struct list_head *queue)
+ static void cpuset_propagate_hotplug_workfn(struct work_struct *work)
{
- struct cpuset *cp;
- struct cpuset *child; /* scans child cpusets of cp */
- struct cgroup *cont;
+ static cpumask_t off_cpus;
+ static nodemask_t off_mems, tmp_mems;
+ struct cpuset *cs = container_of(work, struct cpuset, hotplug_work);
+ bool is_empty;
- if (list_empty(queue))
- return NULL;
+ mutex_lock(&cpuset_mutex);
+
+ cpumask_andnot(&off_cpus, cs->cpus_allowed, top_cpuset.cpus_allowed);
+ nodes_andnot(off_mems, cs->mems_allowed, top_cpuset.mems_allowed);
- cp = list_first_entry(queue, struct cpuset, stack_list);
- list_del(queue->next);
- list_for_each_entry(cont, &cp->css.cgroup->children, sibling) {
- child = cgroup_cs(cont);
- list_add_tail(&child->stack_list, queue);
+ /* remove offline cpus from @cs */
+ if (!cpumask_empty(&off_cpus)) {
+ mutex_lock(&callback_mutex);
+ cpumask_andnot(cs->cpus_allowed, cs->cpus_allowed, &off_cpus);
+ mutex_unlock(&callback_mutex);
+ update_tasks_cpumask(cs, NULL);
}
- return cp;
+ /* remove offline mems from @cs */
+ if (!nodes_empty(off_mems)) {
+ tmp_mems = cs->mems_allowed;
+ mutex_lock(&callback_mutex);
+ nodes_andnot(cs->mems_allowed, cs->mems_allowed, off_mems);
+ mutex_unlock(&callback_mutex);
+ update_tasks_nodemask(cs, &tmp_mems, NULL);
+ }
+
+ is_empty = cpumask_empty(cs->cpus_allowed) ||
+ nodes_empty(cs->mems_allowed);
+
+ mutex_unlock(&cpuset_mutex);
+
+ /*
+ * If @cs became empty, move tasks to the nearest ancestor with
+ * execution resources. This is full cgroup operation which will
+ * also call back into cpuset. Should be done outside any lock.
+ */
+ if (is_empty)
+ remove_tasks_in_empty_cpuset(cs);
+
+ /* the following may free @cs, should be the last operation */
+ css_put(&cs->css);
}
+ /**
+ * schedule_cpuset_propagate_hotplug - schedule hotplug propagation to a cpuset
+ * @cs: cpuset of interest
+ *
+ * Schedule cpuset_propagate_hotplug_workfn() which will update CPU and
+ * memory masks according to top_cpuset.
+ */
+ static void schedule_cpuset_propagate_hotplug(struct cpuset *cs)
+ {
+ /*
+ * Pin @cs. The refcnt will be released when the work item
+ * finishes executing.
+ */
+ if (!css_tryget(&cs->css))
+ return;
- /*
- * Walk the specified cpuset subtree upon a hotplug operation (CPU/Memory
- * online/offline) and update the cpusets accordingly.
- * For regular CPU/Mem hotplug, look for empty cpusets; the tasks of such
- * cpuset must be moved to a parent cpuset.
+ /*
+ * Queue @cs->hotplug_work. If already pending, lose the css ref.
+ * cpuset_propagate_hotplug_wq is ordered and propagation will
+ * happen in the order this function is called.
+ */
+ if (!queue_work(cpuset_propagate_hotplug_wq, &cs->hotplug_work))
+ css_put(&cs->css);
+ }
+
+ /**
+ * cpuset_hotplug_workfn - handle CPU/memory hotunplug for a cpuset
*
- * Called with cgroup_mutex held. We take callback_mutex to modify
- * cpus_allowed and mems_allowed.
+ * This function is called after either CPU or memory configuration has
+ * changed and updates cpuset accordingly. The top_cpuset is always
+ * synchronized to cpu_active_mask and N_MEMORY, which is necessary in
+ * order to make cpusets transparent (of no affect) on systems that are
+ * actively using CPU hotplug but making no active use of cpusets.
*
- * This walk processes the tree from top to bottom, completing one layer
- * before dropping down to the next. It always processes a node before
- * any of its children.
+ * Non-root cpusets are only affected by offlining. If any CPUs or memory
+ * nodes have been taken down, cpuset_propagate_hotplug() is invoked on all
+ * descendants.
*
- * In the case of memory hot-unplug, it will remove nodes from N_MEMORY
- * if all present pages from a node are offlined.
+ * Note that CPU offlining during suspend is ignored. We don't modify
+ * cpusets across suspend/resume cycles at all.
*/
- static void
- scan_cpusets_upon_hotplug(struct cpuset *root, enum hotplug_event event)
+ static void cpuset_hotplug_workfn(struct work_struct *work)
{
- LIST_HEAD(queue);
- struct cpuset *cp; /* scans cpusets being updated */
- static nodemask_t oldmems; /* protected by cgroup_mutex */
+ static cpumask_t new_cpus, tmp_cpus;
+ static nodemask_t new_mems, tmp_mems;
+ bool cpus_updated, mems_updated;
+ bool cpus_offlined, mems_offlined;
- list_add_tail((struct list_head *)&root->stack_list, &queue);
+ mutex_lock(&cpuset_mutex);
- switch (event) {
- case CPUSET_CPU_OFFLINE:
- while ((cp = cpuset_next(&queue)) != NULL) {
+ /* fetch the available cpus/mems and find out which changed how */
+ cpumask_copy(&new_cpus, cpu_active_mask);
+ new_mems = node_states[N_MEMORY];
- /* Continue past cpusets with all cpus online */
- if (cpumask_subset(cp->cpus_allowed, cpu_active_mask))
- continue;
+ cpus_updated = !cpumask_equal(top_cpuset.cpus_allowed, &new_cpus);
+ cpus_offlined = cpumask_andnot(&tmp_cpus, top_cpuset.cpus_allowed,
+ &new_cpus);
- /* Remove offline cpus from this cpuset. */
- mutex_lock(&callback_mutex);
- cpumask_and(cp->cpus_allowed, cp->cpus_allowed,
- cpu_active_mask);
- mutex_unlock(&callback_mutex);
+ mems_updated = !nodes_equal(top_cpuset.mems_allowed, new_mems);
+ nodes_andnot(tmp_mems, top_cpuset.mems_allowed, new_mems);
+ mems_offlined = !nodes_empty(tmp_mems);
- /* Move tasks from the empty cpuset to a parent */
- if (cpumask_empty(cp->cpus_allowed))
- remove_tasks_in_empty_cpuset(cp);
- else
- update_tasks_cpumask(cp, NULL);
- }
- break;
+ /* synchronize cpus_allowed to cpu_active_mask */
+ if (cpus_updated) {
+ mutex_lock(&callback_mutex);
+ cpumask_copy(top_cpuset.cpus_allowed, &new_cpus);
+ mutex_unlock(&callback_mutex);
+ /* we don't mess with cpumasks of tasks in top_cpuset */
+ }
- case CPUSET_MEM_OFFLINE:
- while ((cp = cpuset_next(&queue)) != NULL) {
+ /* synchronize mems_allowed to N_MEMORY */
+ if (mems_updated) {
+ tmp_mems = top_cpuset.mems_allowed;
+ mutex_lock(&callback_mutex);
+ top_cpuset.mems_allowed = new_mems;
+ mutex_unlock(&callback_mutex);
+ update_tasks_nodemask(&top_cpuset, &tmp_mems, NULL);
+ }
- /* Continue past cpusets with all mems online */
- if (nodes_subset(cp->mems_allowed,
- node_states[N_MEMORY]))
- continue;
+ /* if cpus or mems went down, we need to propagate to descendants */
+ if (cpus_offlined || mems_offlined) {
+ struct cpuset *cs;
+ struct cgroup *pos_cgrp;
- oldmems = cp->mems_allowed;
+ rcu_read_lock();
+ cpuset_for_each_descendant_pre(cs, pos_cgrp, &top_cpuset)
+ schedule_cpuset_propagate_hotplug(cs);
+ rcu_read_unlock();
+ }
- /* Remove offline mems from this cpuset. */
- mutex_lock(&callback_mutex);
- nodes_and(cp->mems_allowed, cp->mems_allowed,
- node_states[N_MEMORY]);
- mutex_unlock(&callback_mutex);
+ mutex_unlock(&cpuset_mutex);
- /* Move tasks from the empty cpuset to a parent */
- if (nodes_empty(cp->mems_allowed))
- remove_tasks_in_empty_cpuset(cp);
- else
- update_tasks_nodemask(cp, &oldmems, NULL);
- }
+ /* wait for propagations to finish */
+ flush_workqueue(cpuset_propagate_hotplug_wq);
+
+ /* rebuild sched domains if cpus_allowed has changed */
+ if (cpus_updated) {
+ struct sched_domain_attr *attr;
+ cpumask_var_t *doms;
+ int ndoms;
+
+ mutex_lock(&cpuset_mutex);
+ ndoms = generate_sched_domains(&doms, &attr);
+ mutex_unlock(&cpuset_mutex);
+
+ partition_sched_domains(ndoms, doms, attr);
}
}
- /*
- * The top_cpuset tracks what CPUs and Memory Nodes are online,
- * period. This is necessary in order to make cpusets transparent
- * (of no affect) on systems that are actively using CPU hotplug
- * but making no active use of cpusets.
- *
- * The only exception to this is suspend/resume, where we don't
- * modify cpusets at all.
- *
- * This routine ensures that top_cpuset.cpus_allowed tracks
- * cpu_active_mask on each CPU hotplug (cpuhp) event.
- *
- * Called within get_online_cpus(). Needs to call cgroup_lock()
- * before calling generate_sched_domains().
- *
- * @cpu_online: Indicates whether this is a CPU online event (true) or
- * a CPU offline event (false).
- */
void cpuset_update_active_cpus(bool cpu_online)
{
- struct sched_domain_attr *attr;
- cpumask_var_t *doms;
- int ndoms;
-
- cgroup_lock();
- mutex_lock(&callback_mutex);
- cpumask_copy(top_cpuset.cpus_allowed, cpu_active_mask);
- mutex_unlock(&callback_mutex);
-
- if (!cpu_online)
- scan_cpusets_upon_hotplug(&top_cpuset, CPUSET_CPU_OFFLINE);
-
- ndoms = generate_sched_domains(&doms, &attr);
- cgroup_unlock();
-
- /* Have scheduler rebuild the domains */
- partition_sched_domains(ndoms, doms, attr);
+ /*
+ * We're inside cpu hotplug critical region which usually nests
+ * inside cgroup synchronization. Bounce actual hotplug processing
+ * to a work item to avoid reverse locking order.
+ *
+ * We still need to do partition_sched_domains() synchronously;
+ * otherwise, the scheduler will get confused and put tasks to the
+ * dead CPU. Fall back to the default single domain.
+ * cpuset_hotplug_workfn() will rebuild it as necessary.
+ */
+ partition_sched_domains(1, NULL, NULL);
+ schedule_work(&cpuset_hotplug_work);
}
#ifdef CONFIG_MEMORY_HOTPLUG
static int cpuset_track_online_nodes(struct notifier_block *self,
unsigned long action, void *arg)
{
- static nodemask_t oldmems; /* protected by cgroup_mutex */
-
- cgroup_lock();
- switch (action) {
- case MEM_ONLINE:
- oldmems = top_cpuset.mems_allowed;
- mutex_lock(&callback_mutex);
- top_cpuset.mems_allowed = node_states[N_MEMORY];
- mutex_unlock(&callback_mutex);
- update_tasks_nodemask(&top_cpuset, &oldmems, NULL);
- break;
- case MEM_OFFLINE:
- /*
- * needn't update top_cpuset.mems_allowed explicitly because
- * scan_cpusets_upon_hotplug() will update it.
- */
- scan_cpusets_upon_hotplug(&top_cpuset, CPUSET_MEM_OFFLINE);
- break;
- default:
- break;
- }
- cgroup_unlock();
-
+ schedule_work(&cpuset_hotplug_work);
return NOTIFY_OK;
}
#endif
hotplug_memory_notifier(cpuset_track_online_nodes, 10);
- cpuset_wq = create_singlethread_workqueue("cpuset");
- BUG_ON(!cpuset_wq);
+ cpuset_propagate_hotplug_wq =
+ alloc_ordered_workqueue("cpuset_hotplug", 0);
+ BUG_ON(!cpuset_propagate_hotplug_wq);
}
/**
*/
static const struct cpuset *nearest_hardwall_ancestor(const struct cpuset *cs)
{
- while (!(is_mem_exclusive(cs) || is_mem_hardwall(cs)) && cs->parent)
- cs = cs->parent;
+ while (!(is_mem_exclusive(cs) || is_mem_hardwall(cs)) && parent_cs(cs))
+ cs = parent_cs(cs);
return cs;
}
return 0;
}
- /**
- * cpuset_unlock - release lock on cpuset changes
- *
- * Undo the lock taken in a previous cpuset_lock() call.
- */
-
- void cpuset_unlock(void)
- {
- mutex_unlock(&callback_mutex);
- }
-
/**
* cpuset_mem_spread_node() - On which node to begin search for a file page
* cpuset_slab_spread_node() - On which node to begin search for a slab page
dentry = task_cs(tsk)->css.cgroup->dentry;
spin_lock(&cpuset_buffer_lock);
- snprintf(cpuset_name, CPUSET_NAME_LEN,
- dentry ? (const char *)dentry->d_name.name : "/");
+
+ if (!dentry) {
+ strcpy(cpuset_name, "/");
+ } else {
+ spin_lock(&dentry->d_lock);
+ strlcpy(cpuset_name, (const char *)dentry->d_name.name,
+ CPUSET_NAME_LEN);
+ spin_unlock(&dentry->d_lock);
+ }
+
nodelist_scnprintf(cpuset_nodelist, CPUSET_NODELIST_LEN,
tsk->mems_allowed);
printk(KERN_INFO "%s cpuset=%s mems_allowed=%s\n",
* - Used for /proc/<pid>/cpuset.
* - No need to task_lock(tsk) on this tsk->cpuset reference, as it
* doesn't really matter if tsk->cpuset changes after we read it,
- * and we take cgroup_mutex, keeping cpuset_attach() from changing it
+ * and we take cpuset_mutex, keeping cpuset_attach() from changing it
* anyway.
*/
static int proc_cpuset_show(struct seq_file *m, void *unused_v)
if (!tsk)
goto out_free;
- retval = -EINVAL;
- cgroup_lock();
+ rcu_read_lock();
css = task_subsys_state(tsk, cpuset_subsys_id);
retval = cgroup_path(css->cgroup, buf, PAGE_SIZE);
+ rcu_read_unlock();
if (retval < 0)
- goto out_unlock;
+ goto out_put_task;
seq_puts(m, buf);
seq_putc(m, '\n');
- out_unlock:
- cgroup_unlock();
+ out_put_task:
put_task_struct(tsk);
out_free:
kfree(buf);