2.6.32.22-stable review
Subsystems (53)
cover 2.6.32.22-stable review
[Note, I do still have patches that people have sent me for inclusion in the .32-stable tree in my queue, but I figured this series was already big enough that it should go out now. If you notice, I _did_ apply all patches that went through Linus's tree with a [email protected] marking on it, so people might consider using that method instead...]
This is the start of the stable review cycle for the 2.6.32.22 release. There are 123 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let us know. If anyone is a maintainer of the proper subsystem, and wants to add a Signed-off-by: line to the patch, please respond with it.
Responses should be made by September 20, 2010 19:00:00 UTC. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
kernel.org/pub/linux/kernel/v2.6/stable-review/patch-2.6.32.22-rc1.gz
and the diffstat can be found below.
thanks,
greg k-h
Makefile | 2 +- arch/arm/kernel/entry-common.S | 2 + arch/ia64/include/asm/compat.h | 2 +- arch/ia64/kernel/msi_ia64.c | 2 +- arch/ia64/sn/kernel/msi_sn.c | 2 +- arch/mips/include/asm/compat.h | 2 +- arch/parisc/include/asm/compat.h | 2 +- arch/powerpc/include/asm/compat.h | 2 +- arch/s390/include/asm/compat.h | 2 +- arch/sparc/include/asm/compat.h | 2 +- arch/x86/ia32/ia32entry.S | 22 +- arch/x86/include/asm/compat.h | 2 +- arch/x86/include/asm/tsc.h | 2 + arch/x86/kernel/apic/io_apic.c | 2 +- arch/x86/kernel/tsc.c | 38 +++ arch/x86/oprofile/nmi_int.c | 22 +- arch/x86/power/cpu.c | 2 + drivers/ata/libata-core.c | 14 +- drivers/ata/libata-eh.c | 4 + drivers/ata/sata_mv.c | 44 +++- drivers/gpu/drm/drm_crtc_helper.c | 4 +- drivers/gpu/drm/i915/i915_dma.c | 12 +- drivers/gpu/drm/i915/i915_gem.c | 1 + drivers/gpu/drm/i915/intel_display.c | 5 +- drivers/hid/usbhid/hid-core.c | 18 +- drivers/hwmon/f75375s.c | 6 +- drivers/hwmon/k8temp.c | 35 ++- drivers/input/serio/i8042.c | 2 +- drivers/mmc/host/tmio_mmc.c | 7 +- drivers/mmc/host/tmio_mmc.h | 13 +- drivers/net/tun.c | 3 +- drivers/net/wireless/ath/ath5k/base.c | 4 + drivers/net/wireless/ath/ath9k/eeprom.h | 2 +- drivers/net/wireless/ath/regd.h | 1 - drivers/net/wireless/p54/txrx.c | 2 +- drivers/oprofile/buffer_sync.c | 27 +- drivers/oprofile/cpu_buffer.c | 2 - drivers/pci/msi.c | 27 ++- drivers/power/apm_power.c | 1 + drivers/staging/hv/RingBuffer.c | 2 +- drivers/staging/hv/StorVscApi.h | 4 +- drivers/staging/hv/netvsc_drv.c | 3 + drivers/staging/hv/storvsc_drv.c | 9 +- drivers/usb/class/cdc-acm.c | 85 ++++++- drivers/usb/gadget/rndis.c | 10 +- drivers/usb/host/ehci-ppc-of.c | 12 +- drivers/usb/serial/cp210x.c | 10 +- drivers/usb/serial/ftdi_sio.c | 8 + drivers/usb/serial/ftdi_sio_ids.h | 12 + drivers/usb/serial/mos7840.c | 55 +++- drivers/xen/events.c | 21 +- fs/binfmt_misc.c | 2 +- fs/fuse/dev.c | 16 +- fs/nfs/client.c | 2 +- fs/ocfs2/inode.c | 6 +- fs/sysfs/file.c | 2 +- include/linux/compat.h | 2 + include/linux/cpuset.h | 16 +- include/linux/libata.h | 1 + include/linux/msi.h | 2 + include/linux/sched.h | 20 +- include/linux/topology.h | 2 +- kernel/compat.c | 22 ++ kernel/cpu.c | 44 +--- kernel/cpuset.c | 67 +++-- kernel/fork.c | 15 - kernel/gcov/fs.c | 244 ++++++++++++---- kernel/groups.c | 5 +- kernel/sched.c | 485 ++++++++++++++++++------------- kernel/sched_debug.c | 2 - kernel/sched_fair.c | 210 +++++++++----- kernel/sched_idletask.c | 5 +- kernel/sched_rt.c | 33 ++- kernel/trace/ftrace.c | 19 +- mm/bounce.c | 2 +- mm/memory_hotplug.c | 16 +- net/irda/irlan/irlan_common.c | 2 +- net/sunrpc/auth_gss/auth_gss.c | 9 +- net/sunrpc/rpc_pipe.c | 6 +- net/wireless/wext-compat.c | 3 + net/wireless/wext.c | 16 + sound/core/seq/oss/seq_oss_init.c | 9 +- sound/pci/hda/patch_realtek.c | 9 +- tools/perf/util/callchain.h | 1 + 84 files changed, 1252 insertions(+), 618 deletions(-)
PATCH 1/123 hwmon: (k8temp) Differentiate between AM2 and ASB1
From: Andreas Herrmann <[email protected]>
commit a05e93f3b3fc2f53c1d0de3b17019e207c482349 upstream.
Commit 8bf0223ed515be24de0c671eedaff49e78bebc9c (hwmon, k8temp: Fix temperature reporting for ASB1 processor revisions) fixed temperature reporting for ASB1 CPUs. But those CPU models (model 0x6b, 0x6f, 0x7f) were packaged both as AM2 (desktop) and ASB1 (mobile). Thus the commit leads to wrong temperature reporting for AM2 CPU parts.
The solution is to determine the package type for models 0x6b, 0x6f, 0x7f.
This is done using BrandId from CPUID Fn8000_0001_EBX[15:0]. See "Constructing the processor Name String" in "Revision Guide for AMD NPT Family 0Fh Processors" (Rev. 3.46).
--- drivers/hwmon/k8temp.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-)
drivers/hwmon/k8temp.c +32 -3
@@ -143,6 +143,37 @@ static struct pci_device_id k8temp_ids[]MODULE_DEVICE_TABLE (pci, k8temp_ids); +static int __devinit is_rev_g_desktop (u8 model) +{ +u32 brandidx; + +if (model <0x69 ) +return 0 ; + +if (model ==0xc1 || model ==0x6c || model ==0x7c ) +return 0 ; + +/* +* Differentiate between AM2 and ASB1. +* See "Constructing the processor Name String" in "Revision +* Guide for AMD NPT Family 0Fh Processors" (33610). +*/ + brandidx =cpuid_ebx (0x80000001 ); + brandidx = (brandidx >>9 ) &0x1f ; + +/* Single core */ +if ((model ==0x6f || model ==0x7f ) && + (brandidx ==0x7 || brandidx ==0x9 || brandidx ==0xc )) +return 0 ; + +/* Dual core */ +if (model ==0x6b && + (brandidx ==0xb || brandidx ==0xc )) +return 0 ; + +return 1 ; +} +static int __devinit k8temp_probe (struct pci_dev *pdev,const struct pci_device_id *id) {
@@ -179,9 +210,7 @@ static int __devinit k8temp_probe(struct "wrong - check erratum #141\n"); } -if ((model >=0x69 ) && - !(model ==0xc1 || model ==0x6c || model ==0x7c || - model ==0x6b || model ==0x6f || model ==0x7f )) { +if (is_rev_g_desktop (model)) {/* * RevG desktop CPUs (i.e. no socket S1G1 or * ASB1 parts) need additional offset,
PATCH 2/123 xen: handle events as edge-triggered
In reply to Greg KHFrom: Jeremy Fitzhardinge <[email protected]>
commit dffe2e1e1a1ddb566a76266136c312801c66dcf7 upstream.
Xen events are logically edge triggered, as Xen only calls the event upcall when an event is newly set, but not continuously as it remains set. As a result, use handle_edge_irq rather than handle_level_irq.
This has the important side-effect of fixing a long-standing bug of events getting lost if:
- an event's interrupt handler is running
- the event is migrated to a different vcpu
- the event is re-triggered
The most noticable symptom of these lost events is occasional lockups of blkfront.
Many thanks to Tom Kopec and Daniel Stodden in tracking this down.
--- drivers/xen/events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/xen/events.c +1 -1
@@ -362,7 +362,7 @@ int bind_evtchn_to_irq(unsigned int evtc irq =find_unbound_irq ();set_irq_chip_and_handler_name (irq, &xen_dynamic_chip, - handle_level_irq,"event" ); + handle_edge_irq,"event" ); evtchn_to_irq[evtchn] = irq; irq_info[irq] =mk_evtchn_info (evtchn);
PATCH 3/123 xen: use percpu interrupts for IPIs and VIRQs
In reply to Greg KHFrom: Jeremy Fitzhardinge <[email protected]>
commit aaca49642b92c8a57d3ca5029a5a94019c7af69f upstream.
IPIs and VIRQs are inherently per-cpu event types, so treat them as such:
- use a specific percpu irq_chip implementation, and
- handle them with handle_percpu_irq
This makes the path for delivering these interrupts more efficient (no masking/unmasking, no locks), and it avoid problems with attempts to migrate them.
--- drivers/xen/events.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-)
drivers/xen/events.c +15 -4
@@ -106,6 +106,7 @@ static inline unsigned long *cpu_evtchn_#define VALID_EVTCHN (chn) ((chn) != 0)static struct irq_chip xen_dynamic_chip; +static struct irq_chip xen_percpu_chip;/* Constructor for packed IRQ information. */ static struct irq_info mk_unbound_info (void )
@@ -388,8 +389,8 @@ static int bind_ipi_to_irq(unsigned intif (irq <0 ) goto out; -set_irq_chip_and_handler_name (irq, &xen_dynamic_chip, - handle_level_irq,"ipi" ); +set_irq_chip_and_handler_name (irq, &xen_percpu_chip, + handle_percpu_irq,"ipi" ); bind_ipi.vcpu = cpu; if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
@@ -429,8 +430,8 @@ static int bind_virq_to_irq(unsigned int irq =find_unbound_irq (); -set_irq_chip_and_handler_name (irq, &xen_dynamic_chip, - handle_level_irq,"virq" ); +set_irq_chip_and_handler_name (irq, &xen_percpu_chip, + handle_percpu_irq,"virq" ); evtchn_to_irq[evtchn] = irq; irq_info[irq] =mk_virq_info (evtchn, virq);
@@ -929,6 +930,16 @@ static struct irq_chip xen_dynamic_chip .retrigger = retrigger_dynirq, }; +static struct irq_chip en_percpu_chip__read_mostly = { + .name ="xen-percpu" , + + .disable = disable_dynirq, + .mask = disable_dynirq, + .unmask = enable_dynirq, + + .ack = ack_dynirq, +}; +void __init xen_init_IRQ (void ) {int i;
PATCH 4/123 ALSA: hda - Rename iMic to Int Mic on Lenovo NB0763
In reply to Greg KHFrom: David Henningsson <[email protected]>
commit 150b432f448281d5518f5229d240923f9a9c5459 upstream.
The non-standard name "iMic" makes PulseAudio ignore the microphone.
--- sound/pci/hda/patch_realtek.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
sound/pci/hda/patch_realtek.c +3 -3
@@ -6589,7 +6589,7 @@ static struct hda_input_mux alc883_lenov .num_items = 4, .items = { { "Mic", 0x0 }, - { "iMic", 0x1 }, + { "Int Mic", 0x1 }, { "Line", 0x2 }, { "CD", 0x4 }, },
@@ -8038,8 +8038,8 @@ static struct snd_kcontrol_new alc883_leHDA_CODEC_MUTE ("CD Playback Switch" ,0x0b ,0x04 ,HDA_INPUT ),HDA_CODEC_VOLUME ("Mic Playback Volume" ,0x0b ,0x0 ,HDA_INPUT ),HDA_CODEC_MUTE ("Mic Playback Switch" ,0x0b ,0x0 ,HDA_INPUT ), -HDA_CODEC_VOLUME ("iMic Playback Volume" ,0x0b ,0x1 ,HDA_INPUT ), - HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT), +HDA_CODEC_VOLUME ("Int Mic Playback Volume" ,0x0b ,0x1 ,HDA_INPUT ), + HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ };
PATCH 5/123 sata_mv: fix broken DSM/TRIM support (v2)
In reply to Greg KHFrom: Mark Lord <[email protected]>
commit 44b733809a5aba7f6b15a548d31a56d25bf3851c upstream.
Fix DSM/TRIM commands in sata_mv (v2). These need to be issued using old-school "BM DMA", rather than via the EDMA host queue.
Since the chips don't have proper BM DMA status,
we need to be more careful with setting the ATA_DMA_INTR bit, since DSM/TRIM often has a long delay between "DMA complete" and "command complete".
GEN_I chips don't have BM DMA, so no TRIM for them.
--- drivers/ata/sata_mv.c | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-)
drivers/ata/sata_mv.c +37 -7
@@ -1879,19 +1879,25 @@ static void mv_bmdma_start(struct ata_qu* LOCKING: * Inherited from caller. */ -static void mv_bmdma_stop (struct ata_queued_cmd *qc) +static void mv_bmdma_stop_ap (struct ata_port *ap) { -struct ata_port *ap = qc->ap;void __iomem *port_mmio =mv_ap_base (ap);u32 cmd;/* clear start/stop bit */ cmd =readl (port_mmio +BMDMA_CMD ); - cmd &= ~ATA_DMA_START ; -writelfl (cmd, port_mmio +BMDMA_CMD ); +if (cmd &ATA_DMA_START ) { + cmd &= ~ATA_DMA_START ; +writelfl (cmd, port_mmio +BMDMA_CMD ); -/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ -ata_sff_dma_pause (ap); +/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ +ata_sff_dma_pause (ap); + } +} + +static void mv_bmdma_stop (struct ata_queued_cmd *qc) +{ +mv_bmdma_stop_ap (qc->ap); }/**
@@ -1915,8 +1921,21 @@ static u8 mv_bmdma_status(struct ata_por reg =readl (port_mmio +BMDMA_STATUS );if (reg &ATA_DMA_ACTIVE ) status =ATA_DMA_ACTIVE ; -else +else if (reg &ATA_DMA_ERR ) status = (reg &ATA_DMA_ERR ) |ATA_DMA_INTR ; +else { +/* +* Just because DMA_ACTIVE is 0 (DMA completed), +* this does _not_ mean the device is "done". +* So we should not yet be signalling ATA_DMA_INTR +* in some cases. Eg. DSM/TRIM, and perhaps others. +*/ +mv_bmdma_stop_ap (ap); +if (ioread8 (ap->ioaddr.altstatus_addr) &ATA_BUSY ) + status =0 ; +else + status =ATA_DMA_INTR ; + }return status; }
@@ -1976,6 +1995,9 @@ static void mv_qc_prep(struct ata_queuedswitch (tf->protocol) {case ATA_PROT_DMA : +if (tf->command ==ATA_CMD_DSM ) +return ; +/* fall-thru */ case ATA_PROT_NCQ :break ;/* continue below */ case ATA_PROT_PIO :
@@ -2075,6 +2097,8 @@ static void mv_qc_prep_iie(struct ata_quif ((tf->protocol !=ATA_PROT_DMA ) && (tf->protocol !=ATA_PROT_NCQ ))return ; +if (tf->command ==ATA_CMD_DSM ) +return ;/* use bmdma for this */ /* Fill in Gen IIE command request block */ if (!(tf->flags &ATA_TFLAG_WRITE ))
@@ -2270,6 +2294,12 @@ static unsigned int mv_qc_issue(struct aswitch (qc->tf.protocol) {case ATA_PROT_DMA : +if (qc->tf.command ==ATA_CMD_DSM ) { +if (!ap->ops->bmdma_setup)/* no bmdma on GEN_I */ +return AC_ERR_OTHER ; +break ;/* use bmdma for this */ + } +/* fall thru */ case ATA_PROT_NCQ :mv_start_edma (ap, port_mmio, pp, qc->tf.protocol); pp->req_idx = (pp->req_idx +1 ) &MV_MAX_Q_DEPTH_MASK ;
PATCH 6/123 x86, tsc, sched: Recompute cyc2ns_offsets during resume from sleep states
In reply to Greg KHFrom: Suresh Siddha <[email protected]>
commit cd7240c0b900eb6d690ccee088a6c9b46dae815a upstream.
TSC's get reset after suspend/resume (even on cpu's with invariant TSC which runs at a constant rate across ACPI P-, C- and T-states). And in some systems BIOS seem to reinit TSC to arbitrary large value (still sync'd across cpu's) during resume.
This leads to a scenario of scheduler rq->clock (sched_clock_cpu()) less than rq->age_stamp (introduced in 2.6.32). This leads to a big value returned by scale_rt_power() and the resulting big group power set by the update_group_power() is causing improper load balancing between busy and idle cpu's after suspend/resume.
This resulted in multi-threaded workloads (like kernel-compilation) go slower after suspend/resume cycle on core i5 laptops.
Fix this by recomputing cyc2ns_offset's during resume, so that sched_clock() continues from the point where it was left off during suspend.
LKML-Reference: <[email protected]>
--- arch/x86/include/asm/tsc.h | 2 ++ arch/x86/kernel/tsc.c | 38 ++++++++++++++++++++++++++++++++++++++ arch/x86/power/cpu.c | 2 ++ 3 files changed, 42 insertions(+)
arch/x86/include/asm/tsc.h +2 -0
@@ -59,5 +59,7 @@ extern void check_tsc_sync_source(int cpextern void check_tsc_sync_target (void );extern int notsc_setup (char *); +extern void save_sched_clock_state (void ); +extern void restore_sched_clock_state (void );#endif /* _ASM_X86_TSC_H */
arch/x86/kernel/tsc.c +38 -0
@@ -626,6 +626,44 @@ static void set_cyc2ns_scale(unsigned lolocal_irq_restore (flags); } +static unsigned long long cyc2ns_suspend; + +void save_sched_clock_state (void ) +{ +if (!sched_clock_stable) +return ; + + cyc2ns_suspend =sched_clock (); +} + +/* +* Even on processors with invariant TSC, TSC gets reset in some the +* ACPI system sleep states. And in some systems BIOS seem to reinit TSC to +* arbitrary value (still sync'd across cpu's) during resume from such sleep +* states. To cope up with this, recompute the cyc2ns_offset for each cpu so +* that sched_clock() continues from the point where it was left off during +* suspend. +*/ +void restore_sched_clock_state (void ) +{ +unsigned long long offset; +unsigned long flags; +int cpu; + +if (!sched_clock_stable) +return ; + +local_irq_save (flags); + +get_cpu_var (cyc2ns_offset) =0 ; + offset = cyc2ns_suspend -sched_clock (); + +for_each_possible_cpu (cpu) +per_cpu (cyc2ns_offset, cpu) = offset; + +local_irq_restore (flags); +} +#ifdef CONFIG_CPU_FREQ /* Frequency scaling support. Adjust the TSC based timer when the cpu frequency
arch/x86/power/cpu.c +2 -0
@@ -112,6 +112,7 @@ static void __save_processor_state(strucvoid save_processor_state (void ) {__save_processor_state (&saved_context); +save_sched_clock_state (); }#ifdef CONFIG_X86_32 EXPORT_SYMBOL (save_processor_state);
@@ -253,6 +254,7 @@ static void __restore_processor_state(stvoid restore_processor_state (void ) {__restore_processor_state (&saved_context); +restore_sched_clock_state (); }#ifdef CONFIG_X86_32 EXPORT_SYMBOL (restore_processor_state);
PATCH 7/123 PCI: MSI: Remove unsafe and unnecessary hardware access
In reply to Greg KHFrom: Ben Hutchings <[email protected]>
commit fcd097f31a6ee207cc0c3da9cccd2a86d4334785 upstream.
During suspend on an SMP system, {read,write}_msi_msg_desc() may be called to mask and unmask interrupts on a device that is already in a reduced power state. At this point memory-mapped registers including MSI-X tables are not accessible, and config space may not be fully functional either.
While a device is in a reduced power state its interrupts are effectively masked and its MSI(-X) state will be restored when it is brought back to D0. Therefore these functions can simply read and write msi_desc::msg for devices not in D0.
Further, read_msi_msg_desc() should only ever be used to update a previously written message, so it can always read msi_desc::msg and never needs to touch the hardware.
--- drivers/pci/msi.c | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-)
drivers/pci/msi.c +12 -24
@@ -195,30 +195,15 @@ void unmask_msi_irq(unsigned int irq)void read_msi_msg_desc (struct irq_desc *desc,struct msi_msg *msg) {struct msi_desc *entry =get_irq_desc_msi (desc); -if (entry->msi_attrib.is_msix) { -void __iomem *base = entry->mask_base + - entry->msi_attrib.entry_nr *PCI_MSIX_ENTRY_SIZE ; - msg->address_lo =readl (base +PCI_MSIX_ENTRY_LOWER_ADDR ); - msg->address_hi =readl (base +PCI_MSIX_ENTRY_UPPER_ADDR ); - msg->data =readl (base +PCI_MSIX_ENTRY_DATA ); - }else { -struct pci_dev *dev = entry->dev; -int pos = entry->msi_attrib.pos; -u16 data; - -pci_read_config_dword (dev,msi_lower_address_reg (pos), - &msg->address_lo); -if (entry->msi_attrib.is_64) { -pci_read_config_dword (dev,msi_upper_address_reg (pos), - &msg->address_hi); -pci_read_config_word (dev,msi_data_reg (pos,1 ), &data); - }else { - msg->address_hi =0 ; -pci_read_config_word (dev,msi_data_reg (pos,0 ), &data); - } - msg->data = data; - } +/* We do not touch the hardware (which may not even be +* accessible at the moment) but return the last message +* written. Assert that this is valid, assuming that +* valid messages are not all-zeroes. */ +BUG_ON (!(entry->msg.address_hi | entry->msg.address_lo | + entry->msg.data)); + + *msg = entry->msg; }void read_msi_msg (unsigned int irq,struct msi_msg *msg)
@@ -231,7 +216,10 @@ void read_msi_msg(unsigned int irq, struvoid write_msi_msg_desc (struct irq_desc *desc,struct msi_msg *msg) {struct msi_desc *entry =get_irq_desc_msi (desc); -if (entry->msi_attrib.is_msix) { + +if (entry->dev->current_state !=PCI_D0 ) { +/* Don't touch the hardware now */ + }else if (entry->msi_attrib.is_msix) {void __iomem *base; base = entry->mask_base + entry->msi_attrib.entry_nr *PCI_MSIX_ENTRY_SIZE ;
PATCH 8/123 PCI: MSI: Restore read_msi_msg_desc(); add get_cached_msi_msg_desc()
In reply to Greg KHFrom: Ben Hutchings <[email protected]>
commit 30da55242818a8ca08583188ebcbaccd283ad4d9 upstream.
commit 2ca1af9aa3285c6a5f103ed31ad09f7399fc65d7 "PCI: MSI: Remove unsafe and unnecessary hardware access" changed read_msi_msg_desc() to return the last MSI message written instead of reading it from the device, since it may be called while the device is in a reduced power state.
However, the pSeries platform code really does need to read messages from the device, since they are initially written by firmware. Therefore:
- Restore the previous behaviour of read_msi_msg_desc()
- Add new functions get_cached_msi_msg{,_desc}() which return the last MSI message written
- Use the new functions where appropriate
--- arch/ia64/kernel/msi_ia64.c | 2 - arch/ia64/sn/kernel/msi_sn.c | 2 - arch/x86/kernel/apic/io_apic.c | 2 - drivers/pci/msi.c | 47 ++++++++++++++++++++++++++++++++++++----- include/linux/msi.h | 2 + 5 files changed, 47 insertions(+), 8 deletions(-)
arch/ia64/kernel/msi_ia64.c +1 -1
@@ -25,7 +25,7 @@ static int ia64_set_msi_irq_affinity(unsif (irq_prepare_move (irq, cpu))return -1 ; -read_msi_msg (irq, &msg); +get_cached_msi_msg (irq, &msg); addr = msg.address_lo; addr &=MSI_ADDR_DEST_ID_MASK ;
arch/ia64/sn/kernel/msi_sn.c +1 -1
@@ -174,7 +174,7 @@ static int sn_set_msi_irq_affinity(unsig* Release XIO resources for the old MSI PCI address */ -read_msi_msg (irq, &msg); +get_cached_msi_msg (irq, &msg); sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; pdev = sn_pdev->pdi_linux_pcidev; provider =SN_PCIDEV_BUSPROVIDER (pdev);
arch/x86/kernel/apic/io_apic.c +1 -1
@@ -3338,7 +3338,7 @@ static int set_msi_irq_affinity(unsigned cfg = desc->chip_data; -read_msi_msg_desc (desc, &msg); +get_cached_msi_msg_desc (desc, &msg); msg.data &= ~MSI_DATA_VECTOR_MASK ; msg.data |=MSI_DATA_VECTOR (cfg->vector);
drivers/pci/msi.c +42 -5
62 lines not on this page · raw message
include/linux/msi.h +2 -0
@@ -14,8 +14,10 @@ struct irq_desc;extern void mask_msi_irq (unsigned int irq);extern void unmask_msi_irq (unsigned int irq);extern void read_msi_msg_desc (struct irq_desc *desc,struct msi_msg *msg); +extern void get_cached_msi_msg_desc (struct irq_desc *desc,struct msi_msg *msg);extern void write_msi_msg_desc (struct irq_desc *desc,struct msi_msg *msg);extern void read_msi_msg (unsigned int irq,struct msi_msg *msg); +extern void get_cached_msi_msg (unsigned int irq,struct msi_msg *msg);extern void write_msi_msg (unsigned int irq,struct msi_msg *msg);struct msi_desc {
PATCH 9/123 sched: kill migration thread in CPU_POST_DEAD instead of CPU_DEAD
In reply to Greg KHFrom: Amit Arora <[email protected]>
[Fixed in a different manner upstream, due to rewrites in this area]
Problem : In a stress test where some heavy tests were running along with regular CPU offlining and onlining, a hang was observed. The system seems to be hung at a point where migration_call() tries to kill the migration_thread of the dying CPU, which just got moved to the current CPU. This migration thread does not get a chance to run (and die) since rt_throttled is set to 1 on current, and it doesn't get cleared as the hrtimer which is supposed to reset the rt bandwidth (sched_rt_period_timer) is tied to the CPU which we just marked dead!
Solution : This patch pushes the killing of migration thread to "CPU_POST_DEAD" event. By then all the timers (including sched_rt_period_timer) should have got migrated (along with other callbacks).
--- kernel/sched.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
kernel/sched.c +13 -3
@@ -7752,14 +7752,24 @@ migration_call(struct notifier_block *nfcpu_rq (cpu)->migration_thread =NULL ;break ; +case CPU_POST_DEAD : +/* +* Bring the migration thread down in CPU_POST_DEAD event, +* since the timers should have got migrated by now and thus +* we should not see a deadlock between trying to kill the +* migration thread and the sched_rt_period_timer. +*/ + rq =cpu_rq (cpu); +kthread_stop (rq->migration_thread); +put_task_struct (rq->migration_thread); + rq->migration_thread =NULL ; +break ; +case CPU_DEAD :case CPU_DEAD_FROZEN :cpuset_lock ();/* around calls to cpuset_cpus_allowed_lock() */ migrate_live_tasks (cpu); rq =cpu_rq (cpu); -kthread_stop (rq->migration_thread); -put_task_struct (rq->migration_thread); - rq->migration_thread =NULL ;/* Idle task back to normal (off runqueue, low prio) */ spin_lock_irq (&rq->lock);update_rq_clock (rq);
PATCH 10/123 sched: revert stable c6fc81a sched: Fix a race between ttwu() and migrate_task()
In reply to Greg KHFrom: Mike Galbraith <[email protected]>
This commit does not appear to have been meant for 32-stable, and causes ltp's cpusets testcases to fail, revert it.
Original commit text:
sched: Fix a race between ttwu() and migrate_task()
Based on commit e2912009fb7b715728311b0d8fe327a1432b3f79 upstream, but done differently as this issue is not present in .33 or .34 kernels due to rework in this area.
If a task is in the TASK_WAITING state, then try_to_wake_up() is working on it, and it will place it on the correct cpu.
This commit ensures that neither migrate_task() nor __migrate_task() calls set_task_cpu(p) while p is in the TASK_WAKING state. Otherwise, there could be two concurrent calls to set_task_cpu(p), resulting in the task's cfs_rq being inconsistent with its cpu.
--- kernel/sched.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
kernel/sched.c +4 -5
@@ -2123,10 +2123,12 @@ migrate_task(struct task_struct *p, int/* * If the task is not on a runqueue (and not running), then -* the next wake-up will properly place the task. +* it is sufficient to simply update the task's cpu field. */ -if (!p->se.on_rq && !task_running (rq, p)) +if (!p->se.on_rq && !task_running (rq, p)) { +set_task_cpu (p, dest_cpu);return 0 ; + }init_completion (&req->done); req->task = p;
@@ -7217,9 +7219,6 @@ static int __migrate_task(struct task_st/* Already moved. */ if (task_cpu (p) != src_cpu) goto done; -/* Waking up, don't get in the way of try_to_wake_up(). */ -if (p->state ==TASK_WAKING ) - goto fail;/* Affinity changed (again). */ if (!cpumask_test_cpu (dest_cpu, &p->cpus_allowed)) goto fail;
PATCH 11/123 staging: hv: Fix missing functions for net_device_ops
In reply to Greg KHFrom: Haiyang Zhang <[email protected]>
commit b681b5886bb5d1f5b6750a0ed7c62846da7ccea4 upstream.
Fix missing functions for net_device_ops.
It's a bug when porting the drivers from 2.6.27 to 2.6.32. In 2.6.27, the default functions for Ethernet, like eth_change_mtu(), were assigned by ether_setup(). But in 2.6.32, these function pointers moved to net_device_ops structure and no longer be assigned in ether_setup(). So we need to set these functions in our driver code. It will ensure the MTU won't be set beyond 1500. Otherwise, this can cause an error on the server side, because the HyperV linux driver doesn't support jumbo frame yet.
--- drivers/staging/hv/netvsc_drv.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/staging/hv/netvsc_drv.c +3 -0
@@ -392,6 +392,9 @@ static const struct net_device_ops devic .ndo_start_xmit = netvsc_start_xmit, .ndo_get_stats = netvsc_get_stats, .ndo_set_multicast_list = netvsc_set_multicast_list, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, };static int netvsc_probe (struct device *device)
PATCH 12/123 staging: hv: Fixed bounce kmap problem by using correct index
In reply to Greg KHFrom: Hank Janssen <[email protected]>
commit 0c47a70a9a8a6d1ec37a53d2f9cb82f8b8ef8aa2 upstream.
Fixed bounce offset kmap problem by using correct index.
The symptom of the problem is that in some NAS appliances this problem represents Itself by a unresponsive VM under a load with many clients writing small files.
--- drivers/staging/hv/storvsc_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/staging/hv/storvsc_drv.c +2 -2
@@ -532,7 +532,7 @@ static unsigned int copy_to_bounce_buffeASSERT (orig_sgl[i].offset + orig_sgl[i].length <=PAGE_SIZE ); -if (j ==0 ) +if (bounce_addr ==0 ) bounce_addr = (unsigned long )kmap_atomic (sg_page ((&bounce_sgl[j])),KM_IRQ0 );while (srclen) {
@@ -593,7 +593,7 @@ static unsigned int copy_from_bounce_buf destlen = orig_sgl[i].length;ASSERT (orig_sgl[i].offset + orig_sgl[i].length <=PAGE_SIZE ); -if (j ==0 ) +if (bounce_addr ==0 ) bounce_addr = (unsigned long )kmap_atomic (sg_page ((&bounce_sgl[j])),KM_IRQ0 );while (destlen) {
PATCH 13/123 staging: hv: Fixed the value of the 64bit-hole inside ring buffer
In reply to Greg KHFrom: Haiyang Zhang <[email protected]>
commit e5fa721d1c2a54261a37eb59686e18dee34b6af6 upstream.
Fixed the value of the 64bit-hole inside ring buffer, this caused a problem on Hyper-V when running checked Windows builds.
Checked builds of Windows are used internally and given to external system integrators at times. They are builds that for example that all elements in a structure follow the definition of that Structure. The bug this fixed was for a field that we did not fill in at all (Because we do Not use it on the Linux side), and the checked build of windows gives errors on it internally to the Windows logs.
This fixes that error.
--- drivers/staging/hv/RingBuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/hv/RingBuffer.c +1 -1
@@ -192,7 +192,7 @@ Description:static inline u64 GetRingBufferIndices (RING_BUFFER_INFO * RingInfo) { -return ((u64 )RingInfo->RingBuffer->WriteIndex <<32 ) || RingInfo->RingBuffer->ReadIndex; +return (u64 )RingInfo->RingBuffer->WriteIndex <<32 ; }
PATCH 14/123 staging: hv: Increased storvsc ringbuffer and max_io_requests
In reply to Greg KHFrom: Hank Janssen <[email protected]>
commit 15dd1c9f53b31cdc84b8072a88c23fa09527c596 upstream.
Increased storvsc ringbuffer and max_io_requests. This now more closely mimics the numbers on Hyper-V. And will allow more IO requests to take place for the SCSI driver.
Max_IO is set to double from what it was before, Hyper-V allows it and we have had appliance builder requests to see if it was a problem to increase the number.
Ringbuffer size for storvsc is now increased because I have seen A few buffer problems on extremely busy systems. They were Set pretty low before. And since max_io_requests is increased I Really needed to increase the buffer as well.
--- drivers/staging/hv/StorVscApi.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/staging/hv/StorVscApi.h +2 -2
@@ -28,10 +28,10 @@#include "VmbusApi.h" /* Defines */ -#define STORVSC_RING_BUFFER_SIZE (10*PAGE_SIZE) +#define STORVSC_RING_BUFFER_SIZE (20*PAGE_SIZE)#define BLKVSC_RING_BUFFER_SIZE (20*PAGE_SIZE) -#define STORVSC_MAX_IO_REQUESTS 64 +#define STORVSC_MAX_IO_REQUESTS 128/* * In Hyper-V, each port/path/target maps to 1 scsi host adapter. In
PATCH 15/123 staging: hv: Fixed lockup problem with bounce_buffer scatter list
In reply to Greg KHFrom: Hank Janssen <[email protected]>
commit 77c5ceaff31645ea049c6706b99e699eae81fb88 upstream.
Fixed lockup problem with bounce_buffer scatter list which caused crashes in heavy loads. And minor code indentation cleanup in effected area.
Removed whitespace and noted minor indentation changes in description as pointed out by Joe Perches. (Thanks for reviewing Joe)
--- drivers/staging/hv/storvsc_drv.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/staging/hv/storvsc_drv.c +4 -1
@@ -652,6 +652,7 @@ static int storvsc_queuecommand(struct sunsigned int request_size =0 ;int i;struct scatterlist *sgl; +unsigned int sg_count =0 ;DPRINT_ENTER (STORVSC_DRV );
@@ -736,6 +737,7 @@ static int storvsc_queuecommand(struct s request->DataBuffer.Length =scsi_bufflen (scmnd);if (scsi_sg_count (scmnd)) { sgl = (struct scatterlist *)scsi_sglist (scmnd); + sg_count =scsi_sg_count (scmnd);/* check if we need to bounce the sgl */ if (do_bounce_buffer (sgl,scsi_sg_count (scmnd)) !=-1 ) {
@@ -770,11 +772,12 @@ static int storvsc_queuecommand(struct s scsi_sg_count(scmnd)); sgl = cmd_request->bounce_sgl; + sg_count = cmd_request->bounce_sgl_count; } request->DataBuffer.Offset = sgl[0 ].offset; -for (i =0 ; i <scsi_sg_count (scmnd); i++) { +for (i =0 ; i < sg_count; i++) {DPRINT_DBG (STORVSC_DRV ,"sgl[%d] len %d offset %d \n" , i, sgl[i].length, sgl[i].offset); request->DataBuffer.PfnArray[i] =
PATCH 16/123 fuse: flush background queue on connection close
In reply to Greg KHFrom: Miklos Szeredi <[email protected]>
commit 595afaf9e6ee1b48e13ec4b8bcc8c7dee888161a upstream.
David Bartly reported that fuse can hang in fuse_get_req_nofail() when the connection to the filesystem server is no longer active.
If bg_queue is not empty then flush_bg_queue() called from request_end() can put more requests on to the pending queue. If this happens while ending requests on the processing queue then those background requests will be queued to the pending list and never ended.
Another problem is that fuse_dev_release() didn't wake up processes sleeping on blocked_waitq.
Solve this by:
a) flushing the background queue before calling end_requests() on the pending and processing queues
b) setting blocked = 0 and waking up processes waiting on blocked_waitq()
Thanks to David for an excellent bug report.
--- fs/fuse/dev.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
fs/fuse/dev.c +12 -4
@@ -1158,6 +1158,14 @@ __acquires(&fc->lock) } } +static void end_queued_requests (struct fuse_conn *fc) +{ + fc->max_background =UINT_MAX ; +flush_bg_queue (fc); +end_requests (fc, &fc->pending); +end_requests (fc, &fc->processing); +} +/* * Abort all requests. *
@@ -1184,8 +1192,7 @@ void fuse_abort_conn(struct fuse_conn *f fc->connected =0 ; fc->blocked =0 ;end_io_requests (fc); -end_requests (fc, &fc->pending); -end_requests (fc, &fc->processing); +end_queued_requests (fc);wake_up_all (&fc->waitq);wake_up_all (&fc->blocked_waitq);kill_fasync (&fc->fasync,SIGIO ,POLL_IN );
@@ -1200,8 +1207,9 @@ int fuse_dev_release(struct inode *inodeif (fc) {spin_lock (&fc->lock); fc->connected =0 ; -end_requests (fc, &fc->pending); -end_requests (fc, &fc->processing); + fc->blocked =0 ; +end_queued_requests (fc); +wake_up_all (&fc->blocked_waitq);spin_unlock (&fc->lock);fuse_conn_put (fc); }
PATCH 17/123 ath9k_hw: fix parsing of HT40 5 GHz CTLs
In reply to Greg KHFrom: Luis R. Rodriguez <[email protected]>
commit 904879748d7439a6dabdc6be9aad983e216b027d upstream.
The 5 GHz CTL indexes were not being read for all hardware devices due to the masking out through the CTL_MODE_M mask being one bit too short. Without this the calibrated regulatory maximum values were not being picked up when devices operate on 5 GHz in HT40 mode. The final output power used for Atheros devices is the minimum between the calibrated CTL values and what CRDA provides.
--- drivers/net/wireless/ath/ath9k/eeprom.h | 2 +- drivers/net/wireless/ath/regd.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-)
drivers/net/wireless/ath/ath9k/eeprom.h +1 -1
@@ -60,7 +60,7 @@#define SD_NO_CTL 0xE0#define NO_CTL 0xff -#define CTL_MODE_M 7 +#define CTL_MODE_M 0xf#define CTL_11A 0#define CTL_11B 1#define CTL_11G 2
drivers/net/wireless/ath/regd.h +0 -1
@@ -31,7 +31,6 @@ enum ctl_group {#define NO_CTL 0xff#define SD_NO_CTL 0xE0#define NO_CTL 0xff -#define CTL_MODE_M 7#define CTL_11A 0#define CTL_11B 1#define CTL_11G 2
PATCH 18/123 ocfs2: Fix incorrect checksum validation error
In reply to Greg KHFrom: Sunil Mushran <[email protected]>
commit f5ce5a08a40f2086435858ddc80cb40394b082eb upstream.
For local mounts, ocfs2_read_locked_inode() calls ocfs2_read_blocks_sync() to read the inode off the disk. The latter first checks to see if that block is cached in the journal, and, if so, returns that block. That is ok.
But ocfs2_read_locked_inode() goes wrong when it tries to validate the checksum of such blocks. Blocks that are cached in the journal may not have had their checksum computed as yet. We should not validate the checksums of such blocks.
Fixes ossbz#1282
http://oss.oracle.com/bugzilla/show_bug.cgi?id=1282
--- fs/ocfs2/inode.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
fs/ocfs2/inode.c +5 -1
@@ -485,7 +485,11 @@ static int ocfs2_read_locked_inode(struc OCFS2_BH_IGNORE_CACHE); }else { status =ocfs2_read_blocks_sync (osb, args->fi_blkno,1 , &bh); -if (!status) +/* +* If buffer is in jbd, then its checksum may not have been +* computed as yet. +*/ +if (!status && !buffer_jbd (bh)) status =ocfs2_validate_inode_block (osb->sb, bh); }if (status <0 ) {
PATCH 19/123 USB: ehci-ppc-of: problems in unwind
In reply to Greg KHFrom: Dan Carpenter <[email protected]>
commit 08a3b3b1c2e622e378d9086aee9e2e42ce37591d upstream.
The iounmap(ehci->ohci_hcctrl_reg); should be the first thing we do because the ioremap() was the last thing we did. Also if we hit any of the goto statements in the original code then it would have led to a NULL dereference of "ehci". This bug was introduced in: 796bcae7361c "USB: powerpc: Workaround for the PPC440EPX USBH_23 errata [take 3]"
I modified the few lines in front a little so that my code didn't obscure the return success code path.
--- drivers/usb/host/ehci-ppc-of.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/usb/host/ehci-ppc-of.c +7 -5
@@ -192,17 +192,19 @@ ehci_hcd_ppc_of_probe(struct of_device * } rv =usb_add_hcd (hcd, irq,0 ); -if (rv ==0 ) -return 0 ; +if (rv) + goto err_ehci; +return 0 ; + +err_ehci: +if (ehci->has_amcc_usb23) +iounmap (ehci->ohci_hcctrl_reg);iounmap (hcd->regs); err_ioremap:irq_dispose_mapping (irq); err_irq:release_mem_region (hcd->rsrc_start, hcd->rsrc_len); - -if (ehci->has_amcc_usb23) -iounmap (ehci->ohci_hcctrl_reg); err_rmr:usb_put_hcd (hcd);
PATCH 20/123 USB: Fix kernel oops with g_ether and Windows
In reply to Greg KHFrom: Maxim Osipov <[email protected]>
commit 037d3656adbd7e8cb848f01cf5dec423ed76bbe7 upstream.
Please find attached patch for
https://bugzilla.kernel.org/show_bug.cgi?id=16023 problem.
--- drivers/usb/gadget/rndis.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/usb/gadget/rndis.c +7 -3
@@ -291,9 +291,13 @@ gen_ndis_query_resp (int configNr, u32 O/* mandatory */ case OID_GEN_VENDOR_DESCRIPTION :pr_debug ("%s: OID_GEN_VENDOR_DESCRIPTION\n" , __func__); - length =strlen (rndis_per_dev_params [configNr].vendorDescr); -memcpy (outbuf, - rndis_per_dev_params [configNr].vendorDescr, length); +if ( rndis_per_dev_params [configNr].vendorDescr ) { + length =strlen (rndis_per_dev_params [configNr].vendorDescr); +memcpy (outbuf, + rndis_per_dev_params [configNr].vendorDescr, length); + }else { + outbuf[0 ] =0 ; + } retval =0 ;break ;
PATCH 21/123 USB: CP210x Add new device ID
In reply to Greg KHFrom: Craig Shelley <[email protected]>
commit 541e05ec3add5ab5bcf238d60161b53480280b20 upstream.
New device ID added for Balluff RFID reader.
--- drivers/usb/serial/cp210x.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/usb/serial/cp210x.c +5 -4
@@ -111,6 +111,7 @@ static struct usb_device_id id_table [] { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */ { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */ { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ + { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */
@@ -124,14 +125,14 @@ static struct usb_device_id id_table [] { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */ { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ - { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */ - { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ - { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ - { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */ { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */ { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */ { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */ + { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */ + { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ + { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ + { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ { } /* Terminating Entry */ };
PATCH 22/123 USB: cp210x: Add B&G H3000 link cable ID
In reply to Greg KHFrom: Jason Detring <[email protected]>
commit 0bf7a81c5d447c21db434be35363c44c0a30f598 upstream.
This is the cable between an H3000 navigation unit and a multi-function display.
http://www.bandg.com/en/Products/H3000/Spares-and-Accessories/Cables/H3000-CPU-USB-Cable-Pack/
--- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/serial/cp210x.c +1 -0
@@ -90,6 +90,7 @@ static struct usb_device_id id_table [] { USB_DEVICE(0x10C4, 0x8149) }, /* West Mountain Radio Computerized Battery Analyzer */ { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */ { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */ + { USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */ { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */ { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */
PATCH 23/123 USB: ftdi_sio: Added custom PIDs for ChamSys products
In reply to Greg KHFrom: Luke Lowrey <[email protected]>
commit 657373883417b2618023fd4135d251ba06a2c30a upstream.
Added the 0xDAF8 to 0xDAFF PID range for ChamSys limited USB interface/wing products
--- drivers/usb/serial/ftdi_sio.c | 8 ++++++++ drivers/usb/serial/ftdi_sio_ids.h | 12 ++++++++++++ 2 files changed, 20 insertions(+)
drivers/usb/serial/ftdi_sio.c +8 -0
@@ -759,6 +759,14 @@ static struct usb_device_id id_table_com { USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) }, { USB_DEVICE(IONICS_VID, IONICS_PLUGCOMPUTER_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_24_MASTER_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_PC_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_USB_DMX_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MIDI_TIMECODE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MINI_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MAXI_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MEDIA_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_WING_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ };
drivers/usb/serial/ftdi_sio_ids.h +12 -0
@@ -135,6 +135,18 @@#define FTDI_NDI_AURORA_SCU_PID 0xDA74/* NDI Aurora SCU */ /* +* ChamSys Limited (www.chamsys.co.uk) USB wing/interface product IDs +*/ +#define FTDI_CHAMSYS_24_MASTER_WING_PID 0xDAF8 +#define FTDI_CHAMSYS_PC_WING_PID 0xDAF9 +#define FTDI_CHAMSYS_USB_DMX_PID 0xDAFA +#define FTDI_CHAMSYS_MIDI_TIMECODE_PID 0xDAFB +#define FTDI_CHAMSYS_MINI_WING_PID 0xDAFC +#define FTDI_CHAMSYS_MAXI_WING_PID 0xDAFD +#define FTDI_CHAMSYS_MEDIA_WING_PID 0xDAFE +#define FTDI_CHAMSYS_WING_PID 0xDAFF + +/* * Westrex International devices submitted by Cory Lee */ #define FTDI_WESTREX_MODEL_777_PID 0xDC00/* Model 777 */
PATCH 24/123 USB: serial: Extra device/vendor ID for mos7840 driver
In reply to Greg KHFrom: Blaise Gassend <[email protected]>
commit 27f1281d5f72e4f161e215ccad3d7d86b9e624a9 upstream.
--- drivers/usb/serial/mos7840.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/usb/serial/mos7840.c +5 -2
@@ -127,8 +127,9 @@#define BANDB_DEVICE_ID_US9ML2_4 0xAC30#define BANDB_DEVICE_ID_USPTL4_2 0xAC31#define BANDB_DEVICE_ID_USPTL4_4 0xAC32 -#define BANDB_DEVICE_ID_USOPTL4_2 0xAC42 -#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44 +#define BANDB_DEVICE_ID_USOPTL4_2 0xAC42 +#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44 +#define BANDB_DEVICE_ID_USOPTL2_4 0xAC24/* This driver also supports * ATEN UC2324 device using Moschip MCS7840
@@ -191,6 +192,7 @@ static struct usb_device_id moschip_port {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, {} /* terminating entry */
@@ -207,6 +209,7 @@ static __devinitdata struct usb_device_i {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, {} /* terminating entry */
PATCH 25/123 usb: serial: mos7840: Add USB ID to support the B&B Electronics USOPTL4-2P.
In reply to Greg KHFrom: Dave Ludlow <[email protected]>
commit caf3a636a9f809fdca5fa746e6687096457accb1 upstream.
Add the USB ID needed to support B&B Electronic's 2-port, optically-isolated, powered, USB to RS485 converter.
--- drivers/usb/serial/mos7840.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/usb/serial/mos7840.c +3 -0
@@ -130,6 +130,7 @@#define BANDB_DEVICE_ID_USOPTL4_2 0xAC42#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44#define BANDB_DEVICE_ID_USOPTL2_4 0xAC24 +#define BANDB_DEVICE_ID_USOPTL4_2P 0xBC02/* This driver also supports * ATEN UC2324 device using Moschip MCS7840
@@ -193,6 +194,7 @@ static struct usb_device_id moschip_port {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4P)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, {} /* terminating entry */
@@ -210,6 +212,7 @@ static __devinitdata struct usb_device_i {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4P)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, {} /* terminating entry */
PATCH 26/123 USB: mos7840: fix DMA buffers on stack and endianess bugs
In reply to Greg KHFrom: Johan Hovold <[email protected]>
commit 9e221a35f82cbef0397d81fed588bafba95b550c upstream.
--- drivers/usb/serial/mos7840.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)
drivers/usb/serial/mos7840.c +18 -4
@@ -286,12 +286,19 @@ static int mos7840_get_reg_sync(struct u {struct usb_device *dev = port->serial->dev;int ret =0 ; +u8 *buf; + + buf =kmalloc (VENDOR_READ_LENGTH ,GFP_KERNEL ); +if (!buf) +return -ENOMEM ; ret =usb_control_msg (dev,usb_rcvctrlpipe (dev,0 ),MCS_RDREQ , -MCS_RD_RTYPE ,0 , reg, val,VENDOR_READ_LENGTH , +MCS_RD_RTYPE ,0 , reg, buf,VENDOR_READ_LENGTH ,MOS_WDR_TIMEOUT ); + *val = buf[0 ];dbg ("mos7840_get_reg_sync offset is %x, return val %x" , reg, *val); - *val = (*val) &0x00ff ; + +kfree (buf);return ret; }
@@ -344,6 +351,11 @@ static int mos7840_get_uart_reg(struct ustruct usb_device *dev = port->serial->dev;int ret =0 ;__u16 Wval; +u8 *buf; + + buf =kmalloc (VENDOR_READ_LENGTH ,GFP_KERNEL ); +if (!buf) +return -ENOMEM ;/* dbg("application number is %4x", (((__u16)port->number - (__u16)(port->serial->minor))+1)<<8); */
@@ -367,9 +379,11 @@ static int mos7840_get_uart_reg(struct u } } ret =usb_control_msg (dev,usb_rcvctrlpipe (dev,0 ),MCS_RDREQ , -MCS_RD_RTYPE , Wval, reg, val,VENDOR_READ_LENGTH , +MCS_RD_RTYPE , Wval, reg, buf,VENDOR_READ_LENGTH ,MOS_WDR_TIMEOUT ); - *val = (*val) &0x00ff ; + *val = buf[0 ]; + +kfree (buf);return ret; }
PATCH 27/123 usb: serial: mos7840: Add USB IDs to support more B&B USB/RS485 converters.
In reply to Greg KHFrom: Dave Ludlow <[email protected]>
commit 870408c8291015872a7a0b583673a9e56b3e73f4 upstream.
Add the USB IDs needed to support the B&B USOPTL4-4P, USO9ML2-2P, and USO9ML2-4P. This patch expands and corrects a typo in the patch sent on 08-31-2010.
--- drivers/usb/serial/mos7840.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-)
drivers/usb/serial/mos7840.c +22 -13
@@ -120,17 +120,20 @@* by making a change here, in moschip_port_id_table, and in * moschip_id_table_combined */ -#define USB_VENDOR_ID_BANDB 0x0856 -#define BANDB_DEVICE_ID_USO9ML2_2 0xAC22 -#define BANDB_DEVICE_ID_USO9ML2_4 0xAC24 -#define BANDB_DEVICE_ID_US9ML2_2 0xAC29 -#define BANDB_DEVICE_ID_US9ML2_4 0xAC30 -#define BANDB_DEVICE_ID_USPTL4_2 0xAC31 -#define BANDB_DEVICE_ID_USPTL4_4 0xAC32 -#define BANDB_DEVICE_ID_USOPTL4_2 0xAC42 -#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44 -#define BANDB_DEVICE_ID_USOPTL2_4 0xAC24 -#define BANDB_DEVICE_ID_USOPTL4_2P 0xBC02 +#define USB_VENDOR_ID_BANDB 0x0856 +#define BANDB_DEVICE_ID_USO9ML2_2 0xAC22 +#define BANDB_DEVICE_ID_USO9ML2_2P 0xBC00 +#define BANDB_DEVICE_ID_USO9ML2_4 0xAC24 +#define BANDB_DEVICE_ID_USO9ML2_4P 0xBC01 +#define BANDB_DEVICE_ID_US9ML2_2 0xAC29 +#define BANDB_DEVICE_ID_US9ML2_4 0xAC30 +#define BANDB_DEVICE_ID_USPTL4_2 0xAC31 +#define BANDB_DEVICE_ID_USPTL4_4 0xAC32 +#define BANDB_DEVICE_ID_USOPTL4_2 0xAC42 +#define BANDB_DEVICE_ID_USOPTL4_2P 0xBC02 +#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44 +#define BANDB_DEVICE_ID_USOPTL4_4P 0xBC03 +#define BANDB_DEVICE_ID_USOPTL2_4 0xAC24/* This driver also supports * ATEN UC2324 device using Moschip MCS7840
@@ -186,15 +189,18 @@ static struct usb_device_id moschip_port {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4P)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, {} /* terminating entry */
@@ -204,15 +210,18 @@ static __devinitdata struct usb_device_i {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4P)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, {} /* terminating entry */
PATCH 28/123 USB: Exposing second ACM channel as tty for Nokia S60 phones.
In reply to Greg KHFrom: Adrian Taylor <[email protected]>
commit c1479a92cf0a7792298d364e44a781550621cb58 upstream.
Nokia S60 phones expose two ACM channels. The first is a modem and is picked up by the standard AT-command interface information in the CDC-ACM driver. The second is marked as having a vendor-specific protocol. Normally, we don't expose those as ttys. (On some other devices, they may be claimed by the rndis_host driver and used as a network interface).
But on S60 this second ACM channel is the way that third-party S60 application developers are expected to communicate over USB. It acts as a serial device at the S60 end, and so it should on Linux too.
The list of devices is largely derived from:
http://wiki.forum.nokia.com/index.php/S60_Platform_and_device_identification_codes
http://wiki.forum.nokia.com/index.php/Nokia_USB_Product_IDs
and includes only the S60 3rd Edition+ devices documented there.
There are many devices for which the USB device ID is not documented, including:
Nokia 6290
Nokia E63
Nokia 5630 XpressMusic
Nokia 5730 XpressMusic
Nokia 6710 Navigator
Nokia 6720 classic
Nokia 6730 Classic
Nokia 6760 slide
Nokia 6790 slide
Nokia 6790 Surge
Nokia E52
Nokia E55
Nokia E71x (AT&T)
Nokia E72
Nokia E75
Nokia E75 US+LTA variant
Nokia N79
Nokia N86 8MP
Nokia 5230 (RM-588)
Nokia 5230 (RM-594)
Nokia 5530 XpressMusic
Nokia 5530 XpressMusic (china)
Nokia 5800 XM
Nokia N97 (RM-506)
Nokia N97 mini
Nokia X6
It would be good to add those subsequently.
--- drivers/usb/class/cdc-acm.c | 58 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-)
drivers/usb/class/cdc-acm.c +57 -1
@@ -1464,6 +1464,12 @@ err_out: }#endif /* CONFIG_PM */ + +#define NOKIA_PCSUITE_ACM_INFO (x) \ + USB_DEVICE_AND_INTERFACE_INFO(0x0421, x, \ + USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \ + USB_CDC_ACM_PROTO_VENDOR) +/* * USB driver structure. */
@@ -1522,6 +1528,57 @@ static struct usb_device_id acm_ids[] = .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ }, +/* Nokia S60 phones expose two ACM channels. The first is +* a modem and is picked up by the standard AT-command +* information below. The second is 'vendor-specific' but +* is treated as a serial device at the S60 end, so we want +* to expose it on Linux too. */ + { NOKIA_PCSUITE_ACM_INFO(0x042D), }, /* Nokia 3250 */ + { NOKIA_PCSUITE_ACM_INFO(0x04D8), }, /* Nokia 5500 Sport */ + { NOKIA_PCSUITE_ACM_INFO(0x04C9), }, /* Nokia E50 */ + { NOKIA_PCSUITE_ACM_INFO(0x0419), }, /* Nokia E60 */ + { NOKIA_PCSUITE_ACM_INFO(0x044D), }, /* Nokia E61 */ + { NOKIA_PCSUITE_ACM_INFO(0x0001), }, /* Nokia E61i */ + { NOKIA_PCSUITE_ACM_INFO(0x0475), }, /* Nokia E62 */ + { NOKIA_PCSUITE_ACM_INFO(0x0508), }, /* Nokia E65 */ + { NOKIA_PCSUITE_ACM_INFO(0x0418), }, /* Nokia E70 */ + { NOKIA_PCSUITE_ACM_INFO(0x0425), }, /* Nokia N71 */ + { NOKIA_PCSUITE_ACM_INFO(0x0486), }, /* Nokia N73 */ + { NOKIA_PCSUITE_ACM_INFO(0x04DF), }, /* Nokia N75 */ + { NOKIA_PCSUITE_ACM_INFO(0x000e), }, /* Nokia N77 */ + { NOKIA_PCSUITE_ACM_INFO(0x0445), }, /* Nokia N80 */ + { NOKIA_PCSUITE_ACM_INFO(0x042F), }, /* Nokia N91 & N91 8GB */ + { NOKIA_PCSUITE_ACM_INFO(0x048E), }, /* Nokia N92 */ + { NOKIA_PCSUITE_ACM_INFO(0x0420), }, /* Nokia N93 */ + { NOKIA_PCSUITE_ACM_INFO(0x04E6), }, /* Nokia N93i */ + { NOKIA_PCSUITE_ACM_INFO(0x04B2), }, /* Nokia 5700 XpressMusic */ + { NOKIA_PCSUITE_ACM_INFO(0x0134), }, /* Nokia 6110 Navigator (China) */ + { NOKIA_PCSUITE_ACM_INFO(0x046E), }, /* Nokia 6110 Navigator */ + { NOKIA_PCSUITE_ACM_INFO(0x002f), }, /* Nokia 6120 classic & */ + { NOKIA_PCSUITE_ACM_INFO(0x0088), }, /* Nokia 6121 classic */ + { NOKIA_PCSUITE_ACM_INFO(0x00fc), }, /* Nokia 6124 classic */ + { NOKIA_PCSUITE_ACM_INFO(0x0042), }, /* Nokia E51 */ + { NOKIA_PCSUITE_ACM_INFO(0x00b0), }, /* Nokia E66 */ + { NOKIA_PCSUITE_ACM_INFO(0x00ab), }, /* Nokia E71 */ + { NOKIA_PCSUITE_ACM_INFO(0x0481), }, /* Nokia N76 */ + { NOKIA_PCSUITE_ACM_INFO(0x0007), }, /* Nokia N81 & N81 8GB */ + { NOKIA_PCSUITE_ACM_INFO(0x0071), }, /* Nokia N82 */ + { NOKIA_PCSUITE_ACM_INFO(0x04F0), }, /* Nokia N95 & N95-3 NAM */ + { NOKIA_PCSUITE_ACM_INFO(0x0070), }, /* Nokia N95 8GB */ + { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */ + { NOKIA_PCSUITE_ACM_INFO(0x0099), }, /* Nokia 6210 Navigator, RM-367 */ + { NOKIA_PCSUITE_ACM_INFO(0x0128), }, /* Nokia 6210 Navigator, RM-419 */ + { NOKIA_PCSUITE_ACM_INFO(0x008f), }, /* Nokia 6220 Classic */ + { NOKIA_PCSUITE_ACM_INFO(0x00a0), }, /* Nokia 6650 */ + { NOKIA_PCSUITE_ACM_INFO(0x007b), }, /* Nokia N78 */ + { NOKIA_PCSUITE_ACM_INFO(0x0094), }, /* Nokia N85 */ + { NOKIA_PCSUITE_ACM_INFO(0x003a), }, /* Nokia N96 & N96-3 */ + { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */ + { NOKIA_PCSUITE_ACM_INFO(0x0108), }, /* Nokia 5320 XpressMusic 2G */ + { NOKIA_PCSUITE_ACM_INFO(0x01f5), }, /* Nokia N97, RM-505 */ + + /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ + /* control interfaces with various AT-command sets */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_ACM_PROTO_AT_V25TER) },
@@ -1536,7 +1593,6 @@ static struct usb_device_id acm_ids[] = { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_ACM_PROTO_AT_CDMA) }, -/* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */ { } };
PATCH 29/123 USB: cdc-acm: add another device quirk
In reply to Greg KHFrom: Russ Nelson <[email protected]>
commit c3baa19b0a9b711b02cec81d9fea33b7b9628957 upstream.
The Maretron USB100 needs this quirk in order to work properly.
--- drivers/usb/class/cdc-acm.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/usb/class/cdc-acm.c +3 -0
@@ -1527,6 +1527,9 @@ static struct usb_device_id acm_ids[] = { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ .driver_info =NO_UNION_NORMAL ,/* reports zero length descriptor */ }, + { USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */ + .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ + },/* Nokia S60 phones expose two ACM channels. The first is * a modem and is picked up by the standard AT-command
PATCH 30/123 USB: Expose vendor-specific ACM channel on Nokia 5230
In reply to Greg KHFrom: Przemo Firszt <[email protected]>
commit 83a4eae9aeed4a69e89e323a105e653ae06e7c1f upstream.
Nokia S60 phones expose two ACM channels. The first is a modem, the second is 'vendor-specific' but is treated as a serial device at the S60 end, so we want to expose it on Linux too.
--- drivers/usb/class/cdc-acm.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/class/cdc-acm.c +1 -0
@@ -1579,6 +1579,7 @@ static struct usb_device_id acm_ids[] = { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */ { NOKIA_PCSUITE_ACM_INFO(0x0108), }, /* Nokia 5320 XpressMusic 2G */ { NOKIA_PCSUITE_ACM_INFO(0x01f5), }, /* Nokia N97, RM-505 */ + { NOKIA_PCSUITE_ACM_INFO(0x02e3), }, /* Nokia 5230, RM-588 *//* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
PATCH 31/123 USB: cdc-acm: Adding second ACM channel support for various Nokia and one Samsung phones
In reply to Greg KHFrom: Toby Gray <[email protected]>
commit 4035e45632c2a8bb4edae83c20447051bd9a9604 upstream.
S60 phones from Nokia and Samsung expose two ACM channels. The first is a modem with a standard AT-command interface, which is picked up correctly by CDC-ACM.
The second ACM port is marked as having a vendor-specific protocol. This means that the ACM driver will not claim the second channel by default.
This adds support for the second ACM channel for the following devices:
Nokia E63
Nokia E75
Nokia 6760 Slide
Nokia E52
Nokia E55
Nokia E72
Nokia X6
Nokia N97 Mini
Nokia 5800 Xpressmusic
Nokia E90
Samsung GTi8510 (INNOV8)
--- drivers/usb/class/cdc-acm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
drivers/usb/class/cdc-acm.c +16 -0
@@ -1470,6 +1470,11 @@ err_out: USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \ USB_CDC_ACM_PROTO_VENDOR) +#define SAMSUNG_PCSUITE_ACM_INFO (x) \ + USB_DEVICE_AND_INTERFACE_INFO(0x04e7, x, \ + USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \ + USB_CDC_ACM_PROTO_VENDOR) +/* * USB driver structure. */
@@ -1580,6 +1585,17 @@ static struct usb_device_id acm_ids[] = { NOKIA_PCSUITE_ACM_INFO(0x0108), }, /* Nokia 5320 XpressMusic 2G */ { NOKIA_PCSUITE_ACM_INFO(0x01f5), }, /* Nokia N97, RM-505 */ { NOKIA_PCSUITE_ACM_INFO(0x02e3), }, /* Nokia 5230, RM-588 */ + { NOKIA_PCSUITE_ACM_INFO(0x0178), }, /* Nokia E63 */ + { NOKIA_PCSUITE_ACM_INFO(0x010e), }, /* Nokia E75 */ + { NOKIA_PCSUITE_ACM_INFO(0x02d9), }, /* Nokia 6760 Slide */ + { NOKIA_PCSUITE_ACM_INFO(0x01d0), }, /* Nokia E52 */ + { NOKIA_PCSUITE_ACM_INFO(0x0223), }, /* Nokia E72 */ + { NOKIA_PCSUITE_ACM_INFO(0x0275), }, /* Nokia X6 */ + { NOKIA_PCSUITE_ACM_INFO(0x026c), }, /* Nokia N97 Mini */ + { NOKIA_PCSUITE_ACM_INFO(0x0154), }, /* Nokia 5800 XpressMusic */ + { NOKIA_PCSUITE_ACM_INFO(0x04ce), }, /* Nokia E90 */ + { NOKIA_PCSUITE_ACM_INFO(0x01d4), }, /* Nokia E55 */ + { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) *//* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
PATCH 32/123 USB: cdc-acm: Add pseudo modem without AT command capabilities
In reply to Greg KHFrom: Philippe Corbes <[email protected]>
commit 5b239f0aebd4dd6f85b13decf5e18e86e35d57f0 upstream.
cdc-acm.c : Manage pseudo-modem without AT commands capabilities
Enable to drive electronic simple gadgets based on microcontrolers. The Interface descriptor is like this:
bInterfaceClass 2 Communications
bInterfaceSubClass 2 Abstract (modem)
bInterfaceProtocol 0 None--- drivers/usb/class/cdc-acm.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/class/cdc-acm.c +4 -0
@@ -1599,6 +1599,10 @@ static struct usb_device_id acm_ids[] =/* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ +/* control interfaces without any protocol set */ + {USB_INTERFACE_INFO (USB_CLASS_COMM ,USB_CDC_SUBCLASS_ACM , + USB_CDC_PROTO_NONE) }, +/* control interfaces with various AT-command sets */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_ACM_PROTO_AT_V25TER) },
PATCH 33/123 USB: cdc-acm: Fixing crash when ACM probing interfaces with no endpoint descriptors.
In reply to Greg KHFrom: Toby Gray <[email protected]>
commit 577045c0a76e34294f902a7d5d60e90b04d094d0 upstream.
Certain USB devices, such as the Nokia X6 mobile phone, don't expose any endpoint descriptors on some of their interfaces. If the ACM driver is forced to probe all interfaces on a device the a NULL pointer dereference will occur when the ACM driver attempts to use the endpoint of the alternative settings. One way to get the ACM driver to probe all the interfaces is by using the /sys/bus/usb/drivers/cdc_acm/new_id interface.
This patch checks that the endpoint pointer for the current alternate settings is non-NULL before using it.
--- drivers/usb/class/cdc-acm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/usb/class/cdc-acm.c +2 -1
@@ -971,7 +971,8 @@ static int acm_probe(struct usb_interfac }if (!buflen) { -if (intf->cur_altsetting->endpoint->extralen && +if (intf->cur_altsetting->endpoint && + intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {dev_dbg (&intf->dev,"Seeking extra descriptors on endpoint\n" );
PATCH 34/123 ALSA: hda - Fix auto-parser of ALC269vb for HP pin NID 0x21
In reply to Greg KHFrom: Kailang Yang <[email protected]>
commit 531d8791accf1464bc6854ff69d08dd866189d17 upstream.
ALC269vb has an alternative HP pin 0x21 in addition. Fix the parser to recognize it.
--- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+)
sound/pci/hda/patch_realtek.c +1 -0
@@ -12389,6 +12389,7 @@ static int alc268_new_analog_output(stru dac =0x02 ;break ;case 0x15 : +case 0x21 :/* ALC269vb has this pin, too */ dac =0x03 ;break ;default :
PATCH 35/123 ALSA: seq/oss - Fix double-free at error path of snd_seq_oss_open()
In reply to Greg KHFrom: Takashi Iwai <[email protected]>
commit 27f7ad53829f79e799a253285318bff79ece15bd upstream.
The error handling in snd_seq_oss_open() has several bad codes that do dereferecing released pointers and double-free of kmalloc'ed data. The object dp is release in free_devinfo() that is called via private_free callback. The rest shouldn't touch this object any more.
The patch changes delete_port() to call kfree() in any case, and gets rid of unnecessary calls of destructors in snd_seq_oss_open().
Fixes CVE-2010-3080.
--- sound/core/seq/oss/seq_oss_init.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
sound/core/seq/oss/seq_oss_init.c +4 -5
@@ -280,13 +280,10 @@ snd_seq_oss_open(struct file *file, intreturn 0 ; _error: -snd_seq_oss_writeq_delete (dp->writeq); -snd_seq_oss_readq_delete (dp->readq);snd_seq_oss_synth_cleanup (dp);snd_seq_oss_midi_cleanup (dp); -delete_port (dp);delete_seq_queue (dp->queue); -kfree (dp); +delete_port (dp);return rc; }
@@ -349,8 +346,10 @@ create_port(struct seq_oss_devinfo *dp)static int delete_port (struct seq_oss_devinfo *dp) { -if (dp->port <0 ) +if (dp->port <0 ) { +kfree (dp);return 0 ; + }debug_printk (("delete_port %i\n" , dp->port));return snd_seq_event_port_detach (dp->cseq, dp->port);
PATCH 36/123 sysfs: checking for NULL instead of ERR_PTR
In reply to Greg KHFrom: Dan Carpenter <[email protected]>
commit 57f9bdac2510cd7fda58e4a111d250861eb1ebeb upstream.
d_path() returns an ERR_PTR and it doesn't return NULL.
--- fs/sysfs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/sysfs/file.c +1 -1
@@ -340,7 +340,7 @@ static int sysfs_open_file(struct inodechar *p; p =d_path (&file->f_path, last_sysfs_file,sizeof (last_sysfs_file)); -if (p) +if (!IS_ERR (p))memmove (last_sysfs_file, p,strlen (p) +1 );/* need attr_sd for attr and ops, its parent for kobj */
PATCH 37/123 tun: Dont add sysfs attributes to devices without sysfs directories
In reply to Greg KHFrom: Ben Hutchings <[email protected]>
This applies to 2.6.32 *only*. It has not been applied upstream since the limitation no longer exists.
Prior to Linux 2.6.35, net devices outside the initial net namespace did not have sysfs directories. Attempting to add attributes to them will trigger a BUG().
--- drivers/net/tun.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/tun.c +2 -1
@@ -1006,7 +1006,8 @@ static int tun_set_iff(struct net *net,if (err <0 ) goto err_free_sk; -if (device_create_file (&tun->dev->dev, &dev_attr_tun_flags) || +if (!net_eq (dev_net (tun->dev), &init_net) || +device_create_file (&tun->dev->dev, &dev_attr_tun_flags) ||device_create_file (&tun->dev->dev, &dev_attr_owner) ||device_create_file (&tun->dev->dev, &dev_attr_group))printk (KERN_ERR "Failed to create tun sysfs files\n" );
PATCH 38/123 oprofile: fix crash when accessing freed task structs
In reply to Greg KHFrom: Robert Richter <[email protected]>
commit 750d857c682f4db60d14722d430c7ccc35070962 upstream.
This patch fixes a crash during shutdown reported below. The crash is caused by accessing already freed task structs. The fix changes the order for registering and unregistering notifier callbacks.
All notifiers must be initialized before buffers start working. To stop buffer synchronization we cancel all workqueues, unregister the notifier callback and then flush all buffers. After all of this we finally can free all tasks listed.
This should avoid accessing freed tasks.
Quoted 18 lines · Benjamin Herrenschmidt
So the initial observation is a spinlock bad magic followed by a crash in the spinlock debug code:
[ 1541.586531] BUG: spinlock bad magic on CPU#5, events/5/136 [ 1541.597564] Unable to handle kernel paging request for data at address 0x6b6b6b6b6b6b6d03Backtrace looks like:
spin_bug+0x74/0xd4 ._raw_spin_lock+0x48/0x184 ._spin_lock+0x10/0x24 .get_task_mm+0x28/0x8c .sync_buffer+0x1b4/0x598 .wq_sync_buffer+0xa0/0xdc .worker_thread+0x1d8/0x2a8 .kthread+0xa8/0xb4 .kernel_thread+0x54/0x70
Quoted 2 lines
So we are accessing a freed task struct in the work queue when processing the samples.
--- drivers/oprofile/buffer_sync.c | 27 ++++++++++++++------------- drivers/oprofile/cpu_buffer.c | 2 -- 2 files changed, 14 insertions(+), 15 deletions(-)
drivers/oprofile/buffer_sync.c +14 -13
@@ -140,16 +140,6 @@ static struct notifier_block module_load .notifier_call = module_load_notify, }; - -static void end_sync (void ) -{ -end_cpu_work (); -/* make sure we don't leak task structs */ -process_task_mortuary (); -process_task_mortuary (); -} - -int sync_start (void ) {int err;
@@ -157,7 +147,7 @@ int sync_start(void)if (!zalloc_cpumask_var (&marked_cpus,GFP_KERNEL ))return -ENOMEM ; -start_cpu_work (); +mutex_lock (&buffer_mutex); err =task_handoff_register (&task_free_nb);if (err)
@@ -172,7 +162,10 @@ int sync_start(void)if (err) goto out4; +start_cpu_work (); + out: +mutex_unlock (&buffer_mutex);return err; out4:profile_event_unregister (PROFILE_MUNMAP , &munmap_nb);
@@ -181,7 +174,6 @@ out3: out2:task_handoff_unregister (&task_free_nb); out1: -end_sync ();free_cpumask_var (marked_cpus); goto out; }
@@ -189,11 +181,20 @@ out1:void sync_stop (void ) { +/* flush buffers */ +mutex_lock (&buffer_mutex); +end_cpu_work ();unregister_module_notifier (&module_load_nb);profile_event_unregister (PROFILE_MUNMAP , &munmap_nb);profile_event_unregister (PROFILE_TASK_EXIT , &task_exit_nb);task_handoff_unregister (&task_free_nb); -end_sync (); +mutex_unlock (&buffer_mutex); +flush_scheduled_work (); + +/* make sure we don't leak task structs */ +process_task_mortuary (); +process_task_mortuary (); +free_cpumask_var (marked_cpus); }
drivers/oprofile/cpu_buffer.c +0 -2
@@ -121,8 +121,6 @@ void end_cpu_work(void)cancel_delayed_work (&b->work); } - -flush_scheduled_work (); }/*
PATCH 39/123 oprofile, x86: fix init_sysfs error handling
In reply to Greg KHFrom: Robert Richter <[email protected]>
commit 10f0412f57f2a76a90eff4376f59cbb0a39e4e18 upstream.
On failure init_sysfs() might not properly free resources. The error code of the function is not checked. And, when reinitializing the exit function might be called twice. This patch fixes all this.
--- arch/x86/oprofile/nmi_int.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
arch/x86/oprofile/nmi_int.c +13 -3
@@ -518,8 +518,13 @@ static int __init init_sysfs(void)int error; error =sysdev_class_register (&oprofile_sysclass); -if (!error) - error =sysdev_register (&device_oprofile); +if (error) +return error; + + error =sysdev_register (&device_oprofile); +if (error) +sysdev_class_unregister (&oprofile_sysclass); +return error; }
@@ -645,6 +650,8 @@ int __init op_nmi_init(struct oprofile_ochar *cpu_type =NULL ;int ret =0 ; + using_nmi =0 ; +if (!cpu_has_apic)return -ENODEV ;
@@ -727,7 +734,10 @@ int __init op_nmi_init(struct oprofile_omux_init (ops); -init_sysfs (); + ret =init_sysfs (); +if (ret) +return ret; + using_nmi =1 ;printk (KERN_INFO "oprofile: using NMI interrupt.\n" );return 0 ;
PATCH 40/123 oprofile, x86: fix init_sysfs() function stub
In reply to Greg KHFrom: Robert Richter <[email protected]>
commit 269f45c25028c75fe10e6d9be86e7202ab461fbc upstream.
The use of the return value of init_sysfs() with commit
10f0412 oprofile, x86: fix init_sysfs error handling
discovered the following build error for !CONFIG_PM:
.../linux/arch/x86/oprofile/nmi_int.c: In function ‘op_nmi_init’:
.../linux/arch/x86/oprofile/nmi_int.c:784: error: expected expression before ‘do’ make[2]: *** [arch/x86/oprofile/nmi_int.o] Error 1
make[1]: *** [arch/x86/oprofile] Error 2
This patch fixes this.
--- arch/x86/oprofile/nmi_int.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
arch/x86/oprofile/nmi_int.c +4 -2
@@ -535,8 +535,10 @@ static void exit_sysfs(void) }#else -#define init_sysfs () do { } while (0) -#define exit_sysfs () do { } while (0) + +static inline int init_sysfs (void ) {return 0 ; } +static inline void exit_sysfs (void ) { } +#endif /* CONFIG_PM */ static int __init p4_init (char **cpu_type)
PATCH 41/123 HID: usbhid: initialize interface pointers early enough
In reply to Greg KHFrom: Jiri Kosina <[email protected]>
commit 57ab12e418ec4fe24c11788bb1bbdabb29d05679 upstream.
Move the initialization of USB interface pointers from _start() over to _probe() callback, which is where it belongs.
This fixes case where interface is NULL when parsing of report descriptor fails.
LKML-Reference: <[email protected]>
--- drivers/hid/usbhid/hid-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/hid/usbhid/hid-core.c +2 -3
@@ -1007,9 +1007,6 @@ static int usbhid_start(struct hid_devicspin_lock_init (&usbhid->lock); - usbhid->intf = intf; - usbhid->ifnum = interface->desc.bInterfaceNumber; - usbhid->urbctrl =usb_alloc_urb (0 ,GFP_KERNEL );if (!usbhid->urbctrl) { ret = -ENOMEM ;
@@ -1180,6 +1177,8 @@ static int usbhid_probe(struct usb_inter hid->driver_data = usbhid; usbhid->hid = hid; + usbhid->intf = intf; + usbhid->ifnum = interface->desc.bInterfaceNumber; ret =hid_add_device (hid);if (ret) {
PATCH 42/123 HID: fix suspend crash by moving initializations earlier
In reply to Greg KHFrom: Alan Stern <[email protected]>
commit fde4e2f73208b8f34f123791e39c0cb6bc74b32a upstream.
Although the usbhid driver allocates its usbhid structure in the probe routine, several critical fields in that structure don't get initialized until usbhid_start(). However if report descriptor parsing fails then usbhid_start() is never called. This leads to problems during system suspend -- the system will freeze.
This patch (as1378) fixes the bug by moving the initialization statements up into usbhid_probe().
--- drivers/hid/usbhid/hid-core.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
drivers/hid/usbhid/hid-core.c +6 -7
@@ -1000,13 +1000,6 @@ static int usbhid_start(struct hid_devic } } -init_waitqueue_head (&usbhid->wait); -INIT_WORK (&usbhid->reset_work, hid_reset); -INIT_WORK (&usbhid->restart_work, __usbhid_restart_queues); -setup_timer (&usbhid->io_retry, hid_retry_timeout, (unsigned long ) hid); - -spin_lock_init (&usbhid->lock); - usbhid->urbctrl =usb_alloc_urb (0 ,GFP_KERNEL );if (!usbhid->urbctrl) { ret = -ENOMEM ;
@@ -1180,6 +1173,12 @@ static int usbhid_probe(struct usb_inter usbhid->intf = intf; usbhid->ifnum = interface->desc.bInterfaceNumber; +init_waitqueue_head (&usbhid->wait); +INIT_WORK (&usbhid->reset_work, hid_reset); +INIT_WORK (&usbhid->restart_work, __usbhid_restart_queues); +setup_timer (&usbhid->io_retry, hid_retry_timeout, (unsigned long ) hid); +spin_lock_init (&usbhid->lock); + ret =hid_add_device (hid);if (ret) {if (ret != -ENODEV )
PATCH 43/123 libata: skip EH autopsy and recovery during suspend
In reply to Greg KHFrom: Tejun Heo <[email protected]>
commit e2f3d75fc0e4a0d03c61872bad39ffa2e74a04ff upstream.
For some mysterious reason, certain hardware reacts badly to usual EH actions while the system is going for suspend. As the devices won't be needed until the system is resumed, ask EH to skip usual autopsy and recovery and proceed directly to suspend.
--- drivers/ata/libata-core.c | 14 +++++++++++++- drivers/ata/libata-eh.c | 4 ++++ include/linux/libata.h | 1 + 3 files changed, 18 insertions(+), 1 deletion(-)
drivers/ata/libata-core.c +13 -1
@@ -5504,6 +5504,7 @@ static int ata_host_request_pm(struct at*/ int ata_host_suspend (struct ata_host *host,pm_message_t mesg) { +unsigned int ehi_flags =ATA_EHI_QUIET ;int rc;/*
@@ -5512,7 +5513,18 @@ int ata_host_suspend(struct ata_host *ho*/ ata_lpm_enable (host); - rc =ata_host_request_pm (host, mesg,0 ,ATA_EHI_QUIET ,1 ); +/* +* On some hardware, device fails to respond after spun down +* for suspend. As the device won't be used before being +* resumed, we don't need to touch the device. Ask EH to skip +* the usual stuff and proceed directly to suspend. +* +* http://thread.gmane.org/gmane.linux.ide/46764 +*/ +if (mesg.event ==PM_EVENT_SUSPEND ) + ehi_flags |=ATA_EHI_NO_AUTOPSY |ATA_EHI_NO_RECOVERY ; + + rc =ata_host_request_pm (host, mesg,0 , ehi_flags,1 );if (rc ==0 ) host->dev->power.power_state = mesg;return rc;
drivers/ata/libata-eh.c +4 -0
@@ -3149,6 +3149,10 @@ static int ata_eh_skip_recovery(struct aif (link->flags &ATA_LFLAG_DISABLED )return 1 ; +/* skip if explicitly requested */ +if (ehc->i.flags &ATA_EHI_NO_RECOVERY ) +return 1 ; +/* thaw frozen port and recover failed devices */ if ((ap->pflags &ATA_PFLAG_FROZEN ) ||ata_link_nr_enabled (link))return 0 ;
include/linux/libata.h +1 -0
@@ -339,6 +339,7 @@ enum {ATA_EHI_HOTPLUGGED = (1 <<0 ),/* could have been hotplugged */ ATA_EHI_NO_AUTOPSY = (1 <<2 ),/* no autopsy */ ATA_EHI_QUIET = (1 <<3 ),/* be quiet */ +ATA_EHI_NO_RECOVERY = (1 <<4 ),/* no recovery */ ATA_EHI_DID_SOFTRESET = (1 <<16 ),/* already soft-reset this port */ ATA_EHI_DID_HARDRESET = (1 << 17), /* already soft-reset this port */
PATCH 44/123 tracing: Fix a race in function profile
In reply to Greg KHFrom: Li Zefan <[email protected]>
commit 3aaba20f26f58843e8f20611e5c0b1c06954310f upstream.
While we are reading trace_stat/functionX and someone just disabled function_profile at that time, we can trigger this:
divide error: 0000 [#1] PREEMPT SMP ... EIP is at function_stat_show+0x90/0x230 ...
This fix just takes the ftrace_profile_lock and checks if rec->counter is 0. If it's 0, we know the profile buffer has been reset.
LKML-Reference: <[email protected]>
--- kernel/trace/ftrace.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)
kernel/trace/ftrace.c +11 -4
@@ -369,11 +369,18 @@ static int function_stat_show(struct seq {struct ftrace_profile *rec = v;char str[KSYM_SYMBOL_LEN ]; +int ret =0 ;#ifdef CONFIG_FUNCTION_GRAPH_TRACER -static DEFINE_MUTEX (mutex);static struct trace_seq s;unsigned long long avg;#endif +mutex_lock (&ftrace_profile_lock); + +/* we raced with function_profile_reset() */ +if (unlikely (rec->counter ==0 )) { + ret = -EBUSY ; + goto out; + }kallsyms_lookup (rec->ip,NULL ,NULL ,NULL , str);seq_printf (m," %-30.30s %10lu" , str, rec->counter);
@@ -383,17 +390,17 @@ static int function_stat_show(struct seq avg = rec->time;do_div (avg, rec->counter); -mutex_lock (&mutex);trace_seq_init (&s);trace_print_graph_duration (rec->time, &s);trace_seq_puts (&s," " );trace_print_graph_duration (avg, &s);trace_print_seq (m, &s); -mutex_unlock (&mutex);#endif seq_putc (m,'\n' ); +out: +mutex_unlock (&ftrace_profile_lock); -return 0 ; +return ret; }static void ftrace_profile_reset (struct ftrace_profile_stat *stat)
PATCH 45/123 tracing: Do not allow llseek to set_ftrace_filter
In reply to Greg KHFrom: Steven Rostedt <[email protected]>
commit 9c55cb12c1c172e2d51e85fbb5a4796ca86b77e7 upstream.
Reading the file set_ftrace_filter does three things.
1) shows whether or not filters are set for the function tracer
2) shows what functions are set for the function tracer
3) shows what triggers are set on any functions
3 is independent from 1 and 2.
The way this file currently works is that it is a state machine, and as you read it, it may change state. But this assumption breaks when you use lseek() on the file. The state machine gets out of sync and the t_show() may use the wrong pointer and cause a kernel oops.
Luckily, this will only kill the app that does the lseek, but the app dies while holding a mutex. This prevents anyone else from using the set_ftrace_filter file (or any other function tracing file for that matter).
A real fix for this is to rewrite the code, but that is too much for a -rc release or stable. This patch simply disables llseek on the set_ftrace_filter() file for now, and we can do the proper fix for the next major release.
--- kernel/trace/ftrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/ftrace.c +1 -1
@@ -2400,7 +2400,7 @@ static const struct file_operations ftra .open = ftrace_filter_open, .read = seq_read, .write = ftrace_filter_write, - .llseek = ftrace_regex_lseek, + .llseek = no_llseek, .release = ftrace_filter_release, };
PATCH 46/123 tracing: t_start: reset FTRACE_ITER_HASH in case of seek/pread
In reply to Greg KHFrom: Chris Wright <[email protected]>
commit df09162550fbb53354f0c88e85b5d0e6129ee9cc upstream.
Be sure to avoid entering t_show() with FTRACE_ITER_HASH set without having properly started the iterator to iterate the hash. This case is degenerate and, as discovered by Robert Swiecki, can cause t_hash_show() to misuse a pointer. This causes a NULL ptr deref with possible security implications. Tracked as CVE-2010-3079.
--- kernel/trace/ftrace.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/trace/ftrace.c +2 -0
@@ -1480,6 +1480,8 @@ static void *t_start(struct seq_file *m,if (*pos >0 )return t_hash_start (m, pos); iter->flags |=FTRACE_ITER_PRINTALL ; +/* reset in case of seek/pread */ + iter->flags &= ~FTRACE_ITER_HASH ;return iter; }
PATCH 47/123 irda: off by one
In reply to Greg KHFrom: Dan Carpenter <[email protected]>
commit cf9b94f88bdbe8a02015fc30d7c232b2d262d4ad upstream.
This is an off by one. We would go past the end when we NUL terminate the "value" string at end of the function. The "value" buffer is allocated in irlan_client_parse_response() or irlan_provider_parse_command().
--- net/irda/irlan/irlan_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/irda/irlan/irlan_common.c +1 -1
@@ -1101,7 +1101,7 @@ int irlan_extract_param(__u8 *buf, charmemcpy (&val_len, buf+n,2 );/* To avoid alignment problems */ le16_to_cpus (&val_len); n+=2 ; -if (val_len >1016 ) { +if (val_len >=1016 ) {IRDA_DEBUG (2 ,"%s(), parameter length to long\n" , __func__ );return -RSP_INVALID_COMMAND_FORMAT ; }
PATCH 48/123 gcov: fix null-pointer dereference for certain module types
In reply to Greg KHFrom: Peter Oberparleiter <[email protected]>
commit 85a0fdfd0f967507f3903e8419bc7e408f5a59de upstream.
The gcov-kernel infrastructure expects that each object file is loaded only once. This may not be true, e.g. when loading multiple kernel modules which are linked to the same object file. As a result, loading such kernel modules will result in incorrect gcov results while unloading will cause a null-pointer dereference.
This patch fixes these problems by changing the gcov-kernel infrastructure so that multiple profiling data sets can be associated with one debugfs entry. It applies to 2.6.36-rc1.
--- kernel/gcov/fs.c | 244 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 180 insertions(+), 64 deletions(-)
kernel/gcov/fs.c +180 -64
@@ -33,10 +33,11 @@* @children: child nodes * @all: list head for list of all nodes * @parent: parent node -* @info: associated profiling data structure if not a directory -* @ghost: when an object file containing profiling data is unloaded we keep a -* copy of the profiling data here to allow collecting coverage data -* for cleanup code. Such a node is called a "ghost". +* @loaded_info: array of pointers to profiling data sets for loaded object +* files. +* @num_loaded: number of profiling data sets for loaded object files. +* @unloaded_info: accumulated copy of profiling data sets for unloaded +* object files. Used only when gcov_persist=1. * @dentry: main debugfs entry, either a directory or data file * @links: associated symbolic links * @name: data file basename
@@ -51,10 +52,11 @@ struct gcov_node {struct list_head children;struct list_head all;struct gcov_node *parent; -struct gcov_info *info; -struct gcov_info *ghost; +struct gcov_info **loaded_info; +struct gcov_info *unloaded_info;struct dentry *dentry;struct dentry **links; +int num_loaded;char name[0 ]; };
@@ -136,16 +138,37 @@ static const struct seq_operations gcov_ };/* -* Return the profiling data set for a given node. This can either be the -* original profiling data structure or a duplicate (also called "ghost") -* in case the associated object file has been unloaded. +* Return a profiling data set associated with the given node. This is +* either a data set for a loaded object file or a data set copy in case +* all associated object files have been unloaded. */ static struct gcov_info *get_node_info (struct gcov_node *node) { -if (node->info) -return node->info; +if (node->num_loaded >0 ) +return node->loaded_info[0 ]; -return node->ghost; +return node->unloaded_info; +} + +/* +* Return a newly allocated profiling data set which contains the sum of +* all profiling data associated with the given node. +*/ +static struct gcov_info *get_accumulated_info (struct gcov_node *node) +{ +struct gcov_info *info; +int i =0 ; + +if (node->unloaded_info) + info =gcov_info_dup (node->unloaded_info); +else + info =gcov_info_dup (node->loaded_info[i++]); +if (!info) +return NULL ; +for (; i < node->num_loaded; i++) +gcov_info_add (info, node->loaded_info[i]); + +return info; }/*
@@ -163,9 +186,10 @@ static int gcov_seq_open(struct inode *imutex_lock (&node_lock);/* * Read from a profiling data copy to minimize reference tracking -* complexity and concurrent access. +* complexity and concurrent access and to keep accumulating multiple +* profiling data sets associated with one node simple. */ - info =gcov_info_dup (get_node_info (node)); + info =get_accumulated_info (node);if (!info) goto out_unlock; iter =gcov_iter_new (info);
@@ -225,12 +249,25 @@ static struct gcov_node *get_node_by_namreturn NULL ; } +/* +* Reset all profiling data associated with the specified node. +*/ +static void reset_node (struct gcov_node *node) +{ +int i; + +if (node->unloaded_info) +gcov_info_reset (node->unloaded_info); +for (i =0 ; i < node->num_loaded; i++) +gcov_info_reset (node->loaded_info[i]); +} +static void remove_node (struct gcov_node *node);/* * write() implementation for gcov data files. Reset profiling data for the -* associated file. If the object file has been unloaded (i.e. this is -* a "ghost" node), remove the debug fs node as well. +* corresponding file. If all associated object files have been unloaded, +* remove the debug fs node as well. */ static ssize_t gcov_seq_write (struct file *file,const char __user *addr,size_t len,loff_t *pos)
@@ -245,10 +282,10 @@ static ssize_t gcov_seq_write(struct fil node =get_node_by_name (info->filename);if (node) {/* Reset counts or remove node for unloaded modules. */ -if (node->ghost) +if (node->num_loaded ==0 )remove_node (node);else -gcov_info_reset (node->info); +reset_node (node); }/* Reset counts for open file. */ gcov_info_reset (info);
@@ -378,7 +415,10 @@ static void init_node(struct gcov_node *INIT_LIST_HEAD (&node->list);INIT_LIST_HEAD (&node->children);INIT_LIST_HEAD (&node->all); - node->info = info; +if (node->loaded_info) { + node->loaded_info[0 ] = info; + node->num_loaded =1 ; + } node->parent = parent;if (name)strcpy (node->name, name);
@@ -394,9 +434,13 @@ static struct gcov_node *new_node(structstruct gcov_node *node; node =kzalloc (sizeof (struct gcov_node ) +strlen (name) +1 ,GFP_KERNEL ); -if (!node) { -pr_warning ("out of memory\n" ); -return NULL ; +if (!node) + goto err_nomem; +if (info) { + node->loaded_info =kcalloc (1 ,sizeof (struct gcov_info *), +GFP_KERNEL ); +if (!node->loaded_info) + goto err_nomem; }init_node (node, info, name, parent);/* Differentiate between gcov data file nodes and directory nodes. */
@@ -416,6 +460,11 @@ static struct gcov_node *new_node(structlist_add (&node->all, &all_head);return node; + +err_nomem: +kfree (node); +pr_warning ("out of memory\n" ); +return NULL ; }/* Remove symbolic links associated with node. */
@@ -441,8 +490,9 @@ static void release_node(struct gcov_nodlist_del (&node->all);debugfs_remove (node->dentry);remove_links (node); -if (node->ghost) -gcov_info_free (node->ghost); +kfree (node->loaded_info); +if (node->unloaded_info) +gcov_info_free (node->unloaded_info);kfree (node); }
@@ -477,7 +527,7 @@ static struct gcov_node *get_child_by_na/* * write() implementation for reset file. Reset all profiling data to zero -* and remove ghost nodes. +* and remove nodes for which all associated object files are unloaded. */ static ssize_t reset_write (struct file *file,const char __user *addr,size_t len,loff_t *pos)
@@ -487,8 +537,8 @@ static ssize_t reset_write(struct file *mutex_lock (&node_lock); restart:list_for_each_entry (node, &all_head, all) { -if (node->info) -gcov_info_reset (node->info); +if (node->num_loaded >0 ) +reset_node (node);else if (list_empty (&node->children)) {remove_node (node);/* Several nodes may have gone - restart loop. */
@@ -564,37 +614,115 @@ err_remove: }/* -* The profiling data set associated with this node is being unloaded. Store a -* copy of the profiling data and turn this node into a "ghost". +* Associate a profiling data set with an existing node. Needs to be called +* with node_lock held. */ -static int ghost_node (struct gcov_node *node) +static void add_info (struct gcov_node *node,struct gcov_info *info) { - node->ghost =gcov_info_dup (node->info); -if (!node->ghost) { -pr_warning ("could not save data for '%s' (out of memory)\n" , - node->info->filename); -return -ENOMEM ; +struct gcov_info **loaded_info; +int num = node->num_loaded; + +/* +* Prepare new array. This is done first to simplify cleanup in +* case the new data set is incompatible, the node only contains +* unloaded data sets and there's not enough memory for the array. +*/ + loaded_info =kcalloc (num +1 ,sizeof (struct gcov_info *),GFP_KERNEL ); +if (!loaded_info) { +pr_warning ("could not add '%s' (out of memory)\n" , + info->filename); +return ; + } +memcpy (loaded_info, node->loaded_info, + num *sizeof (struct gcov_info *)); + loaded_info[num] = info; +/* Check if the new data set is compatible. */ +if (num ==0 ) { +/* +* A module was unloaded, modified and reloaded. The new +* data set replaces the copy of the last one. +*/ +if (!gcov_info_is_compatible (node->unloaded_info, info)) { +pr_warning ("discarding saved data for %s " +"(incompatible version)\n" , info->filename); +gcov_info_free (node->unloaded_info); + node->unloaded_info =NULL ; + } + }else { +/* +* Two different versions of the same object file are loaded. +* The initial one takes precedence. +*/ +if (!gcov_info_is_compatible (node->loaded_info[0 ], info)) { +pr_warning ("could not add '%s' (incompatible " +"version)\n" , info->filename); +kfree (loaded_info); +return ; + } } - node->info =NULL ; +/* Overwrite previous array. */ +kfree (node->loaded_info); + node->loaded_info = loaded_info; + node->num_loaded = num +1 ; +} -return 0 ; +/* +* Return the index of a profiling data set associated with a node. +*/ +static int get_info_index (struct gcov_node *node,struct gcov_info *info) +{ +int i; + +for (i =0 ; i < node->num_loaded; i++) { +if (node->loaded_info[i] == info) +return i; + } +return -ENOENT ; }/* -* Profiling data for this node has been loaded again. Add profiling data -* from previous instantiation and turn this node into a regular node. +* Save the data of a profiling data set which is being unloaded. */ -static void revive_node (struct gcov_node *node,struct gcov_info *info) +static void save_info (struct gcov_node *node,struct gcov_info *info) { -if (gcov_info_is_compatible (node->ghost, info)) -gcov_info_add (info, node->ghost); +if (node->unloaded_info) +gcov_info_add (node->unloaded_info, info);else { -pr_warning ("discarding saved data for '%s' (version changed)\n" , + node->unloaded_info =gcov_info_dup (info); +if (!node->unloaded_info) { +pr_warning ("could not save data for '%s' " +"(out of memory)\n" , info->filename); + } + } +} + +/* +* Disassociate a profiling data set from a node. Needs to be called with +* node_lock held. +*/ +static void remove_info (struct gcov_node *node,struct gcov_info *info) +{ +int i; + + i =get_info_index (node, info); +if (i <0 ) { +pr_warning ("could not remove '%s' (not found)\n" , info->filename); +return ; } -gcov_info_free (node->ghost); - node->ghost =NULL ; - node->info = info; +if (gcov_persist) +save_info (node, info); +/* Shrink array. */ + node->loaded_info[i] = node->loaded_info[node->num_loaded -1 ]; + node->num_loaded--; +if (node->num_loaded >0 ) +return ; +/* Last loaded data set was removed. */ +kfree (node->loaded_info); + node->loaded_info =NULL ; + node->num_loaded =0 ; +if (!node->unloaded_info) +remove_node (node); }/*
@@ -609,30 +737,18 @@ void gcov_event(enum gcov_action action, node =get_node_by_name (info->filename);switch (action) {case GCOV_ADD : -/* Add new node or revive ghost. */ -if (!node) { +if (node) +add_info (node, info); +else add_node (info); -break ; - } -if (gcov_persist) -revive_node (node, info); -else { -pr_warning ("could not add '%s' (already exists)\n" , - info->filename); - }break ;case GCOV_REMOVE : -/* Remove node or turn into ghost. */ -if (!node) { +if (node) +remove_info (node, info); +else {pr_warning ("could not remove '%s' (not found)\n" , info->filename); -break ; } -if (gcov_persist) { -if (!ghost_node (node)) -break ; - } -remove_node (node);break ; }mutex_unlock (&node_lock);
PATCH 49/123 tmio_mmc: dont clear unhandled pending interrupts
In reply to Greg KHFrom: Yusuke Goda <[email protected]>
commit b78d6c5f51935ba89df8db33a57bacb547aa7325 upstream.
Previously, it was possible for ack_mmc_irqs() to clear pending interrupt bits in the CTL_STATUS register, even though the interrupt handler had not been called. This was because of a race that existed when doing a read-modify-write sequence on CTL_STATUS. After the read step in this sequence, if an interrupt occurred (causing one of the bits in CTL_STATUS to be set) the write step would inadvertently clear it.
Observed with the TMIO_STAT_RXRDY bit together with CMD53 on AR6002 and BCM4318 SDIO cards in polled mode.
This patch eliminates this race by only writing to CTL_STATUS and clearing the interrupts that were passed as an argument to ack_mmc_irqs()."
--- drivers/mmc/host/tmio_mmc.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
drivers/mmc/host/tmio_mmc.h +1 -4
@@ -102,10 +102,7 @@#define ack_mmc_irqs (host, i) \ do { \ - u32 mask;\ - mask = sd_ctrl_read32((host), CTL_STATUS); \ - mask &= ~((i) & TMIO_MASK_IRQ); \ - sd_ctrl_write32((host), CTL_STATUS, mask); \ + sd_ctrl_write32((host), CTL_STATUS, ~(i)); \ } while (0)
PATCH 50/123 mmc: fix the use of kunmap_atomic() in tmio_mmc.h
In reply to Greg KHFrom: Guennadi Liakhovetski <[email protected]>
commit 5600efb1bc2745d93ae0bc08130117a84f2b9d69 upstream.
kunmap_atomic() takes the cookie, returned by the kmap_atomic() as its argument and not the page address, used as an argument to kmap_atomic(). This patch fixes the compile error:
In file included from drivers/mmc/host/tmio_mmc.c:37:drivers/mmc/host/tmio_mmc.h: In function 'tmio_mmc_kunmap_atomic':drivers/mmc/host/tmio_mmc.h:192: error: negative width in bit-field '<anonymous>'
--- drivers/mmc/host/tmio_mmc.c | 7 ++++--- drivers/mmc/host/tmio_mmc.h | 8 +++----- 2 files changed, 7 insertions(+), 8 deletions(-)
drivers/mmc/host/tmio_mmc.c +4 -3
@@ -161,6 +161,7 @@ tmio_mmc_start_command(struct tmio_mmc_hstatic inline void tmio_mmc_pio_irq (struct tmio_mmc_host *host) {struct mmc_data *data = host->data; +void *sg_virt;unsigned short *buf;unsigned int count;unsigned long flags;
@@ -170,8 +171,8 @@ static inline void tmio_mmc_pio_irq(strureturn ; } - buf = (unsigned short *)(tmio_mmc_kmap_atomic (host, &flags) + - host->sg_off); + sg_virt =tmio_mmc_kmap_atomic (host->sg_ptr, &flags); + buf = (unsigned short *)(sg_virt + host->sg_off); count = host->sg_ptr->length - host->sg_off;if (count > data->blksz)
@@ -188,7 +189,7 @@ static inline void tmio_mmc_pio_irq(stru host->sg_off += count; -tmio_mmc_kunmap_atomic (host, &flags); +tmio_mmc_kunmap_atomic (sg_virt, &flags);if (host->sg_off == host->sg_ptr->length)tmio_mmc_next_sg (host);
drivers/mmc/host/tmio_mmc.h +3 -5
@@ -197,19 +197,17 @@ static inline int tmio_mmc_next_sg(strucreturn --host->sg_len; } -static inline char *tmio_mmc_kmap_atomic (struct tmio_mmc_host *host, +static inline char *tmio_mmc_kmap_atomic (struct scatterlist *sg,unsigned long *flags) { -struct scatterlist *sg = host->sg_ptr; -local_irq_save (*flags);return kmap_atomic (sg_page (sg),KM_BIO_SRC_IRQ ) + sg->offset; } -static inline void tmio_mmc_kunmap_atomic (struct tmio_mmc_host *host, +static inline void tmio_mmc_kunmap_atomic (void *virt,unsigned long *flags) { -kunmap_atomic (sg_page (host->sg_ptr),KM_BIO_SRC_IRQ ); +kunmap_atomic (virt,KM_BIO_SRC_IRQ );local_irq_restore (*flags); }
PATCH 51/123 bounce: call flush_dcache_page() after bounce_copy_vec()
In reply to Greg KHFrom: Gary King <[email protected]>
commit ac8456d6f9a3011c824176bd6084d39e5f70a382 upstream.
I have been seeing problems on Tegra 2 (ARMv7 SMP) systems with HIGHMEM enabled on 2.6.35 (plus some patches targetted at 2.6.36 to perform cache maintenance lazily), and the root cause appears to be that the mm bouncing code is calling flush_dcache_page before it copies the bounce buffer into the bio.
The bounced page needs to be flushed after data is copied into it, to ensure that architecture implementations can synchronize instruction and data caches if necessary.
--- mm/bounce.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/bounce.c +1 -1
@@ -115,8 +115,8 @@ static void copy_to_high_bio_irq(struct*/ vfrom =page_address (fromvec->bv_page) + tovec->bv_offset; -flush_dcache_page (tovec->bv_page);bounce_copy_vec (tovec, vfrom); +flush_dcache_page (tovec->bv_page); } }
PATCH 52/123 kernel/groups.c: fix integer overflow in groups_search
In reply to Greg KHFrom: Jerome Marchand <[email protected]>
commit 1c24de60e50fb19b94d94225458da17c720f0729 upstream.
gid_t is a unsigned int. If group_info contains a gid greater than MAX_INT, groups_search() function may look on the wrong side of the search tree.
This solves some unfair "permission denied" problems.
--- kernel/groups.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
kernel/groups.c +2 -3
@@ -143,10 +143,9 @@ int groups_search(const struct group_inf right = group_info->ngroups;while (left < right) {unsigned int mid = (left+right)/2 ; -int cmp = grp -GROUP_AT (group_info, mid); -if (cmp >0 ) +if (grp >GROUP_AT (group_info, mid)) left = mid +1 ; -else if (cmp <0 ) +else if (grp <GROUP_AT (group_info, mid)) right = mid;else return 1 ;
PATCH 53/123 binfmt_misc: fix binfmt_misc priority
In reply to Greg KHFrom: Jan Sembera <[email protected]>
commit ee3aebdd8f5f8eac41c25c80ceee3d728f920f3b upstream.
Commit 74641f584da ("alpha: binfmt_aout fix") (May 2009) introduced a regression - binfmt_misc is now consulted after binfmt_elf, which will unfortunately break ia32el. ia32 ELF binaries on ia64 used to be matched using binfmt_misc and executed using wrapper. As 32bit binaries are now matched by binfmt_elf before bindmt_misc kicks in, the wrapper is ignored.
The fix increases precedence of binfmt_misc to the original state.
--- fs/binfmt_misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/binfmt_misc.c +1 -1
@@ -723,7 +723,7 @@ static int __init init_misc_binfmt(void) {int err =register_filesystem (&bm_fs_type);if (!err) { - err =register_binfmt (&misc_format); + err =insert_binfmt (&misc_format);if (err)unregister_filesystem (&bm_fs_type); }
PATCH 54/123 Input: i8042 - fix device removal on unload
In reply to Greg KHFrom: Dmitry Torokhov <[email protected]>
commit af045b86662f17bf130239a65995c61a34f00a6b upstream.
We need to call platform_device_unregister(i8042_platform_device) before calling platform_driver_unregister() because i8042_remove() resets i8042_platform_device to NULL. This leaves the platform device instance behind and prevents driver reload.
Fixes https://bugzilla.kernel.org/show_bug.cgi?id=16613
--- drivers/input/serio/i8042.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/input/serio/i8042.c +1 -1
@@ -1412,8 +1412,8 @@ static int __init i8042_init(void) static void __exit i8042_exit(void) { -platform_driver_unregister (&i8042_driver);platform_device_unregister (i8042_platform_device); +platform_driver_unregister (&i8042_driver);i8042_platform_exit (); panic_blink =NULL ;
PATCH 55/123 memory hotplug: fix next block calculation in is_removable
In reply to Greg KHFrom: KAMEZAWA Hiroyuki <[email protected]>
commit 0dcc48c15f63ee86c2fcd33968b08d651f0360a5 upstream.
next_active_pageblock() is for finding next _used_ freeblock. It skips several blocks when it finds there are a chunk of free pages lager than pageblock. But it has 2 bugs.
1. We have no lock. page_order(page) - pageblock_order can be minus.
2. pageblocks_stride += is wrong. it should skip page_order(p) of pages.
--- mm/memory_hotplug.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
mm/memory_hotplug.c +8 -8
@@ -551,19 +551,19 @@ static inline int pageblock_free(struct/* Return the start of the next active pageblock after a given page */ static struct page *next_active_pageblock (struct page *page) { -int pageblocks_stride; -/* Ensure the starting page is pageblock-aligned */ BUG_ON (page_to_pfn (page) & (pageblock_nr_pages -1 )); -/* Move forward by at least 1 * pageblock_nr_pages */ - pageblocks_stride =1 ; -/* If the entire pageblock is free, move to the end of free page */ -if (pageblock_free (page)) - pageblocks_stride +=page_order (page) - pageblock_order; +if (pageblock_free (page)) { +int order; +/* be careful. we don't have locks, page_order can be changed.*/ + order =page_order (page); +if ((order <MAX_ORDER ) && (order >= pageblock_order)) +return page + (1 << order); + } -return page + (pageblocks_stride * pageblock_nr_pages); +return page + pageblock_nr_pages; }/* Checks if this range of memory is likely to be hot-removable. */
PATCH 56/123 perf: Initialize callchains rootss childen hits
In reply to Greg KHFrom: Frederic Weisbecker <[email protected]>
commit 5225c45899e872383ca39f5533d28ec63c54b39e upstream.
Each histogram entry has a callchain root that stores the callchain samples. However we forgot to initialize the tracking of children hits of these roots, which then got random values on their creation.
The root children hits is multiplied by the minimum percentage of hits provided by the user, and the result becomes the minimum hits expected from children branches. If the random value due to the uninitialization is big enough, then this minimum number of hits can be huge and eventually filter every children branches.
The end result was invisible callchains. All we need to fix this is to initialize the children hits of the root.
--- tools/perf/util/callchain.h | 1 + 1 file changed, 1 insertion(+)
tools/perf/util/callchain.h +1 -0
@@ -49,6 +49,7 @@ static inline void callchain_init(structINIT_LIST_HEAD (&node->children);INIT_LIST_HEAD (&node->val); + node->children_hit =0 ; node->parent =NULL ; node->hit =0 ; }
PATCH 57/123 p54: fix tx feedback status flag check
In reply to Greg KHFrom: Christian Lamparter <[email protected]>
commit f880c2050f30b23c9b6f80028c09f76e693bf309 upstream.
Michael reported that p54* never really entered power save mode, even tough it was enabled.
It turned out that upon a power save mode change the firmware will set a special flag onto the last outgoing frame tx status (which in this case is almost always the designated PSM nullfunc frame). This flag confused the driver; It erroneously reported transmission failures to the stack, which then generated the next nullfunc. and so on...
--- drivers/net/wireless/p54/txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/p54/txrx.c +1 -1
@@ -445,7 +445,7 @@ static void p54_rx_frame_sent(struct p54 }if (!(info->flags &IEEE80211_TX_CTL_NO_ACK ) && - (!payload->status)) + !(payload->status &P54_TX_FAILED )) info->flags |=IEEE80211_TX_STAT_ACK ;if (payload->status &P54_TX_PSM_CANCELLED ) info->flags |=IEEE80211_TX_STAT_TX_FILTERED ;
PATCH 58/123 ath5k: check return value of ieee80211_get_tx_rate
In reply to Greg KHFrom: John W. Linville <[email protected]>
commit d8e1ba76d619dbc0be8fbeee4e6c683b5c812d3a upstream.
This avoids a NULL pointer dereference as reported here:
https://bugzilla.redhat.com/show_bug.cgi?id=625889
When the WARN condition is hit in ieee80211_get_tx_rate, it will return NULL. So, we need to check the return value and avoid dereferencing it in that case.
--- drivers/net/wireless/ath/ath5k/base.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/wireless/ath/ath5k/base.c +4 -0
@@ -1288,6 +1288,10 @@ ath5k_txbuf_setup(struct ath5k_softc *sc PCI_DMA_TODEVICE); rate =ieee80211_get_tx_rate (sc->hw, info); +if (!rate) { + ret = -EINVAL ; + goto err_unmap; + }if (info->flags &IEEE80211_TX_CTL_NO_ACK ) flags |=AR5K_TXDESC_NOACK ;
PATCH 59/123 wireless extensions: fix kernel heap content leak
In reply to Greg KHFrom: Johannes Berg <[email protected]>
commit 42da2f948d949efd0111309f5827bf0298bcc9a4 upstream.
Wireless extensions have an unfortunate, undocumented requirement which requires drivers to always fill iwp->length when returning a successful status. When a driver doesn't do this, it leads to a kernel heap content leak when userspace offers a larger buffer than would have been necessary.
Arguably, this is a driver bug, as it should, if it returns 0, fill iwp->length, even if it separately indicated that the buffer contents was not valid.
However, we can also at least avoid the memory content leak if the driver doesn't do this by setting the iwp length to max_tokens, which then reflects how big the buffer is that the driver may fill, regardless of how big the userspace buffer is.
To illustrate the point, this patch also fixes a corresponding cfg80211 bug (since this requirement isn't documented nor was ever pointed out by anyone during code review, I don't trust all drivers nor all cfg80211 handlers to implement it correctly).
--- net/wireless/wext-compat.c | 3 +++ net/wireless/wext.c | 16 ++++++++++++++++ 2 files changed, 19 insertions(+)
net/wireless/wext-compat.c +3 -0
@@ -1358,6 +1358,9 @@ int cfg80211_wext_giwessid(struct net_de {struct wireless_dev *wdev = dev->ieee80211_ptr; + data->flags =0 ; + data->length =0 ; +switch (wdev->iftype) {case NL80211_IFTYPE_ADHOC :return cfg80211_ibss_wext_giwessid (dev, info, data, ssid);
net/wireless/wext.c +16 -0
@@ -854,6 +854,22 @@ static int ioctl_standard_iw_point(struc } } +if (IW_IS_GET (cmd) && !(descr->flags &IW_DESCR_FLAG_NOMAX )) { +/* +* If this is a GET, but not NOMAX, it means that the extra +* data is not bounded by userspace, but by max_tokens. Thus +* set the length to max_tokens. This matches the extra data +* allocation. +* The driver should fill it with the number of tokens it +* provided, and it may check iwp->length rather than having +* knowledge of max_tokens. If the driver doesn't change the +* iwp->length, this ioctl just copies back max_token tokens +* filled with zeroes. Hopefully the driver isn't claiming +* them to be valid data. +*/ + iwp->length = descr->max_tokens; + } + err =handler (dev, info, (union iwreq_data *) iwp, extra); iwp->length += essid_compat;
PATCH 60/123 x86, tsc: Fix a preemption leak in restore_sched_clock_state()
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit 55496c896b8a695140045099d4e0175cf09d4eae upstream.
Doh, a real life genuine preemption leak..
This caused a suspend failure.
Reported-bisected-and-tested-by-the-invaluable: Jeff Chua <[email protected]>
sleep states
LKML-Reference: <1284150773.402.122.camel@laptop>
--- arch/x86/kernel/tsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kernel/tsc.c +1 -1
@@ -655,7 +655,7 @@ void restore_sched_clock_state(void)local_irq_save (flags); -get_cpu_var (cyc2ns_offset) =0 ; +__get_cpu_var (cyc2ns_offset) =0 ; offset = cyc2ns_suspend -sched_clock ();for_each_possible_cpu (cpu)
PATCH 61/123 x86-64, compat: Test %rax for the syscall number, not %eax
In reply to Greg KHFrom: H. Peter Anvin <[email protected]>
commit 36d001c70d8a0144ac1d038f6876c484849a74de upstream.
On 64 bits, we always, by necessity, jump through the system call table via %rax. For 32-bit system calls, in theory the system call number is stored in %eax, and the code was testing %eax for a valid system call number. At one point we loaded the stored value back from the stack to enforce zero-extension, but that was removed in checkin d4d67150165df8bf1cc05e532f6efca96f907cab. An actual 32-bit process will not be able to introduce a non-zero-extended number, but it can happen via ptrace.
Instead of re-introducing the zero-extension, test what we are actually going to use, i.e. %rax. This only adds a handful of REX prefixes to the code.
--- arch/x86/ia32/ia32entry.S | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
arch/x86/ia32/ia32entry.S +7 -7
@@ -153,7 +153,7 @@ ENTRY(ia32_sysenter_target) testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) CFI_REMEMBER_STATE jnz sysenter_tracesys - cmpl $(IA32_NR_syscalls-1),%eax + cmpq $(IA32_NR_syscalls-1),%rax ja ia32_badsys sysenter_do_call: IA32_ARG_FIXUP
@@ -195,7 +195,7 @@ sysexit_from_sys_call: movl $AUDIT_ARCH_I386,%edi /* 1st arg: audit arch */ call audit_syscall_entry movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall number */ - cmpl $(IA32_NR_syscalls-1),%eax + cmpq $(IA32_NR_syscalls-1),%rax ja ia32_badsys movl %ebx,%edi /* reload 1st syscall arg */ movl RCX-ARGOFFSET(%rsp),%esi /* reload 2nd syscall arg */
@@ -248,7 +248,7 @@ sysenter_tracesys: call syscall_trace_enter LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ RESTORE_REST - cmpl $(IA32_NR_syscalls-1),%eax + cmpq $(IA32_NR_syscalls-1),%rax ja int_ret_from_sys_call /* sysenter_tracesys has set RAX(%rsp) */ jmp sysenter_do_call CFI_ENDPROC
@@ -314,7 +314,7 @@ ENTRY(ia32_cstar_target) testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) CFI_REMEMBER_STATE jnz cstar_tracesys - cmpl $IA32_NR_syscalls-1,%eax + cmpq $IA32_NR_syscalls-1,%rax ja ia32_badsys cstar_do_call: IA32_ARG_FIXUP 1
@@ -367,7 +367,7 @@ cstar_tracesys: LOAD_ARGS32 ARGOFFSET, 1 /* reload args from stack in case ptrace changed it */ RESTORE_REST xchgl %ebp,%r9d - cmpl $(IA32_NR_syscalls-1),%eax + cmpq $(IA32_NR_syscalls-1),%rax ja int_ret_from_sys_call /* cstar_tracesys has set RAX(%rsp) */ jmp cstar_do_call END(ia32_cstar_target)
@@ -425,7 +425,7 @@ ENTRY(ia32_syscall) orl $TS_COMPAT,TI_status(%r10) testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) jnz ia32_tracesys - cmpl $(IA32_NR_syscalls-1),%eax + cmpq $(IA32_NR_syscalls-1),%rax ja ia32_badsys ia32_do_call: IA32_ARG_FIXUP
@@ -444,7 +444,7 @@ ia32_tracesys: call syscall_trace_enter LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ RESTORE_REST - cmpl $(IA32_NR_syscalls-1),%eax + cmpq $(IA32_NR_syscalls-1),%rax ja int_ret_from_sys_call /* ia32_tracesys has set RAX(%rsp) */ jmp ia32_do_call END(ia32_syscall)
PATCH 62/123 compat: Make compat_alloc_user_space() incorporate the access_ok()
In reply to Greg KHFrom: H. Peter Anvin <[email protected]>
commit c41d68a513c71e35a14f66d71782d27a79a81ea6 upstream.
compat_alloc_user_space() expects the caller to independently call access_ok() to verify the returned area. A missing call could introduce problems on some architectures.
This patch incorporates the access_ok() check into compat_alloc_user_space() and also adds a sanity check on the length. The existing compat_alloc_user_space() implementations are renamed arch_compat_alloc_user_space() and are used as part of the implementation of the new global function.
This patch assumes NULL will cause __get_user()/__put_user() to either fail or access userspace on all architectures. This should be followed by checking the return value of compat_access_user_space() for NULL in the callers, at which time the access_ok() in the callers can also be removed.
--- arch/ia64/include/asm/compat.h | 2 +- arch/mips/include/asm/compat.h | 2 +- arch/parisc/include/asm/compat.h | 2 +- arch/powerpc/include/asm/compat.h | 2 +- arch/s390/include/asm/compat.h | 2 +- arch/sparc/include/asm/compat.h | 2 +- arch/x86/include/asm/compat.h | 2 +- include/linux/compat.h | 2 ++ kernel/compat.c | 22 ++++++++++++++++++++++ 9 files changed, 31 insertions(+), 7 deletions(-)
arch/ia64/include/asm/compat.h +1 -1
@@ -198,7 +198,7 @@ ptr_to_compat(void __user *uptr) }static __inline__void __user * -compat_alloc_user_space (long len) +arch_compat_alloc_user_space (long len) {struct pt_regs *regs =task_pt_regs (current);return (void __user *) (((regs->r12 &0xffffffff ) &-16 ) - len);
arch/mips/include/asm/compat.h +1 -1
@@ -144,7 +144,7 @@ static inline compat_uptr_t ptr_to_compareturn (u32 )(unsigned long )uptr; } -static inline void __user *compat_alloc_user_space (long len) +static inline void __user *arch_compat_alloc_user_space (long len) {struct pt_regs *regs = (struct pt_regs *) ((unsigned long )current_thread_info () +THREAD_SIZE -32 ) -1 ;
arch/parisc/include/asm/compat.h +1 -1
@@ -146,7 +146,7 @@ static inline compat_uptr_t ptr_to_compareturn (u32 )(unsigned long )uptr; } -static __inline__void __user *compat_alloc_user_space (long len) +static __inline__void __user *arch_compat_alloc_user_space (long len) {struct pt_regs *regs = ¤t->thread.regs;return (void __user *)regs->gr[30 ];
arch/powerpc/include/asm/compat.h +1 -1
@@ -133,7 +133,7 @@ static inline compat_uptr_t ptr_to_compareturn (u32 )(unsigned long )uptr; } -static inline void __user *compat_alloc_user_space (long len) +static inline void __user *arch_compat_alloc_user_space (long len) {struct pt_regs *regs = current->thread.regs;unsigned long usp = regs->gpr[1 ];
arch/s390/include/asm/compat.h +1 -1
@@ -180,7 +180,7 @@ static inline int is_compat_task(void)#endif -static inline void __user *compat_alloc_user_space (long len) +static inline void __user *arch_compat_alloc_user_space (long len) {unsigned long stack;
arch/sparc/include/asm/compat.h +1 -1
@@ -166,7 +166,7 @@ static inline compat_uptr_t ptr_to_compareturn (u32 )(unsigned long )uptr; } -static inline void __user *compat_alloc_user_space (long len) +static inline void __user *arch_compat_alloc_user_space (long len) {struct pt_regs *regs =current_thread_info ()->kregs;unsigned long usp = regs->u_regs[UREG_I6 ];
arch/x86/include/asm/compat.h +1 -1
@@ -204,7 +204,7 @@ static inline compat_uptr_t ptr_to_compareturn (u32 )(unsigned long )uptr; } -static inline void __user *compat_alloc_user_space (long len) +static inline void __user *arch_compat_alloc_user_space (long len) {struct pt_regs *regs =task_pt_regs (current);return (void __user *)regs->sp - len;
include/linux/compat.h +2 -0
@@ -309,5 +309,7 @@ asmlinkage long compat_sys_newfstatat(unasmlinkage long compat_sys_openat (unsigned int dfd,const char __user *filename,int flags,int mode); +extern void __user *compat_alloc_user_space (unsigned long len); +#endif /* CONFIG_COMPAT */ #endif /* _LINUX_COMPAT_H */
kernel/compat.c +22 -0
@@ -25,6 +25,7 @@#include <linux/posix-timers.h> #include <linux/times.h> #include <linux/ptrace.h> +#include <linux/module.h> #include <asm/uaccess.h>
@@ -1136,3 +1137,24 @@ compat_sys_sysinfo(struct compat_sysinforeturn 0 ; } + +/* +* Allocate user-space memory for the duration of a single system call, +* in order to marshall parameters inside a compat thunk. +*/ +void __user *compat_alloc_user_space (unsigned long len) +{ +void __user *ptr; + +/* If len would occupy more than half of the entire compat space... */ +if (unlikely (len > (((compat_uptr_t )~0 ) >>1 ))) +return NULL ; + + ptr =arch_compat_alloc_user_space (len); + +if (unlikely (!access_ok (VERIFY_WRITE , ptr, len))) +return NULL ; + +return ptr; +} +EXPORT_SYMBOL_GPL (compat_alloc_user_space);
PATCH 63/123 x86-64, compat: Retruncate rax after ia32 syscall entry tracing
In reply to Greg KHFrom: Roland McGrath <[email protected]>
commit eefdca043e8391dcd719711716492063030b55ac upstream.
In commit d4d6715, we reopened an old hole for a 64-bit ptracer touching a 32-bit tracee in system call entry. A %rax value set via ptrace at the entry tracing stop gets used whole as a 32-bit syscall number, while we only check the low 32 bits for validity.
Fix it by truncating %rax back to 32 bits after syscall_trace_enter, in addition to testing the full 64 bits as has already been added.
--- arch/x86/ia32/ia32entry.S | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
arch/x86/ia32/ia32entry.S +7 -1
@@ -50,7 +50,12 @@ /* * Reload arg registers from stack in case ptrace changed them. * We don't reload %eax because syscall_trace_enter() returned - * the value it wants us to use in the table lookup. + * the %rax value we should see. Instead, we just truncate that + * value to 32 bits again as we did on entry from user mode. + * If it's a new value set by user_regset during entry tracing, + * this matches the normal truncation of the user-mode value. + * If it's -1 to make us punt the syscall, then (u32)-1 is still + * an appropriately invalid value. */ .macro LOAD_ARGS32 offset, _r9=0 .if \_r9
@@ -60,6 +65,7 @@ movl \offset+48(%rsp),%edx movl \offset+56(%rsp),%esi movl \offset+64(%rsp),%edi + movl %eax,%eax /* zero extension */ .endm .macro CFI_STARTPROC32 simple
PATCH 64/123 sched: Protect task->cpus_allowed access in sched_getaffinity()
In reply to Greg KHFrom: Thomas Gleixner <[email protected]>
commit 3160568371da441b7f2fb57f2f1225404207e8f2 upstream
sched_getaffinity() is not protected against a concurrent modification of the tasks affinity.
Serialize the access with task_rq_lock(task).
LKML-Reference: <[email protected]>
--- kernel/sched.c | 4 ++++ 1 file changed, 4 insertions(+)
kernel/sched.c +4 -0
@@ -6686,6 +6686,8 @@ SYSCALL_DEFINE3(sched_setaffinity, pid_tlong sched_getaffinity (pid_t pid,struct cpumask *mask) {struct task_struct *p; +unsigned long flags; +struct rq *rq;int retval;get_online_cpus ();
@@ -6700,7 +6702,9 @@ long sched_getaffinity(pid_t pid, structif (retval) goto out_unlock; + rq =task_rq_lock (p, &flags);cpumask_and (mask, &p->cpus_allowed, cpu_online_mask); +task_rq_unlock (rq, &flags); out_unlock:read_unlock (&tasklist_lock);
Re: [Stable-review] [064/123] sched: Protect task->cpus_allowed access in sched_getaffinity()
I'm somewhat disturbed by the number of non-trivial scheduler changes here. How well have these been tested as applied to the 2.6.32.y branch?
Ben.
Signature · 2 lines
Ben Hutchings Once a job is fouled up, anything done to improve it makes it worse.
Re: [Stable-review] [064/123] sched: Protect task->cpus_allowed access in sched_getaffinity()
Quoted 3 lines · Ben Hutchings
I'm somewhat disturbed by the number of non-trivial scheduler changes here. How well have these been tested as applied to the 2.6.32.y branch?
Mike has tested these very well and gotten the ACK for them to go in from Ingo and Peter.
I think they are also currently shipping in one distro's enterprise kernel as well, but am not quite sure...
Ben, feel free to test them yourself and report any problems, but at the least, they do fix one reported problem, and lots of others as well.
thanks,
greg k-h
Re: [Stable-review] [064/123] sched: Protect task->cpus_allowed access in sched_getaffinity()
In reply to Ben HutchingsQuoted 3 lines · Ben Hutchings
I'm somewhat disturbed by the number of non-trivial scheduler changes here. How well have these been tested as applied to the 2.6.32.y branch?
All of them of course.
-Mike
Re: [Stable-review] [064/123] sched: Protect task->cpus_allowed access in sched_getaffinity()
Quoted 6 lines · Mike Galbraith
Quoted 3 lines · Ben Hutchings
I'm somewhat disturbed by the number of non-trivial scheduler changes here. How well have these been tested as applied to the 2.6.32.y branch?
All of them of course.
(parse error)
The patch set saw a lot of stress and benchmark hours on boxen large and small, to be as sure as anyone can be that it was not going to upset the enterprise apple cart, nor harm the desktop.
I call it heavily tested, but can't post a detailed log of everything done on every box for others to decide for themselves, since I didn't compile same.
-Mike
PATCH 65/123 sched: Protect sched_rr_get_param() access to task->sched_class
In reply to Greg KHFrom: Thomas Gleixner <[email protected]>
commit dba091b9e3522b9d32fc9975e48d3b69633b45f0 upstream
sched_rr_get_param calls task->sched_class->get_rr_interval(task) without protection against a concurrent sched_setscheduler() call which modifies task->sched_class.
Serialize the access with task_rq_lock(task) and hand the rq pointer into get_rr_interval() as it's needed at least in the sched_fair implementation.
LKML-Reference: <[email protected]>
--- include/linux/sched.h | 3 ++- kernel/sched.c | 6 +++++- kernel/sched_fair.c | 6 +----- kernel/sched_idletask.c | 2 +- kernel/sched_rt.c | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-)
include/linux/sched.h +2 -1
@@ -1114,7 +1114,8 @@ struct sched_class {void (*prio_changed) (struct rq *this_rq,struct task_struct *task,int oldprio,int running); -unsigned int (*get_rr_interval) (struct task_struct *task); +unsigned int (*get_rr_interval) (struct rq *rq, +struct task_struct *task);#ifdef CONFIG_FAIR_GROUP_SCHED void (*moved_group) (struct task_struct *p);
kernel/sched.c +5 -1
@@ -6946,6 +6946,8 @@ SYSCALL_DEFINE2(sched_rr_get_interval, p {struct task_struct *p;unsigned int time_slice; +unsigned long flags; +struct rq *rq;int retval;struct timespec t;
@@ -6962,7 +6964,9 @@ SYSCALL_DEFINE2(sched_rr_get_interval, pif (retval) goto out_unlock; - time_slice = p->sched_class->get_rr_interval (p); + rq =task_rq_lock (p, &flags); + time_slice = p->sched_class->get_rr_interval (rq, p); +task_rq_unlock (rq, &flags);read_unlock (&tasklist_lock);jiffies_to_timespec (time_slice, &t);
kernel/sched_fair.c +1 -5
@@ -2003,21 +2003,17 @@ static void moved_group_fair(struct task }#endif -unsigned int get_rr_interval_fair (struct task_struct *task) +unsigned int get_rr_interval_fair (struct rq *rq,struct task_struct *task) {struct sched_entity *se = &task->se; -unsigned long flags; -struct rq *rq;unsigned int rr_interval =0 ;/* * Time slice is 0 for SCHED_OTHER tasks that are on an otherwise * idle runqueue: */ - rq =task_rq_lock (task, &flags);if (rq->cfs.load.weight) rr_interval =NS_TO_JIFFIES (sched_slice (&rq->cfs, se)); -task_rq_unlock (rq, &flags);return rr_interval; }
kernel/sched_idletask.c +1 -1
@@ -97,7 +97,7 @@ static void prio_changed_idle(struct rqcheck_preempt_curr (rq, p,0 ); } -unsigned int get_rr_interval_idle (struct task_struct *task) +unsigned int get_rr_interval_idle (struct rq *rq,struct task_struct *task) {return 0 ; }
kernel/sched_rt.c +1 -1
@@ -1734,7 +1734,7 @@ static void set_curr_task_rt(struct rq *dequeue_pushable_task (rq, p); } -unsigned int get_rr_interval_rt (struct task_struct *task) +unsigned int get_rr_interval_rt (struct rq *rq,struct task_struct *task) {/* * Time slice is 0 for SCHED_FIFO tasks
PATCH 66/123 sched: Consolidate select_task_rq() callers
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit 970b13bacba14a8cef6f642861947df1d175b0b3 upstream
sched: Consolidate select_task_rq() callers
Small cleanup.
LKML-Reference: <new-submission>
--- kernel/sched.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
kernel/sched.c +11 -3
@@ -2333,6 +2333,14 @@ void task_oncpu_function_call(struct taspreempt_enable (); } +#ifdef CONFIG_SMP +static inline +int select_task_rq (struct task_struct *p,int sd_flags,int wake_flags) +{ +return p->sched_class->select_task_rq (p, sd_flags, wake_flags); +} +#endif +/*** * try_to_wake_up - wake up a thread * @p: the to-be-woken-up thread
@@ -2386,7 +2394,7 @@ static int try_to_wake_up(struct task_st p->state =TASK_WAKING ;task_rq_unlock (rq, &flags); - cpu = p->sched_class->select_task_rq (p,SD_BALANCE_WAKE , wake_flags); + cpu =select_task_rq (p,SD_BALANCE_WAKE , wake_flags);if (cpu != orig_cpu)set_task_cpu (p, cpu);
@@ -2601,7 +2609,7 @@ void sched_fork(struct task_struct *p, i p->sched_class = &fair_sched_class;#ifdef CONFIG_SMP - cpu = p->sched_class->select_task_rq (p,SD_BALANCE_FORK ,0 ); + cpu =select_task_rq (p,SD_BALANCE_FORK ,0 );#endif set_task_cpu (p, cpu);
@@ -3170,7 +3178,7 @@ out:void sched_exec (void ) {int new_cpu, this_cpu =get_cpu (); - new_cpu = current->sched_class->select_task_rq (current,SD_BALANCE_EXEC ,0 ); + new_cpu =select_task_rq (current,SD_BALANCE_EXEC ,0 );put_cpu ();if (new_cpu != this_cpu)sched_migrate_task (current, new_cpu);
PATCH 67/123 sched: Remove unused cpu_nr_migrations()
In reply to Greg KHFrom: Hiroshi Shimamoto <[email protected]>
commit 9824a2b728b63e7ff586b9fd9293c819be79f0f3 upstream
cpu_nr_migrations() is not used, remove it.
LKML-Reference: <[email protected]>
--- include/linux/sched.h | 1 - kernel/sched.c | 11 ----------- 2 files changed, 12 deletions(-)
include/linux/sched.h +0 -1
@@ -145,7 +145,6 @@ extern unsigned long this_cpu_load(void)extern void calc_global_load (void ); -extern u64 cpu_nr_migrations (int cpu);extern unsigned long get_parent_ip (unsigned long addr);
kernel/sched.c +0 -11
@@ -542,7 +542,6 @@ struct rq {struct load_weight load;unsigned long nr_load_updates;u64 nr_switches; -u64 nr_migrations_in;struct cfs_rq cfs;struct rt_rq rt;
@@ -2089,7 +2088,6 @@ void set_task_cpu(struct task_struct *p,#endif if (old_cpu != new_cpu) { p->se.nr_migrations++; - new_rq->nr_migrations_in++;#ifdef CONFIG_SCHEDSTATS if (task_hot (p, old_rq->clock,NULL ))schedstat_inc (p, se.nr_forced2_migrations);
@@ -3048,15 +3046,6 @@ static void calc_load_account_active(str }/* -* Externally visible per-cpu scheduler statistics: -* cpu_nr_migrations(cpu) - number of migrations into that cpu -*/ -u64 cpu_nr_migrations (int cpu) -{ -return cpu_rq (cpu)->nr_migrations_in; -} - -/* * Update rq->cpu_load[] statistics. This function is usually called every * scheduler tick (TICK_NSEC). */
PATCH 68/123 sched: Remove rq->clock coupling from set_task_cpu()
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit 5afcdab706d6002cb02b567ba46e650215e694e8 upstream
set_task_cpu() should be rq invariant and only touch task state, it currently fails to do so, which opens up a few races, since not all callers hold both rq->locks.
Remove the relyance on rq->clock, as any site calling set_task_cpu() should also do a remote clock update, which should ensure the observed time between these two cpus is monotonic, as per kernel/sched_clock.c:sched_clock_remote().
Therefore we can simply remove the clock_offset bits and be happy.
LKML-Reference: <new-submission>
--- kernel/sched.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-)
kernel/sched.c +1 -12
@@ -2069,23 +2069,12 @@ task_hot(struct task_struct *p, u64 now,void set_task_cpu (struct task_struct *p,unsigned int new_cpu) {int old_cpu =task_cpu (p); -struct rq *old_rq =cpu_rq (old_cpu), *new_rq =cpu_rq (new_cpu); +struct rq *old_rq =cpu_rq (old_cpu);struct cfs_rq *old_cfsrq =task_cfs_rq (p), *new_cfsrq =cpu_cfs_rq (old_cfsrq, new_cpu); -u64 clock_offset; - - clock_offset = old_rq->clock - new_rq->clock;trace_sched_migrate_task (p, new_cpu); -#ifdef CONFIG_SCHEDSTATS -if (p->se.wait_start) - p->se.wait_start -= clock_offset; -if (p->se.sleep_start) - p->se.sleep_start -= clock_offset; -if (p->se.block_start) - p->se.block_start -= clock_offset; -#endif if (old_cpu != new_cpu) { p->se.nr_migrations++;#ifdef CONFIG_SCHEDSTATS
PATCH 69/123 sched: Clean up ttwu() rq locking
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit ab19cb23313733c55e0517607844b86720b35f5f upstream
Since set_task_clock() doesn't rely on rq->clock anymore we can simplyfy the mess in ttwu().
Optimize things a bit by not fiddling with the IRQ state there.
LKML-Reference: <new-submission>
--- kernel/sched.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
kernel/sched.c +3 -5
@@ -2379,16 +2379,14 @@ static int try_to_wake_up(struct task_stif (task_contributes_to_load (p)) rq->nr_uninterruptible--; p->state =TASK_WAKING ; -task_rq_unlock (rq, &flags); +__task_rq_unlock (rq); cpu =select_task_rq (p,SD_BALANCE_WAKE , wake_flags);if (cpu != orig_cpu)set_task_cpu (p, cpu); - rq =task_rq_lock (p, &flags); - -if (rq != orig_rq) -update_rq_clock (rq); + rq =__task_rq_lock (p); +update_rq_clock (rq);WARN_ON (p->state !=TASK_WAKING ); cpu =task_cpu (p);
PATCH 70/123 sched: Sanitize fork() handling
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit cd29fe6f2637cc2ccbda5ac65f5332d6bf5fa3c6 upstream
Currently we try to do task placement in wake_up_new_task() after we do the load-balance pass in sched_fork(). This yields complicated semantics in that we have to deal with tasks on different RQs and the set_task_cpu() calls in copy_process() and sched_fork()
Rename ->task_new() to ->task_fork() and call it from sched_fork() before the balancing, this gives the policy a clear point to place the task.
LKML-Reference: <new-submission>
--- include/linux/sched.h | 2 +- kernel/sched.c | 43 ++++++++++++++++++------------------------- kernel/sched_fair.c | 28 +++++++++++++++------------- 3 files changed, 34 insertions(+), 39 deletions(-)
include/linux/sched.h +1 -1
@@ -1104,7 +1104,7 @@ struct sched_class {void (*set_curr_task) (struct rq *rq);void (*task_tick) (struct rq *rq,struct task_struct *p,int queued); -void (*task_new) (struct rq *rq,struct task_struct *p); +void (*task_fork) (struct task_struct *p);void (*switched_from) (struct rq *this_rq,struct task_struct *task,int running);
kernel/sched.c +18 -25
67 lines not on this page · raw message
kernel/sched_fair.c +15 -13
@@ -1911,28 +1911,30 @@ static void task_tick_fair(struct rq *rq }/* -* Share the fairness runtime between parent and child, thus the -* total amount of pressure for CPU stays equal - new tasks -* get a chance to run but frequent forkers are not allowed to -* monopolize the CPU. Note: the parent runqueue is locked, -* the child is not running yet. +* called on fork with the child task as argument from the parent's context +* - child not yet on the tasklist +* - preemption disabled */ -static void task_new_fair (struct rq *rq,struct task_struct *p) +static void task_fork_fair (struct task_struct *p) { -struct cfs_rq *cfs_rq =task_cfs_rq (p); +struct cfs_rq *cfs_rq =task_cfs_rq (current);struct sched_entity *se = &p->se, *curr = cfs_rq->curr;int this_cpu =smp_processor_id (); +struct rq *rq =this_rq (); +unsigned long flags; + +spin_lock_irqsave (&rq->lock, flags); -sched_info_queued (p); +if (unlikely (task_cpu (p) != this_cpu)) +__set_task_cpu (p, this_cpu);update_curr (cfs_rq); +if (curr) se->vruntime = curr->vruntime;place_entity (cfs_rq, se,1 ); -/* 'curr' will be NULL if the child belongs to a different group */ -if (sysctl_sched_child_runs_first && this_cpu ==task_cpu (p) && - curr &&entity_before (curr, se)) { +if (sysctl_sched_child_runs_first && curr &&entity_before (curr, se)) {/* * Upon rescheduling, sched_class::put_prev_task() will place * 'current' within the tree based on its new key value.
@@ -1941,7 +1943,7 @@ static void task_new_fair(struct rq *rq,resched_task (rq->curr); } -enqueue_task_fair (rq, p,0 ); +spin_unlock_irqrestore (&rq->lock, flags); }/*
@@ -2043,7 +2045,7 @@ static const struct sched_class fair_sch .set_curr_task = set_curr_task_fair, .task_tick = task_tick_fair, - .task_new = task_new_fair, + .task_fork = task_fork_fair, .prio_changed = prio_changed_fair, .switched_to = switched_to_fair,
PATCH 71/123 sched: Remove forced2_migrations stats
In reply to Greg KHFrom: Ingo Molnar <[email protected]>
commit b9889ed1ddeca5a3f3569c8de7354e9e97d803ae upstream
This build warning:
kernel/sched.c: In function 'set_task_cpu':
kernel/sched.c:2070: warning: unused variable 'old_rq'
Made me realize that the forced2_migrations stat looks pretty pointless (and a misnomer) - remove it.
Cc: Peter Zijlstra <[email protected]>
Cc: Mike Galbraith <[email protected]>
LKML-Reference: <new-submission>
--- include/linux/sched.h | 1 - kernel/sched.c | 6 ------ kernel/sched_debug.c | 2 -- 3 files changed, 9 deletions(-)
include/linux/sched.h +0 -1
@@ -1178,7 +1178,6 @@ struct sched_entity {u64 nr_failed_migrations_running;u64 nr_failed_migrations_hot;u64 nr_forced_migrations; -u64 nr_forced2_migrations;u64 nr_wakeups;u64 nr_wakeups_sync;
kernel/sched.c +0 -6
@@ -2069,7 +2069,6 @@ task_hot(struct task_struct *p, u64 now,void set_task_cpu (struct task_struct *p,unsigned int new_cpu) {int old_cpu =task_cpu (p); -struct rq *old_rq =cpu_rq (old_cpu);struct cfs_rq *old_cfsrq =task_cfs_rq (p), *new_cfsrq =cpu_cfs_rq (old_cfsrq, new_cpu);
@@ -2077,10 +2076,6 @@ void set_task_cpu(struct task_struct *p,if (old_cpu != new_cpu) { p->se.nr_migrations++; -#ifdef CONFIG_SCHEDSTATS -if (task_hot (p, old_rq->clock,NULL )) -schedstat_inc (p, se.nr_forced2_migrations); -#endif perf_sw_event (PERF_COUNT_SW_CPU_MIGRATIONS ,1 ,1 ,NULL ,0 ); }
@@ -2523,7 +2518,6 @@ static void __sched_fork(struct task_str p->se.nr_failed_migrations_running =0 ; p->se.nr_failed_migrations_hot =0 ; p->se.nr_forced_migrations =0 ; - p->se.nr_forced2_migrations =0 ; p->se.nr_wakeups =0 ; p->se.nr_wakeups_sync =0 ;
kernel/sched_debug.c +0 -2
@@ -423,7 +423,6 @@ void proc_sched_show_task(struct task_stP (se.nr_failed_migrations_running);P (se.nr_failed_migrations_hot);P (se.nr_forced_migrations); -P (se.nr_forced2_migrations);P (se.nr_wakeups);P (se.nr_wakeups_sync);P (se.nr_wakeups_migrate);
@@ -499,7 +498,6 @@ void proc_sched_set_task(struct task_str p->se.nr_failed_migrations_running =0 ; p->se.nr_failed_migrations_hot =0 ; p->se.nr_forced_migrations =0 ; - p->se.nr_forced2_migrations =0 ; p->se.nr_wakeups =0 ; p->se.nr_wakeups_sync =0 ; p->se.nr_wakeups_migrate =0 ;
PATCH 72/123 sched: Make wakeup side and atomic variants of completion API irq safe
In reply to Greg KHFrom: Rafael J.Wysocki <[email protected]>
commit 7539a3b3d1f892dd97eaf094134d7de55c13befe upstream
Alan Stern noticed that all the wakeup side (and atomic) variants of the completion APIs should be irq safe, but the newly introduced completion_done() and try_wait_for_completion() aren't. The use of the irq unsafe variants in IRQ contexts can cause crashes/hangs.
Fix the problem by making them use spin_lock_irqsave() and spin_lock_irqrestore().
LKML-Reference: <[email protected]>
--- kernel/sched.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
kernel/sched.c +6 -4
@@ -5947,14 +5947,15 @@ EXPORT_SYMBOL(wait_for_completion_killab*/ bool try_wait_for_completion (struct completion *x) { +unsigned long flags;int ret =1 ; -spin_lock_irq (&x->wait.lock); +spin_lock_irqsave (&x->wait.lock, flags);if (!x->done) ret =0 ;else x->done--; -spin_unlock_irq (&x->wait.lock); +spin_unlock_irqrestore (&x->wait.lock, flags);return ret; }EXPORT_SYMBOL (try_wait_for_completion);
@@ -5969,12 +5970,13 @@ EXPORT_SYMBOL(try_wait_for_completion);*/ bool completion_done (struct completion *x) { +unsigned long flags;int ret =1 ; -spin_lock_irq (&x->wait.lock); +spin_lock_irqsave (&x->wait.lock, flags);if (!x->done) ret =0 ; -spin_unlock_irq (&x->wait.lock); +spin_unlock_irqrestore (&x->wait.lock, flags);return ret; }EXPORT_SYMBOL (completion_done);
PATCH 73/123 sched: Use rcu in sys_sched_getscheduler/sys_sched_getparam()
In reply to Greg KHFrom: Thomas Gleixner <[email protected]>
commit 5fe85be081edf0ac92d83f9c39e0ab5c1371eb82 upstream
read_lock(&tasklist_lock) does not protect sys_sched_getscheduler and sys_sched_getparam() against a concurrent update of the policy or scheduler parameters as do_sched_setscheduler() does not take the tasklist_lock. The accessed integers can be retrieved w/o locking and are snapshots anyway.
Using rcu_read_lock() to protect find_task_by_vpid() and prevent the task struct from going away is not changing the above situation.
LKML-Reference: <[email protected]>
--- kernel/sched.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
kernel/sched.c +5 -5
@@ -6505,7 +6505,7 @@ SYSCALL_DEFINE1(sched_getscheduler, pid_return -EINVAL ; retval = -ESRCH ; -read_lock (&tasklist_lock); +rcu_read_lock (); p =find_process_by_pid (pid);if (p) { retval =security_task_getscheduler (p);
@@ -6513,7 +6513,7 @@ SYSCALL_DEFINE1(sched_getscheduler, pid_ retval = p->policy | (p->sched_reset_on_fork ?SCHED_RESET_ON_FORK :0 ); } -read_unlock (&tasklist_lock); +rcu_read_unlock ();return retval; }
@@ -6531,7 +6531,7 @@ SYSCALL_DEFINE2(sched_getparam, pid_t, pif (!param || pid <0 )return -EINVAL ; -read_lock (&tasklist_lock); +rcu_read_lock (); p =find_process_by_pid (pid); retval = -ESRCH ;if (!p)
@@ -6542,7 +6542,7 @@ SYSCALL_DEFINE2(sched_getparam, pid_t, p goto out_unlock; lp.sched_priority = p->rt_priority; -read_unlock (&tasklist_lock); +rcu_read_unlock ();/* * This one might sleep, we cannot do it with a spinlock held ...
@@ -6552,7 +6552,7 @@ SYSCALL_DEFINE2(sched_getparam, pid_t, preturn retval; out_unlock: -read_unlock (&tasklist_lock); +rcu_read_unlock ();return retval; }
PATCH 74/123 sched: Use rcu in sched_get/set_affinity()
In reply to Greg KHFrom: Thomas Gleixner <[email protected]>
commit 23f5d142519621b16cf2b378cf8adf4dcf01a616 upstream
tasklist_lock is held read locked to protect the find_task_by_vpid() call and to prevent the task going away. sched_setaffinity acquires a task struct ref and drops tasklist lock right away. The access to the cpus_allowed mask is protected by rq->lock.
rcu_read_lock() provides the same protection here.
LKML-Reference: <[email protected]>
--- kernel/sched.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-)
kernel/sched.c +6 -10
@@ -6563,22 +6563,18 @@ long sched_setaffinity(pid_t pid, constint retval;get_online_cpus (); -read_lock (&tasklist_lock); +rcu_read_lock (); p =find_process_by_pid (pid);if (!p) { -read_unlock (&tasklist_lock); +rcu_read_unlock ();put_online_cpus ();return -ESRCH ; } -/* -* It is not safe to call set_cpus_allowed with the -* tasklist_lock held. We will bump the task_struct's -* usage count and then drop tasklist_lock. -*/ +/* Prevent p going away */ get_task_struct (p); -read_unlock (&tasklist_lock); +rcu_read_unlock ();if (!alloc_cpumask_var (&cpus_allowed,GFP_KERNEL )) { retval = -ENOMEM ;
@@ -6664,7 +6660,7 @@ long sched_getaffinity(pid_t pid, structint retval;get_online_cpus (); -read_lock (&tasklist_lock); +rcu_read_lock (); retval = -ESRCH ; p =find_process_by_pid (pid);
@@ -6680,7 +6676,7 @@ long sched_getaffinity(pid_t pid, structtask_rq_unlock (rq, &flags); out_unlock: -read_unlock (&tasklist_lock); +rcu_read_unlock ();put_online_cpus ();return retval;
PATCH 75/123 sched: Use rcu in sched_get_rr_param()
In reply to Greg KHFrom: Thomas Gleixner <[email protected]>
commit 1a551ae715825bb2a2107a2dd68de024a1fa4e32 upstream
read_lock(&tasklist_lock) does not protect sys_sched_get_rr_param() against a concurrent update of the policy or scheduler parameters as do_sched_scheduler() does not take the tasklist_lock.
The access to task->sched_class->get_rr_interval is protected by task_rq_lock(task).
Use rcu_read_lock() to protect find_task_by_vpid() and prevent the task struct from going away.
LKML-Reference: <[email protected]>
--- kernel/sched.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
kernel/sched.c +3 -3
@@ -6924,7 +6924,7 @@ SYSCALL_DEFINE2(sched_rr_get_interval, preturn -EINVAL ; retval = -ESRCH ; -read_lock (&tasklist_lock); +rcu_read_lock (); p =find_process_by_pid (pid);if (!p) goto out_unlock;
@@ -6937,13 +6937,13 @@ SYSCALL_DEFINE2(sched_rr_get_interval, p time_slice = p->sched_class->get_rr_interval (rq, p);task_rq_unlock (rq, &flags); -read_unlock (&tasklist_lock); +rcu_read_unlock ();jiffies_to_timespec (time_slice, &t); retval =copy_to_user (interval, &t,sizeof (t)) ? -EFAULT :0 ;return retval; out_unlock: -read_unlock (&tasklist_lock); +rcu_read_unlock ();return retval; }
PATCH 76/123 sched: Fix set_cpu_active() in cpu_down()
In reply to Greg KHFrom: Xiaotian Feng <[email protected]>
commit 9ee349ad6d326df3633d43f54202427295999c47 upstream
Sachin found cpu hotplug test failures on powerpc, which made the kernel hang on his POWER box.
The problem is that we fail to re-activate a cpu when a hot-unplug fails. Fix this by moving the de-activation into _cpu_down after doing the initial checks.
Remove the synchronize_sched() calls and rely on those implied by rebuilding the sched domains using the new mask.
LKML-Reference: <[email protected]>
--- kernel/cpu.c | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-)
kernel/cpu.c +3 -21
@@ -209,6 +209,7 @@ static int __ref _cpu_down(unsigned intreturn -ENOMEM ;cpu_hotplug_begin (); +set_cpu_active (cpu, false); err =__raw_notifier_call_chain (&cpu_chain,CPU_DOWN_PREPARE | mod, hcpu,-1 , &nr_calls);if (err ==NOTIFY_BAD ) {
@@ -280,18 +281,6 @@ int __ref cpu_down(unsigned int cpu) goto out; } -set_cpu_active (cpu, false); - -/* -* Make sure the all cpus did the reschedule and are not -* using stale version of the cpu_active_mask. -* This is not strictly necessary becuase stop_machine() -* that we run down the line already provides the required -* synchronization. But it's really a side effect and we do not -* want to depend on the innards of the stop_machine here. -*/ -synchronize_sched (); - err =_cpu_down (cpu,0 ); out:
@@ -382,19 +371,12 @@ int disable_nonboot_cpus(void)return error;cpu_maps_update_begin (); first_cpu =cpumask_first (cpu_online_mask); -/* We take down all of the non-boot CPUs in one shot to avoid races +/* +* We take down all of the non-boot CPUs in one shot to avoid races * with the userspace trying to use the CPU hotplug at the same time */ cpumask_clear (frozen_cpus); -for_each_online_cpu (cpu) { -if (cpu == first_cpu) -continue ; -set_cpu_active (cpu, false); - } - -synchronize_sched (); -printk ("Disabling non-boot CPUs ...\n" );for_each_online_cpu (cpu) {if (cpu == first_cpu)
PATCH 77/123 sched: Use TASK_WAKING for fork wakups
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit 06b83b5fbea273672822b6ee93e16781046553ec upstream
For later convenience use TASK_WAKING for fresh tasks.
LKML-Reference: <[email protected]>
--- kernel/sched.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
kernel/sched.c +9 -9
@@ -2538,14 +2538,6 @@ static void __sched_fork(struct task_str#ifdef CONFIG_PREEMPT_NOTIFIERS INIT_HLIST_HEAD (&p->preempt_notifiers);#endif - -/* -* We mark the process as running here, but have not actually -* inserted it onto the runqueue yet. This guarantees that -* nobody will actually run it, and a signal or other external -* event cannot wake it up and insert it on the runqueue either. -*/ - p->state =TASK_RUNNING ; }/*
@@ -2556,6 +2548,12 @@ void sched_fork(struct task_struct *p, iint cpu =get_cpu ();__sched_fork (p); +/* +* We mark the process as waking here. This guarantees that +* nobody will actually run it, and a signal or other external +* event cannot wake it up and insert it on the runqueue either. +*/ + p->state =TASK_WAKING ;/* * Revert to default priority/policy on fork if requested.
@@ -2624,7 +2622,8 @@ void wake_up_new_task(struct task_structstruct rq *rq; rq =task_rq_lock (p, &flags); -BUG_ON (p->state !=TASK_RUNNING ); +BUG_ON (p->state !=TASK_WAKING ); + p->state =TASK_RUNNING ;update_rq_clock (rq);activate_task (rq, p,0 );trace_sched_wakeup_new (rq, p,1 );
@@ -7034,6 +7033,7 @@ void __cpuinit init_idle(struct task_strspin_lock_irqsave (&rq->lock, flags);__sched_fork (idle); + idle->state =TASK_RUNNING ; idle->se.exec_start =sched_clock ();cpumask_copy (&idle->cpus_allowed,cpumask_of (cpu));
PATCH 78/123 sched: Ensure set_task_cpu() is never called on blocked tasks
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit e2912009fb7b715728311b0d8fe327a1432b3f79 upstream
In order to clean up the set_task_cpu() rq dependencies we need to ensure it is never called on blocked tasks because such usage does not pair with consistent rq->lock usage.
This puts the migration burden on ttwu().
Furthermore we need to close a race against changing ->cpus_allowed, since select_task_rq() runs with only preemption disabled.
For sched_fork() this is safe because the child isn't in the tasklist yet, for wakeup we fix this by synchronizing set_cpus_allowed_ptr() against TASK_WAKING, which leaves sched_exec to be a problem
This also closes a hole in (6ad4c1888 sched: Fix balance vs hotplug race) where ->select_task_rq() doesn't validate the result against the sched_domain/root_domain.
LKML-Reference: <[email protected]>
--- kernel/sched.c | 83 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 17 deletions(-)
kernel/sched.c +66 -17
@@ -2017,21 +2017,15 @@ static inline void check_class_changed(s*/ void kthread_bind (struct task_struct *p,unsigned int cpu) { -struct rq *rq =cpu_rq (cpu); -unsigned long flags; -/* Must have done schedule() in kthread() before we set_task_cpu */ if (!wait_task_inactive (p,TASK_UNINTERRUPTIBLE )) {WARN_ON (1 );return ; } -spin_lock_irqsave (&rq->lock, flags); -set_task_cpu (p, cpu); p->cpus_allowed =cpumask_of_cpu (cpu); p->rt.nr_cpus_allowed =1 ; p->flags |=PF_THREAD_BOUND ; -spin_unlock_irqrestore (&rq->lock, flags); }EXPORT_SYMBOL (kthread_bind);
@@ -2072,6 +2066,14 @@ void set_task_cpu(struct task_struct *p,struct cfs_rq *old_cfsrq =task_cfs_rq (p), *new_cfsrq =cpu_cfs_rq (old_cfsrq, new_cpu); +#ifdef CONFIG_SCHED_DEBUG +/* +* We should never call set_task_cpu() on a blocked task, +* ttwu() will sort out the placement. +*/ +WARN_ON (p->state !=TASK_RUNNING && p->state !=TASK_WAKING ); +#endif +trace_sched_migrate_task (p, new_cpu);if (old_cpu != new_cpu) {
@@ -2105,12 +2107,10 @@ migrate_task(struct task_struct *p, int/* * If the task is not on a runqueue (and not running), then -* it is sufficient to simply update the task's cpu field. +* the next wake-up will properly place the task. */ -if (!p->se.on_rq && !task_running (rq, p)) { -set_task_cpu (p, dest_cpu); +if (!p->se.on_rq && !task_running (rq, p))return 0 ; - }init_completion (&req->done); req->task = p;
@@ -2316,10 +2316,42 @@ void task_oncpu_function_call(struct tas }#ifdef CONFIG_SMP +/* +* Called from: +* +* - fork, @p is stable because it isn't on the tasklist yet +* +* - exec, @p is unstable XXX +* +* - wake-up, we serialize ->cpus_allowed against TASK_WAKING so +* we should be good. +*/ static inline int select_task_rq (struct task_struct *p,int sd_flags,int wake_flags) { -return p->sched_class->select_task_rq (p, sd_flags, wake_flags); +int cpu = p->sched_class->select_task_rq (p, sd_flags, wake_flags); + +/* +* In order not to call set_task_cpu() on a blocking task we need +* to rely on ttwu() to place the task on a valid ->cpus_allowed +* cpu. +* +* Since this is common to all placement strategies, this lives here. +* +* [ this allows ->select_task() to simply return task_cpu(p) and +* not worry about this generic constraint ] +*/ +if (unlikely (!cpumask_test_cpu (cpu, &p->cpus_allowed) || + !cpu_active (cpu))) { + + cpu =cpumask_any_and (&p->cpus_allowed, cpu_active_mask); +/* +* XXX: race against hot-plug modifying cpu_active_mask +*/ +BUG_ON (cpu >= nr_cpu_ids); + } + +return cpu; }#endif
@@ -7128,7 +7160,23 @@ int set_cpus_allowed_ptr(struct task_strstruct rq *rq;int ret =0 ; +/* +* Since we rely on wake-ups to migrate sleeping tasks, don't change +* the ->cpus_allowed mask from under waking tasks, which would be +* possible when we change rq->lock in ttwu(), so synchronize against +* TASK_WAKING to avoid that. +*/ +again: +while (p->state ==TASK_WAKING ) +cpu_relax (); + rq =task_rq_lock (p, &flags); + +if (p->state ==TASK_WAKING ) { +task_rq_unlock (rq, &flags); + goto again; + } +if (!cpumask_intersects (new_mask, cpu_active_mask)) { ret = -EINVAL ; goto out;
@@ -7184,7 +7232,7 @@ EXPORT_SYMBOL_GPL(set_cpus_allowed_ptr);static int __migrate_task (struct task_struct *p,int src_cpu,int dest_cpu) {struct rq *rq_dest, *rq_src; -int ret =0 , on_rq; +int ret =0 ;if (unlikely (!cpu_active (dest_cpu)))return ret;
@@ -7200,12 +7248,13 @@ static int __migrate_task(struct task_stif (!cpumask_test_cpu (dest_cpu, &p->cpus_allowed)) goto fail; - on_rq = p->se.on_rq; -if (on_rq) +/* +* If we're not on a rq, the next wake-up will ensure we're +* placed properly. +*/ +if (p->se.on_rq) {deactivate_task (rq_src, p,0 ); - -set_task_cpu (p, dest_cpu); -if (on_rq) { +set_task_cpu (p, dest_cpu);activate_task (rq_dest, p,0 );check_preempt_curr (rq_dest, p,0 ); }
PATCH 79/123 sched: Make warning less noisy
In reply to Greg KHFrom: Ingo Molnar <[email protected]>
commit 416eb39556a03d1c7e52b0791e9052ccd71db241 upstream
Cc: Peter Zijlstra <[email protected]>
Cc: Mike Galbraith <[email protected]>
LKML-Reference: <[email protected]>
--- kernel/sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/sched.c +1 -1
@@ -2071,7 +2071,7 @@ void set_task_cpu(struct task_struct *p,* We should never call set_task_cpu() on a blocked task, * ttwu() will sort out the placement. */ -WARN_ON (p->state !=TASK_RUNNING && p->state !=TASK_WAKING ); +WARN_ON_ONCE (p->state !=TASK_RUNNING && p->state !=TASK_WAKING );#endif trace_sched_migrate_task (p, new_cpu);
PATCH 80/123 sched: Fix broken assertion
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit 077614ee1e93245a3b9a4e1213659405dbeb0ba6 upstream
There's a preemption race in the set_task_cpu() debug check in that when we get preempted after setting task->state we'd still be on the rq proper, but fail the test.
Check for preempted tasks, since those are always on the RQ.
LKML-Reference: <[email protected]>
--- kernel/sched.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/sched.c +2 -1
@@ -2071,7 +2071,8 @@ void set_task_cpu(struct task_struct *p,* We should never call set_task_cpu() on a blocked task, * ttwu() will sort out the placement. */ -WARN_ON_ONCE (p->state !=TASK_RUNNING && p->state !=TASK_WAKING ); +WARN_ON_ONCE (p->state !=TASK_RUNNING && p->state !=TASK_WAKING && + !(task_thread_info (p)->preempt_count &PREEMPT_ACTIVE ));#endif trace_sched_migrate_task (p, new_cpu);
PATCH 81/123 sched: Fix sched_exec() balancing
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit 3802290628348674985d14914f9bfee7b9084548 upstream
sched: Fix sched_exec() balancing
Since we access ->cpus_allowed without holding rq->lock we need a retry loop to validate the result, this comes for near free when we merge sched_migrate_task() into sched_exec() since that already does the needed check.
LKML-Reference: <[email protected]>
--- kernel/sched.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-)
kernel/sched.c +23 -22
@@ -2322,7 +2322,7 @@ void task_oncpu_function_call(struct tas* * - fork, @p is stable because it isn't on the tasklist yet * -* - exec, @p is unstable XXX +* - exec, @p is unstable, retry loop * * - wake-up, we serialize ->cpus_allowed against TASK_WAKING so * we should be good.
@@ -3133,21 +3133,36 @@ static void double_rq_unlock(struct rq * }/* -* If dest_cpu is allowed for this process, migrate the task to it. -* This is accomplished by forcing the cpu_allowed mask to only -* allow dest_cpu, which will force the cpu onto dest_cpu. Then -* the cpu_allowed mask is restored. +* sched_exec - execve() is a valuable balancing opportunity, because at +* this point the task has the smallest effective memory and cache footprint. */ -static void sched_migrate_task (struct task_struct *p,int dest_cpu) +void sched_exec (void ) { +struct task_struct *p = current;struct migration_req req; +int dest_cpu, this_cpu;unsigned long flags;struct rq *rq; +again: + this_cpu =get_cpu (); + dest_cpu =select_task_rq (p,SD_BALANCE_EXEC ,0 ); +if (dest_cpu == this_cpu) { +put_cpu (); +return ; + } + rq =task_rq_lock (p, &flags); +put_cpu (); + +/* +* select_task_rq() can race against ->cpus_allowed +*/ if (!cpumask_test_cpu (dest_cpu, &p->cpus_allowed) - ||unlikely (!cpu_active (dest_cpu))) - goto out; + ||unlikely (!cpu_active (dest_cpu))) { +task_rq_unlock (rq, &flags); + goto again; + }/* force the process onto the specified CPU */ if (migrate_task (p, dest_cpu, &req)) {
@@ -3162,24 +3177,10 @@ static void sched_migrate_task(struct tareturn ; } -out:task_rq_unlock (rq, &flags); }/* -* sched_exec - execve() is a valuable balancing opportunity, because at -* this point the task has the smallest effective memory and cache footprint. -*/ -void sched_exec (void ) -{ -int new_cpu, this_cpu =get_cpu (); - new_cpu =select_task_rq (current,SD_BALANCE_EXEC ,0 ); -put_cpu (); -if (new_cpu != this_cpu) -sched_migrate_task (current, new_cpu); -} - -/* * pull_task - move a task from a remote runqueue to the local runqueue. * Both runqueues must be locked. */
PATCH 82/123 sched: Fix select_task_rq() vs hotplug issues
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit 5da9a0fb673a0ea0a093862f95f6b89b3390c31e upstream
Since select_task_rq() is now responsible for guaranteeing ->cpus_allowed and cpu_active_mask, we need to verify this.
select_task_rq_rt() can blindly return smp_processor_id()/task_cpu() without checking the valid masks, select_task_rq_fair() can do the same in the rare case that all SD_flags are disabled.
LKML-Reference: <[email protected]>
--- kernel/sched.c | 76 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 36 deletions(-)
kernel/sched.c +40 -36
@@ -2317,6 +2317,43 @@ void task_oncpu_function_call(struct tas }#ifdef CONFIG_SMP +static int select_fallback_rq (int cpu,struct task_struct *p) +{ +int dest_cpu; +const struct cpumask *nodemask =cpumask_of_node (cpu_to_node (cpu)); + +/* Look for allowed, online CPU in same node. */ +for_each_cpu_and (dest_cpu, nodemask, cpu_active_mask) +if (cpumask_test_cpu (dest_cpu, &p->cpus_allowed)) +return dest_cpu; + +/* Any allowed, online CPU? */ + dest_cpu =cpumask_any_and (&p->cpus_allowed, cpu_active_mask); +if (dest_cpu < nr_cpu_ids) +return dest_cpu; + +/* No more Mr. Nice Guy. */ +if (dest_cpu >= nr_cpu_ids) { +rcu_read_lock (); +cpuset_cpus_allowed_locked (p, &p->cpus_allowed); +rcu_read_unlock (); + dest_cpu =cpumask_any_and (cpu_active_mask, &p->cpus_allowed); + +/* +* Don't tell them about moving exiting tasks or +* kernel threads (both mm NULL), since they never +* leave kernel. +*/ +if (p->mm &&printk_ratelimit ()) { +printk (KERN_INFO "process %d (%s) no " +"longer affine to cpu%d\n" , +task_pid_nr (p), p->comm, cpu); + } + } + +return dest_cpu; +} +/* * Called from: *
@@ -2343,14 +2380,8 @@ int select_task_rq(struct task_struct *p* not worry about this generic constraint ] */ if (unlikely (!cpumask_test_cpu (cpu, &p->cpus_allowed) || - !cpu_active (cpu))) { - - cpu =cpumask_any_and (&p->cpus_allowed, cpu_active_mask); -/* -* XXX: race against hot-plug modifying cpu_active_mask -*/ -BUG_ON (cpu >= nr_cpu_ids); - } + !cpu_active (cpu))) + cpu =select_fallback_rq (task_cpu (p), p);return cpu; }
@@ -7352,37 +7383,10 @@ static int __migrate_task_irq(struct tasstatic void move_task_off_dead_cpu (int dead_cpu,struct task_struct *p) {int dest_cpu; -const struct cpumask *nodemask =cpumask_of_node (cpu_to_node (dead_cpu)); again: -/* Look for allowed, online CPU in same node. */ -for_each_cpu_and (dest_cpu, nodemask, cpu_active_mask) -if (cpumask_test_cpu (dest_cpu, &p->cpus_allowed)) - goto move; - -/* Any allowed, online CPU? */ - dest_cpu =cpumask_any_and (&p->cpus_allowed, cpu_active_mask); -if (dest_cpu < nr_cpu_ids) - goto move; - -/* No more Mr. Nice Guy. */ -if (dest_cpu >= nr_cpu_ids) { -cpuset_cpus_allowed_locked (p, &p->cpus_allowed); - dest_cpu =cpumask_any_and (cpu_active_mask, &p->cpus_allowed); - -/* -* Don't tell them about moving exiting tasks or -* kernel threads (both mm NULL), since they never -* leave kernel. -*/ -if (p->mm &&printk_ratelimit ()) { -printk (KERN_INFO "process %d (%s) no " -"longer affine to cpu%d\n" , -task_pid_nr (p), p->comm, dead_cpu); - } - } + dest_cpu =select_fallback_rq (dead_cpu, p); -move:/* It can have affinity changed while we were choosing. */ if (unlikely (!__migrate_task_irq (p, dead_cpu, dest_cpu))) goto again;
PATCH 83/123 sched: Add pre and post wakeup hooks
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit efbbd05a595343a413964ad85a2ad359b7b7efbd upstream
As will be apparent in the next patch, we need a pre wakeup hook for sched_fair task migration, hence rename the post wakeup hook and one pre wakeup.
LKML-Reference: <[email protected]>
--- include/linux/sched.h | 3 ++- kernel/sched.c | 12 ++++++++---- kernel/sched_rt.c | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-)
include/linux/sched.h +2 -1
@@ -1093,7 +1093,8 @@ struct sched_class { enum cpu_idle_type idle);void (*pre_schedule) (struct rq *this_rq,struct task_struct *task);void (*post_schedule) (struct rq *this_rq); -void (*task_wake_up) (struct rq *this_rq,struct task_struct *task); +void (*task_waking) (struct rq *this_rq,struct task_struct *task); +void (*task_woken) (struct rq *this_rq,struct task_struct *task);void (*set_cpus_allowed)(struct task_struct *p,const struct cpumask *newmask);
kernel/sched.c +8 -4
@@ -2438,6 +2438,10 @@ static int try_to_wake_up(struct task_stif (task_contributes_to_load (p)) rq->nr_uninterruptible--; p->state =TASK_WAKING ; + +if (p->sched_class->task_waking) + p->sched_class->task_waking (rq, p); +__task_rq_unlock (rq); cpu =select_task_rq (p,SD_BALANCE_WAKE , wake_flags);
@@ -2501,8 +2505,8 @@ out_running: p->state =TASK_RUNNING ;#ifdef CONFIG_SMP -if (p->sched_class->task_wake_up) - p->sched_class->task_wake_up (rq, p); +if (p->sched_class->task_woken) + p->sched_class->task_woken (rq, p);if (unlikely (rq->idle_stamp)) {u64 delta = rq->clock - rq->idle_stamp;
@@ -2693,8 +2697,8 @@ void wake_up_new_task(struct task_structtrace_sched_wakeup_new (rq, p,1 );check_preempt_curr (rq, p,WF_FORK );#ifdef CONFIG_SMP -if (p->sched_class->task_wake_up) - p->sched_class->task_wake_up (rq, p); +if (p->sched_class->task_woken) + p->sched_class->task_woken (rq, p);#endif task_rq_unlock (rq, &flags); }
kernel/sched_rt.c +2 -2
@@ -1485,7 +1485,7 @@ static void post_schedule_rt(struct rq ** If we are not running and we are not going to reschedule soon, we should * try to push tasks away now */ -static void task_wake_up_rt (struct rq *rq,struct task_struct *p) +static void task_woken_rt (struct rq *rq,struct task_struct *p) { if (!task_running(rq, p) && !test_tsk_need_resched(rq->curr) &&
@@ -1766,7 +1766,7 @@ static const struct sched_class rt_sched .rq_offline = rq_offline_rt, .pre_schedule = pre_schedule_rt, .post_schedule = post_schedule_rt, - .task_wake_up = task_wake_up_rt, + .task_woken = task_woken_rt, .switched_from = switched_from_rt,#endif
PATCH 84/123 sched: Remove the cfs_rq dependency from set_task_cpu()
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit 88ec22d3edb72b261f8628226cd543589a6d5e1b upstream
In order to remove the cfs_rq dependency from set_task_cpu() we need to ensure the task is cfs_rq invariant for all callsites.
The simple approach is to substract cfs_rq->min_vruntime from se->vruntime on dequeue, and add cfs_rq->min_vruntime on enqueue.
However, this has the downside of breaking FAIR_SLEEPERS since we loose the old vruntime as we only maintain the relative position.
To solve this, we observe that we only migrate runnable tasks, we do this using deactivate_task(.sleep=0) and activate_task(.wakeup=0), therefore we can restrain the min_vruntime invariance to that state.
The only other case is wakeup balancing, since we want to maintain the old vruntime we cannot make it relative on dequeue, but since we don't migrate inactive tasks, we can do so right before we activate it again.
This is where we need the new pre-wakeup hook, we need to call this while still holding the old rq->lock. We could fold it into ->select_task_rq(), but since that has multiple callsites and would obfuscate the locking requirements, that seems like a fudge.
This leaves the fork() case, simply make sure that ->task_fork() leaves the ->vruntime in a relative state.
This covers all cases where set_task_cpu() gets called, and ensures it sees a relative vruntime.
LKML-Reference: <[email protected]>
--- include/linux/sched.h | 2 +- kernel/sched.c | 6 +----- kernel/sched_fair.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 46 insertions(+), 12 deletions(-)
include/linux/sched.h +1 -1
@@ -1118,7 +1118,7 @@ struct sched_class { struct task_struct *task);#ifdef CONFIG_FAIR_GROUP_SCHED -void (*moved_group) (struct task_struct *p); +void (*moved_group) (struct task_struct *p,int on_rq);#endif };
kernel/sched.c +1 -5
@@ -2063,8 +2063,6 @@ task_hot(struct task_struct *p, u64 now,void set_task_cpu (struct task_struct *p,unsigned int new_cpu) {int old_cpu =task_cpu (p); -struct cfs_rq *old_cfsrq =task_cfs_rq (p), - *new_cfsrq =cpu_cfs_rq (old_cfsrq, new_cpu);#ifdef CONFIG_SCHED_DEBUG /*
@@ -2082,8 +2080,6 @@ void set_task_cpu(struct task_struct *p,perf_sw_event (PERF_COUNT_SW_CPU_MIGRATIONS ,1 ,1 ,NULL ,0 ); } - p->se.vruntime -= old_cfsrq->min_vruntime - - new_cfsrq->min_vruntime;__set_task_cpu (p, new_cpu); }
@@ -10144,7 +10140,7 @@ void sched_move_task(struct task_struct#ifdef CONFIG_FAIR_GROUP_SCHED if (tsk->sched_class->moved_group) - tsk->sched_class->moved_group (tsk); + tsk->sched_class->moved_group (tsk, on_rq);#endif if (unlikely (running))
kernel/sched_fair.c +44 -6
115 lines not on this page · raw message
PATCH 85/123 sched: Fix hotplug hang
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit 70f1120527797adb31c68bdc6f1b45e182c342c7 upstream
The hot-unplug kstopmachine usage does a wakeup after deactivating the cpu, hence we cannot use cpu_active() here but must rely on the good olde online.
LKML-Reference: <1261326987.4314.24.camel@laptop>
--- kernel/sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/sched.c +1 -1
@@ -2376,7 +2376,7 @@ int select_task_rq(struct task_struct *p* not worry about this generic constraint ] */ if (unlikely (!cpumask_test_cpu (cpu, &p->cpus_allowed) || - !cpu_active (cpu))) + !cpu_online (cpu))) cpu =select_fallback_rq (task_cpu (p), p);return cpu;
PATCH 86/123 sched: Fix fork vs hotplug vs cpuset namespaces
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit fabf318e5e4bda0aca2b0d617b191884fda62703 upstream
There are a number of issues:
1) TASK_WAKING vs cgroup_clone (cpusets)
copy_process():
sched_fork()
child->state = TASK_WAKING; /* waiting for wake_up_new_task() */
if (current->nsproxy != p->nsproxy)
ns_cgroup_clone()
cgroup_clone()
mutex_lock(inode->i_mutex)
mutex_lock(cgroup_mutex)
cgroup_attach_task()
ss->can_attach()
ss->attach() [ -> cpuset_attach() ]
cpuset_attach_task()
set_cpus_allowed_ptr();
while (child->state == TASK_WAKING)
cpu_relax();will deadlock the system.
2) cgroup_clone (cpusets) vs copy_process
So even if the above would work we still have:
copy_process():
if (current->nsproxy != p->nsproxy)
ns_cgroup_clone()
cgroup_clone()
mutex_lock(inode->i_mutex)
mutex_lock(cgroup_mutex)
cgroup_attach_task()
ss->can_attach()
ss->attach() [ -> cpuset_attach() ]
cpuset_attach_task()
set_cpus_allowed_ptr();...
p->cpus_allowed = current->cpus_allowed
over-writing the modified cpus_allowed.
3) fork() vs hotplug
if we unplug the child's cpu after the sanity check when the child gets attached to the task_list but before wake_up_new_task() shit will meet with fan.
Solve all these issues by moving fork cpu selection into wake_up_new_task().
LKML-Reference: <1264106190.4283.1314.camel@laptop>
--- kernel/fork.c | 15 --------------- kernel/sched.c | 39 +++++++++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 27 deletions(-)
kernel/fork.c +0 -15
@@ -1233,21 +1233,6 @@ static struct task_struct *copy_process(/* Need tasklist lock for parent etc handling! */ write_lock_irq (&tasklist_lock); -/* -* The task hasn't been attached yet, so its cpus_allowed mask will -* not be changed, nor will its assigned CPU. -* -* The cpus_allowed mask of the parent may have changed after it was -* copied first time - so re-copy it here, then check the child's CPU -* to ensure it is on a valid CPU (and if not, just force it back to -* parent's CPU). This avoids alot of nasty races. -*/ - p->cpus_allowed = current->cpus_allowed; - p->rt.nr_cpus_allowed = current->rt.nr_cpus_allowed; -if (unlikely (!cpu_isset (task_cpu (p), p->cpus_allowed) || - !cpu_online (task_cpu (p)))) -set_task_cpu (p,smp_processor_id ()); -/* CLONE_PARENT re-uses the old parent */ if (clone_flags & (CLONE_PARENT |CLONE_THREAD )) { p->real_parent = current->real_parent;
kernel/sched.c +27 -12
@@ -2351,14 +2351,12 @@ static int select_fallback_rq(int cpu, s }/* -* Called from: +* Gets called from 3 sites (exec, fork, wakeup), since it is called without +* holding rq->lock we need to ensure ->cpus_allowed is stable, this is done +* by: * -* - fork, @p is stable because it isn't on the tasklist yet -* -* - exec, @p is unstable, retry loop -* -* - wake-up, we serialize ->cpus_allowed against TASK_WAKING so -* we should be good. +* exec: is unstable, retry loop +* fork & wake-up: serialize ->cpus_allowed against TASK_WAKING */ static inline int select_task_rq (struct task_struct *p,int sd_flags,int wake_flags)
@@ -2652,9 +2650,6 @@ void sched_fork(struct task_struct *p, iif (p->sched_class->task_fork) p->sched_class->task_fork (p); -#ifdef CONFIG_SMP - cpu =select_task_rq (p,SD_BALANCE_FORK ,0 ); -#endif set_task_cpu (p, cpu);#if defined(CONFIG_SCHEDSTATS ) || defined(CONFIG_TASK_DELAY_ACCT )
@@ -2684,6 +2679,21 @@ void wake_up_new_task(struct task_struct {unsigned long flags;struct rq *rq; +int cpu =get_cpu (); + +#ifdef CONFIG_SMP +/* +* Fork balancing, do it here and not earlier because: +* - cpus_allowed can change in the fork path +* - any previously selected cpu might disappear through hotplug +* +* We still have TASK_WAKING but PF_STARTING is gone now, meaning +* ->cpus_allowed is stable, we have preemption disabled, meaning +* cpu_online_mask is stable. +*/ + cpu =select_task_rq (p,SD_BALANCE_FORK ,0 ); +set_task_cpu (p, cpu); +#endif rq =task_rq_lock (p, &flags);BUG_ON (p->state !=TASK_WAKING );
@@ -2697,6 +2707,7 @@ void wake_up_new_task(struct task_struct p->sched_class->task_woken (rq, p);#endif task_rq_unlock (rq, &flags); +put_cpu (); }#ifdef CONFIG_PREEMPT_NOTIFIERS
@@ -7198,14 +7209,18 @@ int set_cpus_allowed_ptr(struct task_str* the ->cpus_allowed mask from under waking tasks, which would be * possible when we change rq->lock in ttwu(), so synchronize against * TASK_WAKING to avoid that. +* +* Make an exception for freshly cloned tasks, since cpuset namespaces +* might move the task about, we have to validate the target in +* wake_up_new_task() anyway since the cpu might have gone away. */ again: -while (p->state ==TASK_WAKING ) +while (p->state ==TASK_WAKING && !(p->flags &PF_STARTING ))cpu_relax (); rq =task_rq_lock (p, &flags); -if (p->state ==TASK_WAKING ) { +if (p->state ==TASK_WAKING && !(p->flags &PF_STARTING )) {task_rq_unlock (rq, &flags); goto again; }
PATCH 87/123 sched: Fix incorrect sanity check
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit 11854247e2c851e7ff9ce138e501c6cffc5a4217 upstream
We moved to migrate on wakeup, which means that sleeping tasks could still be present on offline cpus. Amend the check to only test running tasks.
--- kernel/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/cpu.c +1 -1
@@ -151,7 +151,7 @@ static inline void check_for_tasks(int cwrite_lock_irq (&tasklist_lock); for_each_process(p) { - if (task_cpu(p) == cpu && + if (task_cpu(p) == cpu && p->state == TASK_RUNNING && (!cputime_eq(p->utime, cputime_zero) || !cputime_eq(p->stime, cputime_zero))) printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d\
PATCH 88/123 sched: Fix race between ttwu() and task_rq_lock()
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit 0970d2992dfd7d5ec2c787417cf464f01eeaf42a upstream
Thomas found that due to ttwu() changing a task's cpu without holding the rq->lock, task_rq_lock() might end up locking the wrong rq.
Avoid this by serializing against TASK_WAKING.
LKML-Reference: <1266241712.15770.420.camel@laptop>
--- kernel/sched.c | 71 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 26 deletions(-)
kernel/sched.c +45 -26
@@ -942,16 +942,33 @@ static inline void finish_lock_switch(st#endif /* __ARCH_WANT_UNLOCKED_CTXSW */ /* +* Check whether the task is waking, we use this to synchronize against +* ttwu() so that task_cpu() reports a stable number. +* +* We need to make an exception for PF_STARTING tasks because the fork +* path might require task_rq_lock() to work, eg. it can call +* set_cpus_allowed_ptr() from the cpuset clone_ns code. +*/ +static inline int task_is_waking (struct task_struct *p) +{ +return unlikely ((p->state ==TASK_WAKING ) && !(p->flags &PF_STARTING )); +} + +/* * __task_rq_lock - lock the runqueue a given task resides on. * Must be called interrupts disabled. */ static inline struct rq *__task_rq_lock (struct task_struct *p) __acquires(rq->lock) { +struct rq *rq; +for (;;) { -struct rq *rq =task_rq (p); +while (task_is_waking (p)) +cpu_relax (); + rq =task_rq (p);spin_lock (&rq->lock); -if (likely (rq ==task_rq (p))) +if (likely (rq ==task_rq (p) && !task_is_waking (p)))return rq;spin_unlock (&rq->lock); }
@@ -968,10 +985,12 @@ static struct rq *task_rq_lock(struct tastruct rq *rq;for (;;) { +while (task_is_waking (p)) +cpu_relax ();local_irq_save (*flags); rq =task_rq (p);spin_lock (&rq->lock); -if (likely (rq ==task_rq (p))) +if (likely (rq ==task_rq (p) && !task_is_waking (p)))return rq;spin_unlock_irqrestore (&rq->lock, *flags); }
@@ -2439,14 +2458,27 @@ static int try_to_wake_up(struct task_st__task_rq_unlock (rq); cpu =select_task_rq (p,SD_BALANCE_WAKE , wake_flags); -if (cpu != orig_cpu) +if (cpu != orig_cpu) { +/* +* Since we migrate the task without holding any rq->lock, +* we need to be careful with task_rq_lock(), since that +* might end up locking an invalid rq. +*/ set_task_cpu (p, cpu); + } - rq =__task_rq_lock (p); + rq =cpu_rq (cpu); +spin_lock (&rq->lock);update_rq_clock (rq); +/* +* We migrated the task without holding either rq->lock, however +* since the task is not on the task list itself, nobody else +* will try and migrate the task, hence the rq should match the +* cpu we just moved it to. +*/ +WARN_ON (task_cpu (p) != cpu);WARN_ON (p->state !=TASK_WAKING ); - cpu =task_cpu (p);#ifdef CONFIG_SCHEDSTATS schedstat_inc (rq, ttwu_count);
@@ -2695,7 +2727,13 @@ void wake_up_new_task(struct task_structset_task_cpu (p, cpu);#endif - rq =task_rq_lock (p, &flags); +/* +* Since the task is not on the rq and we still have TASK_WAKING set +* nobody else will migrate this task. +*/ + rq =cpu_rq (cpu); +spin_lock_irqsave (&rq->lock, flags); +BUG_ON (p->state !=TASK_WAKING ); p->state =TASK_RUNNING ;update_rq_clock (rq);
@@ -7204,27 +7242,8 @@ int set_cpus_allowed_ptr(struct task_strstruct rq *rq;int ret =0 ; -/* -* Since we rely on wake-ups to migrate sleeping tasks, don't change -* the ->cpus_allowed mask from under waking tasks, which would be -* possible when we change rq->lock in ttwu(), so synchronize against -* TASK_WAKING to avoid that. -* -* Make an exception for freshly cloned tasks, since cpuset namespaces -* might move the task about, we have to validate the target in -* wake_up_new_task() anyway since the cpu might have gone away. -*/ -again: -while (p->state ==TASK_WAKING && !(p->flags &PF_STARTING )) -cpu_relax (); - rq =task_rq_lock (p, &flags); -if (p->state ==TASK_WAKING && !(p->flags &PF_STARTING )) { -task_rq_unlock (rq, &flags); - goto again; - } -if (!cpumask_intersects (new_mask, cpu_active_mask)) { ret = -EINVAL ; goto out;
PATCH 89/123 sched: Extend enqueue_task to allow head queueing
In reply to Greg KHFrom: Thomas Gleixner <[email protected]>
commit ea87bb7853168434f4a82426dd1ea8421f9e604d upstream
The ability of enqueueing a task to the head of a SCHED_FIFO priority list is required to fix some violations of POSIX scheduling policy.
Extend the related functions with a "head" argument.
LKML-Reference: <[email protected]>
--- include/linux/sched.h | 3 ++- kernel/sched.c | 13 +++++++------ kernel/sched_fair.c | 3 ++- kernel/sched_rt.c | 3 ++- 4 files changed, 13 insertions(+), 9 deletions(-)
include/linux/sched.h +2 -1
@@ -1071,7 +1071,8 @@ struct sched_domain;struct sched_class {const struct sched_class *next; -void (*enqueue_task) (struct rq *rq,struct task_struct *p,int wakeup); +void (*enqueue_task) (struct rq *rq,struct task_struct *p,int wakeup, +bool head);void (*dequeue_task) (struct rq *rq,struct task_struct *p,int sleep);void (*yield_task) (struct rq *rq);
kernel/sched.c +7 -6
@@ -1903,13 +1903,14 @@ static void update_avg(u64 *avg, u64 sam *avg += diff >>3 ; } -static void enqueue_task (struct rq *rq,struct task_struct *p,int wakeup) +static void +enqueue_task (struct rq *rq,struct task_struct *p,int wakeup,bool head) {if (wakeup) p->se.start_runtime = p->se.sum_exec_runtime;sched_info_queued (p); - p->sched_class->enqueue_task (rq, p, wakeup); + p->sched_class->enqueue_task (rq, p, wakeup, head); p->se.on_rq =1 ; }
@@ -1985,7 +1986,7 @@ static void activate_task(struct rq *rq,if (task_contributes_to_load (p)) rq->nr_uninterruptible--; -enqueue_task (rq, p, wakeup); +enqueue_task (rq, p, wakeup, false);inc_nr_running (rq); }
@@ -6183,7 +6184,7 @@ void rt_mutex_setprio(struct task_structif (running) p->sched_class->set_curr_task (rq);if (on_rq) { -enqueue_task (rq, p,0 ); +enqueue_task (rq, p,0 , false);check_class_changed (rq, p, prev_class, oldprio, running); }
@@ -6227,7 +6228,7 @@ void set_user_nice(struct task_struct *p delta = p->prio - old_prio;if (on_rq) { -enqueue_task (rq, p,0 ); +enqueue_task (rq, p,0 , false);/* * If the task increased its priority or is running and * lowered its priority, then reschedule its CPU:
@@ -10180,7 +10181,7 @@ void sched_move_task(struct task_structif (unlikely (running)) tsk->sched_class->set_curr_task (rq);if (on_rq) -enqueue_task (rq, tsk,0 ); +enqueue_task (rq, tsk,0 , false);task_rq_unlock (rq, &flags); }
kernel/sched_fair.c +2 -1
@@ -1031,7 +1031,8 @@ static inline void hrtick_update(struct* increased. Here we update the fair scheduling stats and * then put the task into the rbtree: */ -static void enqueue_task_fair (struct rq *rq,struct task_struct *p,int wakeup) +static void +enqueue_task_fair (struct rq *rq,struct task_struct *p,int wakeup,bool head) {struct cfs_rq *cfs_rq;struct sched_entity *se = &p->se;
kernel/sched_rt.c +2 -1
@@ -878,7 +878,8 @@ static void dequeue_rt_entity(struct sch/* * Adding/removing a task to/from a priority array: */ -static void enqueue_task_rt (struct rq *rq,struct task_struct *p,int wakeup) +static void +enqueue_task_rt (struct rq *rq,struct task_struct *p,int wakeup,bool head) {struct sched_rt_entity *rt_se = &p->rt;
PATCH 90/123 sched: Implement head queueing for sched_rt
In reply to Greg KHFrom: Thomas Gleixner <[email protected]>
commit 37dad3fce97f01e5149d69de0833d8452c0e862e upstream
The ability of enqueueing a task to the head of a SCHED_FIFO priority list is required to fix some violations of POSIX scheduling policy.
Implement the functionality in sched_rt.
LKML-Reference: <[email protected]>
--- kernel/sched_rt.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)
kernel/sched_rt.c +11 -8
@@ -194,7 +194,7 @@ static inline struct rt_rq *group_rt_rq(return rt_se->my_q; } -static void enqueue_rt_entity (struct sched_rt_entity *rt_se); +static void enqueue_rt_entity (struct sched_rt_entity *rt_se,bool head);static void dequeue_rt_entity (struct sched_rt_entity *rt_se);static void sched_rt_rq_enqueue (struct rt_rq *rt_rq)
@@ -204,7 +204,7 @@ static void sched_rt_rq_enqueue(struct rif (rt_rq->rt_nr_running) {if (rt_se && !on_rt_rq (rt_se)) -enqueue_rt_entity (rt_se); +enqueue_rt_entity (rt_se, false);if (rt_rq->highest_prio.curr < curr->prio)resched_task (curr); }
@@ -803,7 +803,7 @@ void dec_rt_tasks(struct sched_rt_entitydec_rt_group (rt_se, rt_rq); } -static void __enqueue_rt_entity (struct sched_rt_entity *rt_se) +static void __enqueue_rt_entity (struct sched_rt_entity *rt_se,bool head) {struct rt_rq *rt_rq =rt_rq_of_se (rt_se);struct rt_prio_array *array = &rt_rq->active;
@@ -819,7 +819,10 @@ static void __enqueue_rt_entity(struct sif (group_rq && (rt_rq_throttled (group_rq) || !group_rq->rt_nr_running))return ; -list_add_tail (&rt_se->run_list, queue); +if (head) +list_add (&rt_se->run_list, queue); +else +list_add_tail (&rt_se->run_list, queue);__set_bit (rt_se_prio (rt_se), array->bitmap);inc_rt_tasks (rt_se, rt_rq);
@@ -856,11 +859,11 @@ static void dequeue_rt_stack(struct sche } } -static void enqueue_rt_entity (struct sched_rt_entity *rt_se) +static void enqueue_rt_entity (struct sched_rt_entity *rt_se,bool head) {dequeue_rt_stack (rt_se);for_each_sched_rt_entity (rt_se) -__enqueue_rt_entity (rt_se); +__enqueue_rt_entity (rt_se, head); }static void dequeue_rt_entity (struct sched_rt_entity *rt_se)
@@ -871,7 +874,7 @@ static void dequeue_rt_entity(struct schstruct rt_rq *rt_rq =group_rt_rq (rt_se);if (rt_rq && rt_rq->rt_nr_running) -__enqueue_rt_entity (rt_se); +__enqueue_rt_entity (rt_se, false); } }
@@ -886,7 +889,7 @@ enqueue_task_rt(struct rq *rq, struct taif (wakeup) rt_se->timeout =0 ; -enqueue_rt_entity (rt_se); +enqueue_rt_entity (rt_se, head);if (!task_current (rq, p) && p->rt.nr_cpus_allowed >1 )enqueue_pushable_task (rq, p);
PATCH 91/123 sched: Queue a deboosted task to the head of the RT prio queue
In reply to Greg KHFrom: Thomas Gleixner <[email protected]>
commit 60db48cacb9b253d5607a5ff206112a59cd09e34 upstream
rtmutex_set_prio() is used to implement priority inheritance for futexes. When a task is deboosted it gets enqueued at the tail of its RT priority list. This is violating the POSIX scheduling semantics:
rt priority list X contains two runnable tasks A and B
task A runs with priority X and holds mutex M
task C preempts A and is blocked on mutex M
-> task A is boosted to priority of task C (Y)
task A unlocks the mutex M and deboosts itself
-> A is dequeued from rt priority list Y
-> A is enqueued to the tail of rt priority list Xtask C schedules away
task B runs
This is wrong as task A did not schedule away and therefor violates the POSIX scheduling semantics.
Enqueue the task to the head of the priority list instead.
LKML-Reference: <[email protected]>
--- kernel/sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/sched.c +1 -1
@@ -6184,7 +6184,7 @@ void rt_mutex_setprio(struct task_structif (running) p->sched_class->set_curr_task (rq);if (on_rq) { -enqueue_task (rq, p,0 , false); +enqueue_task (rq, p,0 , oldprio < prio);check_class_changed (rq, p, prev_class, oldprio, running); }
PATCH 92/123 sched: set_cpus_allowed_ptr(): Dont use rq->migration_thread after unlock
In reply to Greg KHFrom: Oleg Nesterov <[email protected]>
commit 47a70985e5c093ae03d8ccf633c70a93761d86f2 upstream
Trivial typo fix. rq->migration_thread can be NULL after task_rq_unlock(), this is why we have "mt" which should be
used instead.
LKML-Reference: <[email protected]>
--- kernel/sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/sched.c +1 -1
@@ -7273,7 +7273,7 @@ int set_cpus_allowed_ptr(struct task_strget_task_struct (mt);task_rq_unlock (rq, &flags); -wake_up_process (rq->migration_thread); +wake_up_process (mt);put_task_struct (mt);wait_for_completion (&req.done);tlb_migrate_finish (p->mm);
PATCH 93/123 sched: Kill the broken and deadlockable cpuset_lock/cpuset_cpus_allowed_locked code
In reply to Greg KHFrom: Oleg Nesterov <[email protected]>
commit 897f0b3c3ff40b443c84e271bef19bd6ae885195 upstream
This patch just states the fact the cpusets/cpuhotplug interaction is broken and removes the deadlockable code which only pretends to work.
- cpuset_lock() doesn't really work. It is needed for cpuset_cpus_allowed_locked() but we can't take this lock in try_to_wake_up()->select_fallback_rq() path.
- cpuset_lock() is deadlockable. Suppose that a task T bound to CPU takes callback_mutex. If cpu_down(CPU) happens before T drops callback_mutex stop_machine() preempts T, then migration_call(CPU_DEAD) tries to take cpuset_lock() and hangs forever because CPU is already dead and thus T can't be scheduled.
- cpuset_cpus_allowed_locked() is deadlockable too. It takes task_lock() which is not irq-safe, but try_to_wake_up() can be called from irq.
Kill them, and change select_fallback_rq() to use cpu_possible_mask, like we currently do without CONFIG_CPUSETS.
Also, with or without this patch, with or without CONFIG_CPUSETS, the callers of select_fallback_rq() can race with each other or with set_cpus_allowed() pathes.
The subsequent patches try to to fix these problems.
LKML-Reference: <[email protected]>
--- include/linux/cpuset.h | 13 ------------- kernel/cpuset.c | 27 +-------------------------- kernel/sched.c | 10 +++------- 3 files changed, 4 insertions(+), 46 deletions(-)
include/linux/cpuset.h +0 -13
@@ -21,8 +21,6 @@ extern int number_of_cpusets; /* How manextern int cpuset_init (void );extern void cpuset_init_smp (void );extern void cpuset_cpus_allowed (struct task_struct *p,struct cpumask *mask); -extern void cpuset_cpus_allowed_locked (struct task_struct *p, -struct cpumask *mask);extern nodemask_t cpuset_mems_allowed (struct task_struct *p);#define cpuset_current_mems_allowed (current->mems_allowed)void cpuset_init_current_mems_allowed (void );
@@ -69,9 +67,6 @@ struct seq_file;extern void cpuset_task_status_allowed (struct seq_file *m,struct task_struct *task); -extern void cpuset_lock (void ); -extern void cpuset_unlock (void ); -extern int cpuset_mem_spread_node (void );static inline int cpuset_do_page_mem_spread (void )
@@ -105,11 +100,6 @@ static inline void cpuset_cpus_allowed(s {cpumask_copy (mask, cpu_possible_mask); } -static inline void cpuset_cpus_allowed_locked (struct task_struct *p, -struct cpumask *mask) -{ -cpumask_copy (mask, cpu_possible_mask); -}static inline nodemask_t cpuset_mems_allowed (struct task_struct *p) {
@@ -157,9 +147,6 @@ static inline void cpuset_task_status_al { } -static inline void cpuset_lock (void ) {} -static inline void cpuset_unlock (void ) {} -static inline int cpuset_mem_spread_node (void ) {return 0 ;
kernel/cpuset.c +1 -26
@@ -2145,19 +2145,10 @@ void __init cpuset_init_smp(void)void cpuset_cpus_allowed (struct task_struct *tsk,struct cpumask *pmask) {mutex_lock (&callback_mutex); -cpuset_cpus_allowed_locked (tsk, pmask); -mutex_unlock (&callback_mutex); -} - -/** -* cpuset_cpus_allowed_locked - return cpus_allowed mask from a tasks cpuset. -* Must be called with callback_mutex held. -**/ -void cpuset_cpus_allowed_locked (struct task_struct *tsk,struct cpumask *pmask) -{task_lock (tsk);guarantee_online_cpus (task_cs (tsk), pmask);task_unlock (tsk); +mutex_unlock (&callback_mutex); }void cpuset_init_current_mems_allowed (void )
@@ -2346,22 +2337,6 @@ int __cpuset_node_allowed_hardwall(int n }/** -* cpuset_lock - lock out any changes to cpuset structures -* -* The out of memory (oom) code needs to mutex_lock cpusets -* from being changed while it scans the tasklist looking for a -* task in an overlapping cpuset. Expose callback_mutex via this -* cpuset_lock() routine, so the oom code can lock it, before -* locking the task list. The tasklist_lock is a spinlock, so -* must be taken inside callback_mutex. -*/ - -void cpuset_lock (void ) -{ -mutex_lock (&callback_mutex); -} - -/** * cpuset_unlock - release lock on cpuset changes * * Undo the lock taken in a previous cpuset_lock() call.
kernel/sched.c +3 -7
@@ -2349,11 +2349,9 @@ static int select_fallback_rq(int cpu, sreturn dest_cpu;/* No more Mr. Nice Guy. */ -if (dest_cpu >= nr_cpu_ids) { -rcu_read_lock (); -cpuset_cpus_allowed_locked (p, &p->cpus_allowed); -rcu_read_unlock (); - dest_cpu =cpumask_any_and (cpu_active_mask, &p->cpus_allowed); +if (unlikely (dest_cpu >= nr_cpu_ids)) { +cpumask_copy (&p->cpus_allowed, cpu_possible_mask); + dest_cpu =cpumask_any (cpu_active_mask);/* * Don't tell them about moving exiting tasks or
@@ -7833,7 +7831,6 @@ migration_call(struct notifier_block *nfcase CPU_DEAD :case CPU_DEAD_FROZEN : -cpuset_lock ();/* around calls to cpuset_cpus_allowed_lock() */ migrate_live_tasks (cpu); rq =cpu_rq (cpu);/* Idle task back to normal (off runqueue, low prio) */
@@ -7844,7 +7841,6 @@ migration_call(struct notifier_block *nf rq->idle->sched_class = &idle_sched_class;migrate_dead_tasks (cpu);spin_unlock_irq (&rq->lock); -cpuset_unlock ();migrate_nr_uninterruptible (rq);BUG_ON (rq->nr_running !=0 );calc_global_load_remove (rq);
PATCH 94/123 sched: move_task_off_dead_cpu(): Take rq->lock around select_fallback_rq()
In reply to Greg KHFrom: Oleg Nesterov <[email protected]>
commit 1445c08d06c5594895b4fae952ef8a457e89c390 upstream
move_task_off_dead_cpu()->select_fallback_rq() reads/updates ->cpus_allowed lockless. We can race with set_cpus_allowed() running in parallel.
Change it to take rq->lock around select_fallback_rq(). Note that it is not trivial to move this spin_lock() into select_fallback_rq(), we must recheck the task was not migrated after we take the lock and other callers do not need this lock.
To avoid the races with other callers of select_fallback_rq() which rely on TASK_WAKING, we also check p->state != TASK_WAKING and do nothing otherwise. The owner of TASK_WAKING must update ->cpus_allowed and choose the correct CPU anyway, and the subsequent __migrate_task() is just meaningless because p->se.on_rq must be false.
Alternatively, we could change select_task_rq() to take rq->lock right after it calls sched_class->select_task_rq(), but this looks a bit ugly.
Also, change it to not assume irqs are disabled and absorb __migrate_task_irq().
LKML-Reference: <[email protected]>
--- kernel/sched.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-)
kernel/sched.c +15 -15
@@ -7399,29 +7399,29 @@ static int migration_thread(void *data) }#ifdef CONFIG_HOTPLUG_CPU - -static int __migrate_task_irq (struct task_struct *p,int src_cpu,int dest_cpu) -{ -int ret; - -local_irq_disable (); - ret =__migrate_task (p, src_cpu, dest_cpu); -local_irq_enable (); -return ret; -} -/* * Figure out where task on dead CPU should go, use force if necessary. */ static void move_task_off_dead_cpu (int dead_cpu,struct task_struct *p) { -int dest_cpu; - +struct rq *rq =cpu_rq (dead_cpu); +int needs_cpu,uninitialized_var (dest_cpu ); +unsigned long flags; again: - dest_cpu =select_fallback_rq (dead_cpu, p); +local_irq_save (flags); + +spin_lock (&rq->lock); + needs_cpu = (task_cpu (p) == dead_cpu) && (p->state !=TASK_WAKING ); +if (needs_cpu) + dest_cpu =select_fallback_rq (dead_cpu, p); +spin_unlock (&rq->lock);/* It can have affinity changed while we were choosing. */ -if (unlikely (!__migrate_task_irq (p, dead_cpu, dest_cpu))) +if (needs_cpu) + needs_cpu = !__migrate_task (p, dead_cpu, dest_cpu); +local_irq_restore (flags); + +if (unlikely (needs_cpu)) goto again; }
PATCH 95/123 sched: move_task_off_dead_cpu(): Remove retry logic
In reply to Greg KHFrom: Oleg Nesterov <[email protected]>
commit c1804d547dc098363443667609c272d1e4d15ee8 upstream
The previous patch preserved the retry logic, but it looks unneeded.
__migrate_task() can only fail if we raced with migration after we dropped the lock, but in this case the caller of set_cpus_allowed/etc must initiate migration itself if ->on_rq == T.
We already fixed p->cpus_allowed, the changes in active/online masks must be visible to racer, it should migrate the task to online cpu correctly.
LKML-Reference: <[email protected]>
--- kernel/sched.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
kernel/sched.c +6 -7
@@ -7407,7 +7407,7 @@ static void move_task_off_dead_cpu(int dstruct rq *rq =cpu_rq (dead_cpu);int needs_cpu,uninitialized_var (dest_cpu );unsigned long flags; -again: +local_irq_save (flags);spin_lock (&rq->lock);
@@ -7415,14 +7415,13 @@ again:if (needs_cpu) dest_cpu =select_fallback_rq (dead_cpu, p);spin_unlock (&rq->lock); - -/* It can have affinity changed while we were choosing. */ +/* +* It can only fail if we race with set_cpus_allowed(), +* in the racer should migrate the task anyway. +*/ if (needs_cpu) - needs_cpu = !__migrate_task (p, dead_cpu, dest_cpu); +__migrate_task (p, dead_cpu, dest_cpu);local_irq_restore (flags); - -if (unlikely (needs_cpu)) - goto again; }/*
PATCH 96/123 sched: sched_exec(): Remove the select_fallback_rq() logic
In reply to Greg KHFrom: Oleg Nesterov <[email protected]>
commit 30da688ef6b76e01969b00608202fff1eed2accc upstream.
sched_exec()->select_task_rq() reads/updates ->cpus_allowed lockless. This can race with other CPUs updating our ->cpus_allowed, and this looks meaningless to me.
The task is current and running, it must have online cpus in ->cpus_allowed, the fallback mode is bogus. And, if ->sched_class returns the "wrong" cpu, this likely means we raced with set_cpus_allowed() which was called for reason, why should sched_exec() retry and call ->select_task_rq() again?
Change the code to call sched_class->select_task_rq() directly and do nothing if the returned cpu is wrong after re-checking under rq->lock.
Quoted 1 line
From now
task_struct->cpus_allowedis always stable underTASK_WAKING,
select_fallback_rq() is always called under rq-lock or the caller or the caller owns TASK_WAKING (select_task_rq).
LKML-Reference: <[email protected]>
--- kernel/sched.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-)
kernel/sched.c +8 -17
@@ -2333,6 +2333,9 @@ void task_oncpu_function_call(struct tas }#ifdef CONFIG_SMP +/* +* ->cpus_allowed is protected by either TASK_WAKING or rq->lock held. +*/ static int select_fallback_rq (int cpu,struct task_struct *p) {int dest_cpu;
@@ -2369,12 +2372,7 @@ static int select_fallback_rq(int cpu, s }/* -* Gets called from 3 sites (exec, fork, wakeup), since it is called without -* holding rq->lock we need to ensure ->cpus_allowed is stable, this is done -* by: -* -* exec: is unstable, retry loop -* fork & wake-up: serialize ->cpus_allowed against TASK_WAKING +* The caller (fork, wakeup) owns TASK_WAKING, ->cpus_allowed is stable. */ static inline int select_task_rq (struct task_struct *p,int sd_flags,int wake_flags)
@@ -3223,9 +3221,8 @@ void sched_exec(void)unsigned long flags;struct rq *rq; -again: this_cpu =get_cpu (); - dest_cpu =select_task_rq (p,SD_BALANCE_EXEC ,0 ); + dest_cpu = p->sched_class->select_task_rq (p,SD_BALANCE_EXEC ,0 );if (dest_cpu == this_cpu) {put_cpu ();return ;
@@ -3233,18 +3230,12 @@ again: rq =task_rq_lock (p, &flags);put_cpu (); -/* * select_task_rq() can race against ->cpus_allowed */ -if (!cpumask_test_cpu (dest_cpu, &p->cpus_allowed) - ||unlikely (!cpu_active (dest_cpu))) { -task_rq_unlock (rq, &flags); - goto again; - } - -/* force the process onto the specified CPU */ -if (migrate_task (p, dest_cpu, &req)) { +if (cpumask_test_cpu (dest_cpu, &p->cpus_allowed) && +likely (cpu_active (dest_cpu)) && +migrate_task (p, dest_cpu, &req)) {/* Need to wait for migration thread (might exit: take ref). */ struct task_struct *mt = rq->migration_thread;
PATCH 97/123 sched: _cpu_down(): Dont play with current->cpus_allowed
In reply to Greg KHFrom: Oleg Nesterov <[email protected]>
commit 6a1bdc1b577ebcb65f6603c57f8347309bc4ab13 upstream
_cpu_down() changes the current task's affinity and then recovers it at the end. The problems are well known: we can't restore old_allowed if it was bound to the now-dead-cpu, and we can race with the userspace which can change cpu-affinity during unplug.
_cpu_down() should not play with current->cpus_allowed at all. Instead, take_cpu_down() can migrate the caller of _cpu_down() after __cpu_disable() removes the dying cpu from cpu_online_mask.
LKML-Reference: <[email protected]>
--- include/linux/sched.h | 1 + kernel/cpu.c | 18 ++++++------------ kernel/sched.c | 2 +- 3 files changed, 8 insertions(+), 13 deletions(-)
include/linux/sched.h +1 -0
@@ -1887,6 +1887,7 @@ extern void sched_clock_idle_sleep_eventextern void sched_clock_idle_wakeup_event (u64 delta_ns);#ifdef CONFIG_HOTPLUG_CPU +extern void move_task_off_dead_cpu (int dead_cpu,struct task_struct *p);extern void idle_task_exit (void );#else static inline void idle_task_exit (void ) {}
kernel/cpu.c +6 -12
@@ -163,6 +163,7 @@ static inline void check_for_tasks(int c }struct take_cpu_down_param { +struct task_struct *caller;unsigned long mod;void *hcpu; };
@@ -171,6 +172,7 @@ struct take_cpu_down_param {static int __ref take_cpu_down (void *_param) {struct take_cpu_down_param *param = _param; +unsigned int cpu = (unsigned long )param->hcpu;int err;/* Ensure this CPU doesn't handle any more interrupts. */
@@ -181,6 +183,8 @@ static int __ref take_cpu_down(void *_paraw_notifier_call_chain (&cpu_chain,CPU_DYING | param->mod, param->hcpu); +if (task_cpu (param->caller) == cpu) +move_task_off_dead_cpu (cpu, param->caller);/* Force idle task to run as soon as we yield: it should immediately notice cpu is offline and die quickly. */ sched_idle_next ();
@@ -191,10 +195,10 @@ static int __ref take_cpu_down(void *_pastatic int __ref _cpu_down (unsigned int cpu,int tasks_frozen) {int err, nr_calls =0 ; -cpumask_var_t old_allowed;void *hcpu = (void *)(long )cpu;unsigned long mod = tasks_frozen ?CPU_TASKS_FROZEN :0 ;struct take_cpu_down_param tcd_param = { + .caller = current, .mod = mod, .hcpu = hcpu, };
@@ -205,9 +209,6 @@ static int __ref _cpu_down(unsigned intif (!cpu_online (cpu))return -EINVAL ; -if (!alloc_cpumask_var (&old_allowed,GFP_KERNEL )) -return -ENOMEM ; -cpu_hotplug_begin ();set_cpu_active (cpu, false); err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod,
@@ -224,10 +225,6 @@ static int __ref _cpu_down(unsigned int goto out_release; } -/* Ensure that we are not runnable on dying cpu */ -cpumask_copy (old_allowed, ¤t->cpus_allowed); -set_cpus_allowed_ptr (current, cpu_active_mask); - err =__stop_machine (take_cpu_down, &tcd_param,cpumask_of (cpu));if (err) {set_cpu_active (cpu, true);
@@ -236,7 +233,7 @@ static int __ref _cpu_down(unsigned int hcpu) == NOTIFY_BAD)BUG (); - goto out_allowed; + goto out_release; }BUG_ON (cpu_online (cpu));
@@ -254,8 +251,6 @@ static int __ref _cpu_down(unsigned intcheck_for_tasks (cpu); -out_allowed: -set_cpus_allowed_ptr (current, old_allowed); out_release:cpu_hotplug_done ();if (!err) {
@@ -263,7 +258,6 @@ out_release: hcpu) == NOTIFY_BAD)BUG (); } -free_cpumask_var (old_allowed);return err; }
kernel/sched.c +1 -1
@@ -7393,7 +7393,7 @@ static int migration_thread(void *data)/* * Figure out where task on dead CPU should go, use force if necessary. */ -static void move_task_off_dead_cpu (int dead_cpu,struct task_struct *p) +void move_task_off_dead_cpu (int dead_cpu,struct task_struct *p) {struct rq *rq =cpu_rq (dead_cpu);int needs_cpu,uninitialized_var (dest_cpu );
PATCH 98/123 sched: Make select_fallback_rq() cpuset friendly
In reply to Greg KHFrom: Oleg Nesterov <[email protected]>
commit 9084bb8246ea935b98320554229e2f371f7f52fa upstream
Introduce cpuset_cpus_allowed_fallback() helper to fix the cpuset problems with select_fallback_rq(). It can be called from any context and can't use any cpuset locks including task_lock(). It is called when the task doesn't have online cpus in ->cpus_allowed but ttwu/etc must be able to find a suitable cpu.
I am not proud of this patch. Everything which needs such a fat comment can't be good even if correct. But I'd prefer to not change the locking rules in the code I hardly understand, and in any case I believe this simple change make the code much more correct compared to deadlocks we currently have.
LKML-Reference: <[email protected]>
--- include/linux/cpuset.h | 7 +++++++ kernel/cpuset.c | 42 ++++++++++++++++++++++++++++++++++++++++++ kernel/sched.c | 4 +--- 3 files changed, 50 insertions(+), 3 deletions(-)
include/linux/cpuset.h +7 -0
@@ -21,6 +21,7 @@ extern int number_of_cpusets; /* How manextern int cpuset_init (void );extern void cpuset_init_smp (void );extern void cpuset_cpus_allowed (struct task_struct *p,struct cpumask *mask); +extern int cpuset_cpus_allowed_fallback (struct task_struct *p);extern nodemask_t cpuset_mems_allowed (struct task_struct *p);#define cpuset_current_mems_allowed (current->mems_allowed)void cpuset_init_current_mems_allowed (void );
@@ -101,6 +102,12 @@ static inline void cpuset_cpus_allowed(scpumask_copy (mask, cpu_possible_mask); } +static inline int cpuset_cpus_allowed_fallback (struct task_struct *p) +{ +cpumask_copy (&p->cpus_allowed, cpu_possible_mask); +return cpumask_any (cpu_active_mask); +} +static inline nodemask_t cpuset_mems_allowed (struct task_struct *p) {return node_possible_map;
kernel/cpuset.c +42 -0
48 lines not on this page · raw message
kernel/sched.c +1 -3
@@ -2353,9 +2353,7 @@ static int select_fallback_rq(int cpu, s/* No more Mr. Nice Guy. */ if (unlikely (dest_cpu >= nr_cpu_ids)) { -cpumask_copy (&p->cpus_allowed, cpu_possible_mask); - dest_cpu =cpumask_any (cpu_active_mask); - + dest_cpu =cpuset_cpus_allowed_fallback (p);/* * Don't tell them about moving exiting tasks or * kernel threads (both mm NULL), since they never
PATCH 99/123 sched: Fix TASK_WAKING vs fork deadlock
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit 0017d735092844118bef006696a750a0e4ef6ebd upstream
Oleg noticed a few races with the TASK_WAKING usage on fork.
- since TASK_WAKING is basically a spinlock, it should be IRQ safe
- since we set TASK_WAKING (*) without holding rq->lock it could be there still is a rq->lock holder, thereby not actually providing full serialization.
(*) in fact we clear PF_STARTING, which in effect enables TASK_WAKING.
Cure the second issue by not setting TASK_WAKING in sched_fork(), but only temporarily in wake_up_new_task() while calling select_task_rq().
Cure the first by holding rq->lock around the select_task_rq() call, this will disable IRQs, this however requires that we push down the rq->lock release into select_task_rq_fair()'s cgroup stuff.
Because select_task_rq_fair() still needs to drop the rq->lock we cannot fully get rid of TASK_WAKING.
LKML-Reference: <new-submission>
--- include/linux/sched.h | 3 +- kernel/sched.c | 65 +++++++++++++++++------------------------------- kernel/sched_fair.c | 8 ++++- kernel/sched_idletask.c | 3 +- kernel/sched_rt.c | 5 +-- 5 files changed, 36 insertions(+), 48 deletions(-)
include/linux/sched.h +2 -1
@@ -1082,7 +1082,8 @@ struct sched_class {void (*put_prev_task) (struct rq *rq,struct task_struct *p);#ifdef CONFIG_SMP -int (*select_task_rq)(struct task_struct *p,int sd_flag,int flags); +int (*select_task_rq)(struct rq *rq,struct task_struct *p, +int sd_flag,int flags); unsigned long (*load_balance) (struct rq *this_rq, int this_cpu, struct rq *busiest, unsigned long max_load_move,
kernel/sched.c +24 -41
128 lines not on this page · raw message
kernel/sched_fair.c +6 -2
@@ -1392,7 +1392,8 @@ find_idlest_cpu(struct sched_group *grou* * preempt must be disabled. */ -static int select_task_rq_fair (struct task_struct *p,int sd_flag,int wake_flags) +static int +select_task_rq_fair (struct rq *rq,struct task_struct *p,int sd_flag,int wake_flags) {struct sched_domain *tmp, *affine_sd =NULL , *sd =NULL ;int cpu =smp_processor_id ();
@@ -1492,8 +1493,11 @@ static int select_task_rq_fair(struct ta cpumask_weight(sched_domain_span(sd)))) tmp = affine_sd; -if (tmp) +if (tmp) { +spin_unlock (&rq->lock);update_shares (tmp); +spin_lock (&rq->lock); + } }if (affine_sd &&wake_affine (affine_sd, p, sync)) {
kernel/sched_idletask.c +2 -1
@@ -6,7 +6,8 @@*/ #ifdef CONFIG_SMP -static int select_task_rq_idle (struct task_struct *p,int sd_flag,int flags) +static int +select_task_rq_idle (struct rq *rq,struct task_struct *p,int sd_flag,int flags) {return task_cpu (p);/* IDLE tasks as never migrated */ }
kernel/sched_rt.c +2 -3
@@ -942,10 +942,9 @@ static void yield_task_rt(struct rq *rq)#ifdef CONFIG_SMP static int find_lowest_rq (struct task_struct *task); -static int select_task_rq_rt (struct task_struct *p,int sd_flag,int flags) +static int +select_task_rq_rt (struct rq *rq,struct task_struct *p,int sd_flag,int flags) { -struct rq *rq =task_rq (p); -if (sd_flag !=SD_BALANCE_WAKE )return smp_processor_id ();
PATCH 100/123 sched: Optimize task_rq_lock()
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit 65cc8e4859ff29a9ddc989c88557d6059834c2a2 upstream
Now that we hold the rq->lock over set_task_cpu() again, we can do away with most of the TASK_WAKING checks and reduce them again to set_cpus_allowed_ptr().
Removes some conditionals from scheduling hot-paths.
LKML-Reference: <new-submission>
--- kernel/sched.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-)
kernel/sched.c +15 -8
@@ -942,8 +942,8 @@ static inline void finish_lock_switch(st#endif /* __ARCH_WANT_UNLOCKED_CTXSW */ /* -* Check whether the task is waking, we use this to synchronize against -* ttwu() so that task_cpu() reports a stable number. +* Check whether the task is waking, we use this to synchronize ->cpus_allowed +* against ttwu(). */ static inline int task_is_waking (struct task_struct *p) {
@@ -960,11 +960,9 @@ static inline struct rq *__task_rq_lock(struct rq *rq;for (;;) { -while (task_is_waking (p)) -cpu_relax (); rq =task_rq (p);spin_lock (&rq->lock); -if (likely (rq ==task_rq (p) && !task_is_waking (p))) +if (likely (rq ==task_rq (p)))return rq;spin_unlock (&rq->lock); }
@@ -981,12 +979,10 @@ static struct rq *task_rq_lock(struct tastruct rq *rq;for (;;) { -while (task_is_waking (p)) -cpu_relax ();local_irq_save (*flags); rq =task_rq (p);spin_lock (&rq->lock); -if (likely (rq ==task_rq (p) && !task_is_waking (p))) +if (likely (rq ==task_rq (p)))return rq;spin_unlock_irqrestore (&rq->lock, *flags); }
@@ -7213,7 +7209,18 @@ int set_cpus_allowed_ptr(struct task_strstruct rq *rq;int ret =0 ; +/* +* Serialize against TASK_WAKING so that ttwu() and wunt() can +* drop the rq->lock and still rely on ->cpus_allowed. +*/ +again: +while (task_is_waking (p)) +cpu_relax (); rq =task_rq_lock (p, &flags); +if (task_is_waking (p)) { +task_rq_unlock (rq, &flags); + goto again; + }if (!cpumask_intersects (new_mask, cpu_active_mask)) { ret = -EINVAL ;
PATCH 101/123 sched: Fix nr_uninterruptible count
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit cc87f76a601d2d256118f7bab15e35254356ae21 upstream
The cpuload calculation in calc_load_account_active() assumes rq->nr_uninterruptible will not change on an offline cpu after migrate_nr_uninterruptible(). However the recent migrate on wakeup changes broke that and would result in decrementing the offline cpu's rq->nr_uninterruptible.
Fix this by accounting the nr_uninterruptible on the waking cpu.
LKML-Reference: <new-submission>
--- kernel/sched.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
kernel/sched.c +6 -2
@@ -2435,8 +2435,12 @@ static int try_to_wake_up(struct task_st* * First fix up the nr_uninterruptible count: */ -if (task_contributes_to_load (p)) - rq->nr_uninterruptible--; +if (task_contributes_to_load (p)) { +if (likely (cpu_online (orig_cpu))) + rq->nr_uninterruptible--; +else +this_rq ()->nr_uninterruptible--; + } p->state =TASK_WAKING ;if (p->sched_class->task_waking)
PATCH 102/123 sched: Fix rq->clock synchronization when migrating tasks
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit 861d034ee814917a83bd5de4b26e3b8336ddeeb8 upstream
sched_fork() -- we do task placement in ->task_fork_fair() ensure we
update_rq_clock() so we work with current time. We leave the vruntime in relative state, so the time delay until wake_up_new_task() doesn't matter.
wake_up_new_task() -- Since task_fork_fair() left p->vruntime in
relative state we can safely migrate, the activate_task() on the remote rq will call update_rq_clock() and causes the clock to be synced (enough).
LKML-Reference: <1281002322.1923.1708.camel@laptop>
--- kernel/sched_fair.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/sched_fair.c +2 -0
@@ -1963,6 +1963,8 @@ static void task_fork_fair(struct task_sspin_lock_irqsave (&rq->lock, flags); +update_rq_clock (rq); +if (unlikely (task_cpu (p) != this_cpu))__set_task_cpu (p, this_cpu);
PATCH 103/123 sched: Remove unnecessary RCU exclusion
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit fb58bac5c75bfff8bbf7d02071a10a62f32fe28b upstream
As Nick pointed out, and realized by myself when doing:
sched: Fix balance vs hotplug race
the patch:
sched: for_each_domain() vs RCU
is wrong, sched_domains are freed after synchronize_sched(), which means disabling preemption is enough.
LKML-Reference: <new-submission>
--- kernel/sched_fair.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-)
kernel/sched_fair.c +2 -7
@@ -1410,7 +1410,6 @@ select_task_rq_fair(struct rq *rq, struc new_cpu = prev_cpu; } -rcu_read_lock ();for_each_domain (cpu, tmp) {if (!(tmp->flags &SD_LOAD_BALANCE ))continue ;
@@ -1500,10 +1499,8 @@ select_task_rq_fair(struct rq *rq, struc } } -if (affine_sd &&wake_affine (affine_sd, p, sync)) { - new_cpu = cpu; - goto out; - } +if (affine_sd &&wake_affine (affine_sd, p, sync)) +return cpu;while (sd) {int load_idx = sd->forkexec_idx;
@@ -1544,8 +1541,6 @@ select_task_rq_fair(struct rq *rq, struc /* while loop will break here if sd == NULL */ } -out: -rcu_read_unlock ();return new_cpu; }#endif /* CONFIG_SMP */
PATCH 104/123 sched: apply RCU protection to wake_affine()
In reply to Greg KHFrom: Daniel J Blueman <[email protected]>
commit f3b577dec1f2ce32d2db6d2ca6badff7002512af upstream
The task_group() function returns a pointer that must be protected by either RCU, the ->alloc_lock, or the cgroup lock (see the rcu_dereference_check() in task_subsys_state(), which is invoked by task_group()). The wake_affine() function currently does none of these, which means that a concurrent update would be within its rights to free the structure returned by task_group(). Because wake_affine() uses this structure only to compute load-balancing heuristics, there is no reason to acquire either of the two locks.
Therefore, this commit introduces an RCU read-side critical section that starts before the first call to task_group() and ends after the last use of the "tg" pointer returned from task_group(). Thanks to Li Zefan for pointing out the need to extend the RCU read-side critical section from that proposed by the original patch.
--- kernel/sched_fair.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/sched_fair.c +2 -0
@@ -1250,6 +1250,7 @@ static int wake_affine(struct sched_doma* effect of the currently running task from the load * of the current CPU: */ +rcu_read_lock ();if (sync) { tg =task_group (current); weight = current->se.load.weight;
@@ -1275,6 +1276,7 @@ static int wake_affine(struct sched_doma balanced = !this_load ||100 *(this_load +effective_load (tg, this_cpu, weight, weight)) <= imbalance*(load +effective_load (tg, prev_cpu,0 , weight)); +rcu_read_unlock ();/* * If the currently running task will sleep within
PATCH 105/123 sched: Cleanup select_task_rq_fair()
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit a50bde5130f65733142b32975616427d0ea50856 upstream
Clean up the new affine to idle sibling bits while trying to grok them. Should not have any function differences.
LKML-Reference: <[email protected]>
--- kernel/sched_fair.c | 73 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 22 deletions(-)
kernel/sched_fair.c +51 -22
@@ -1384,6 +1384,41 @@ find_idlest_cpu(struct sched_group *grou }/* +* Try and locate an idle CPU in the sched_domain. +*/ +static int +select_idle_sibling (struct task_struct *p,struct sched_domain *sd,int target) +{ +int cpu =smp_processor_id (); +int prev_cpu =task_cpu (p); +int i; + +/* +* If this domain spans both cpu and prev_cpu (see the SD_WAKE_AFFINE +* test in select_task_rq_fair) and the prev_cpu is idle then that's +* always a better target than the current cpu. +*/ +if (target == cpu) { +if (!cpu_rq (prev_cpu)->cfs.nr_running) + target = prev_cpu; + } + +/* +* Otherwise, iterate the domain and find an elegible idle cpu. +*/ +if (target ==-1 || target == cpu) { +for_each_cpu_and (i,sched_domain_span (sd), &p->cpus_allowed) { +if (!cpu_rq (i)->cfs.nr_running) { + target = i; +break ; + } + } + } + +return target; +} + +/* * sched_balance_self: balance the current task (running on cpu) in domains * that have the 'flag' flag set. In practice, this is SD_BALANCE_FORK and * SD_BALANCE_EXEC.
@@ -1441,36 +1476,30 @@ select_task_rq_fair(struct rq *rq, struc }if (want_affine && (tmp->flags &SD_WAKE_AFFINE )) { -int candidate =-1 , i; +int target =-1 ; +/* +* If both cpu and prev_cpu are part of this domain, +* cpu is a valid SD_WAKE_AFFINE target. +*/ if (cpumask_test_cpu (prev_cpu,sched_domain_span (tmp))) - candidate = cpu; + target = cpu;/* -* Check for an idle shared cache. +* If there's an idle sibling in this domain, make that +* the wake_affine target instead of the current cpu. +* +* XXX: should we possibly do this outside of +* WAKE_AFFINE, in case the shared cache domain is +* smaller than the WAKE_AFFINE domain? */ -if (tmp->flags &SD_PREFER_SIBLING ) { -if (candidate == cpu) { -if (!cpu_rq (prev_cpu)->cfs.nr_running) - candidate = prev_cpu; - } - -if (candidate ==-1 || candidate == cpu) { -for_each_cpu (i,sched_domain_span (tmp)) { -if (!cpumask_test_cpu (i, &p->cpus_allowed)) -continue ; -if (!cpu_rq (i)->cfs.nr_running) { - candidate = i; -break ; - } - } - } - } +if (tmp->flags &SD_PREFER_SIBLING ) + target =select_idle_sibling (p, tmp, target); -if (candidate >=0 ) { +if (target >=0 ) { affine_sd = tmp; want_affine =0 ; - cpu = candidate; + cpu = target; } }
PATCH 106/123 sched: More generic WAKE_AFFINE vs select_idle_sibling()
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit fe3bcfe1f6c1fc4ea7706ac2d05e579fd9092682 upstream
Instead of only considering SD_WAKE_AFFINE | SD_PREFER_SIBLING domains also allow all SD_PREFER_SIBLING domains below a SD_WAKE_AFFINE domain to change the affinity target.
LKML-Reference: <[email protected]>
--- kernel/sched_fair.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-)
kernel/sched_fair.c +16 -17
@@ -1398,20 +1398,16 @@ select_idle_sibling(struct task_struct ** test in select_task_rq_fair) and the prev_cpu is idle then that's * always a better target than the current cpu. */ -if (target == cpu) { -if (!cpu_rq (prev_cpu)->cfs.nr_running) - target = prev_cpu; - } +if (target == cpu && !cpu_rq (prev_cpu)->cfs.nr_running) +return prev_cpu;/* * Otherwise, iterate the domain and find an elegible idle cpu. */ -if (target ==-1 || target == cpu) { -for_each_cpu_and (i,sched_domain_span (sd), &p->cpus_allowed) { -if (!cpu_rq (i)->cfs.nr_running) { - target = i; -break ; - } +for_each_cpu_and (i,sched_domain_span (sd), &p->cpus_allowed) { +if (!cpu_rq (i)->cfs.nr_running) { + target = i; +break ; } }
@@ -1475,7 +1471,12 @@ select_task_rq_fair(struct rq *rq, struc want_sd =0 ; } -if (want_affine && (tmp->flags &SD_WAKE_AFFINE )) { +/* +* While iterating the domains looking for a spanning +* WAKE_AFFINE domain, adjust the affine target to any idle cpu +* in cache sharing domains along the way. +*/ +if (want_affine) {int target =-1 ;/*
@@ -1488,17 +1489,15 @@ select_task_rq_fair(struct rq *rq, struc/* * If there's an idle sibling in this domain, make that * the wake_affine target instead of the current cpu. -* -* XXX: should we possibly do this outside of -* WAKE_AFFINE, in case the shared cache domain is -* smaller than the WAKE_AFFINE domain? */ if (tmp->flags &SD_PREFER_SIBLING ) target =select_idle_sibling (p, tmp, target);if (target >=0 ) { - affine_sd = tmp; - want_affine =0 ; +if (tmp->flags &SD_WAKE_AFFINE ) { + affine_sd = tmp; + want_affine =0 ; + } cpu = target; } }
PATCH 107/123 sched: Fix vmark regression on big machines
In reply to Greg KHFrom: Mike Galbraith <[email protected]>
commit 50b926e439620c469565e8be0f28be78f5fca1ce upstream
SD_PREFER_SIBLING is set at the CPU domain level if power saving isn't enabled, leading to many cache misses on large machines as we traverse looking for an idle shared cache to wake to. Change the enabler of select_idle_sibling() to SD_SHARE_PKG_RESOURCES, and enable same at the sibling domain level.
LKML-Reference: <[email protected]>
--- include/linux/topology.h | 2 +- kernel/sched_fair.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
include/linux/topology.h +1 -1
@@ -99,7 +99,7 @@ int arch_update_cpu_topology(void); | 1*SD_WAKE_AFFINE \ |1 *SD_SHARE_CPUPOWER \ |0 *SD_POWERSAVINGS_BALANCE \ - |0 *SD_SHARE_PKG_RESOURCES \ + |1 *SD_SHARE_PKG_RESOURCES \ |0 *SD_SERIALIZE \ |0 *SD_PREFER_SIBLING \ , \
kernel/sched_fair.c +1 -1
@@ -1490,7 +1490,7 @@ select_task_rq_fair(struct rq *rq, struc* If there's an idle sibling in this domain, make that * the wake_affine target instead of the current cpu. */ -if (tmp->flags &SD_PREFER_SIBLING ) +if (tmp->flags &SD_SHARE_PKG_RESOURCES ) target =select_idle_sibling (p, tmp, target);if (target >=0 ) {
PATCH 108/123 sched: Fix select_idle_sibling()
In reply to Greg KHFrom: Mike Galbraith <[email protected]>
commit 8b911acdf08477c059d1c36c21113ab1696c612b upstream
Don't bother with selection when the current cpu is idle. Recent load balancing changes also make it no longer necessary to check wake_affine() success before returning the selected sibling, so we now always use it.
LKML-Reference: <[email protected]>
--- kernel/sched_fair.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
kernel/sched_fair.c +10 -4
@@ -1432,7 +1432,7 @@ select_task_rq_fair(struct rq *rq, strucint cpu =smp_processor_id ();int prev_cpu =task_cpu (p);int new_cpu = cpu; -int want_affine =0 ; +int want_affine =0 , cpu_idle = !current->pid;int want_sd =1 ;int sync = wake_flags &WF_SYNC ;
@@ -1490,13 +1490,15 @@ select_task_rq_fair(struct rq *rq, struc* If there's an idle sibling in this domain, make that * the wake_affine target instead of the current cpu. */ -if (tmp->flags &SD_SHARE_PKG_RESOURCES ) +if (!cpu_idle && tmp->flags &SD_SHARE_PKG_RESOURCES ) target =select_idle_sibling (p, tmp, target);if (target >=0 ) {if (tmp->flags &SD_WAKE_AFFINE ) { affine_sd = tmp; want_affine =0 ; +if (target != cpu) + cpu_idle =1 ; } cpu = target; }
@@ -1512,6 +1514,7 @@ select_task_rq_fair(struct rq *rq, struc sd = tmp; } +#ifdef CONFIG_FAIR_GROUP_SCHED if (sched_feat (LB_SHARES_UPDATE )) {/* * Pick the largest domain to update shares over
@@ -1528,9 +1531,12 @@ select_task_rq_fair(struct rq *rq, struc spin_lock(&rq->lock); } } +#endif -if (affine_sd &&wake_affine (affine_sd, p, sync)) -return cpu; +if (affine_sd) { +if (cpu_idle || cpu == prev_cpu ||wake_affine (affine_sd, p, sync)) +return cpu; + }while (sd) {int load_idx = sd->forkexec_idx;
PATCH 109/123 sched: Pre-compute cpumask_weight(sched_domain_span(sd))
In reply to Greg KHFrom: Peter Zijlstra <[email protected]>
commit 669c55e9f99b90e46eaa0f98a67ec53d46dc969a upstream
Dave reported that his large SPARC machines spend lots of time in hweight64(), try and optimize some of those needless cpumask_weight() invocations (esp. with the large offstack cpumasks these are very expensive indeed).
LKML-Reference: <new-submission>
--- include/linux/sched.h | 1 + kernel/sched.c | 7 +++++-- kernel/sched_fair.c | 8 +++----- 3 files changed, 9 insertions(+), 7 deletions(-)
include/linux/sched.h +1 -0
@@ -1000,6 +1000,7 @@ struct sched_domain {char *name;#endif +unsigned int span_weight;/* * Span of all CPUs in this domain. *
kernel/sched.c +5 -2
@@ -3678,7 +3678,7 @@ unsigned long __weak arch_scale_freq_powunsigned long default_scale_smt_power (struct sched_domain *sd,int cpu) { -unsigned long weight =cpumask_weight (sched_domain_span (sd)); +unsigned long weight = sd->span_weight;unsigned long smt_gain = sd->smt_gain; smt_gain /= weight;
@@ -3711,7 +3711,7 @@ unsigned long scale_rt_power(int cpu)static void update_cpu_power (struct sched_domain *sd,int cpu) { -unsigned long weight =cpumask_weight (sched_domain_span (sd)); +unsigned long weight = sd->span_weight;unsigned long power =SCHED_LOAD_SCALE ;struct sched_group *sdg = sd->groups;
@@ -8166,6 +8166,9 @@ cpu_attach_domain(struct sched_domain *sstruct rq *rq =cpu_rq (cpu);struct sched_domain *tmp; +for (tmp = sd; tmp; tmp = tmp->parent) + tmp->span_weight =cpumask_weight (sched_domain_span (tmp)); +/* Remove the sched domains which do not contribute to scheduling. */ for (tmp = sd; tmp; ) {struct sched_domain *parent = tmp->parent;
kernel/sched_fair.c +3 -5
@@ -1520,9 +1520,7 @@ select_task_rq_fair(struct rq *rq, struc* Pick the largest domain to update shares over */ tmp = sd; -if (affine_sd && (!tmp || -cpumask_weight (sched_domain_span (affine_sd)) > -cpumask_weight (sched_domain_span (sd)))) +if (affine_sd && (!tmp || affine_sd->span_weight > sd->span_weight)) tmp = affine_sd;if (tmp) {
@@ -1566,10 +1564,10 @@ select_task_rq_fair(struct rq *rq, struc/* Now try balancing at a lower domain level of new_cpu */ cpu = new_cpu; - weight =cpumask_weight (sched_domain_span (sd)); + weight = sd->span_weight; sd =NULL ;for_each_domain (cpu, tmp) { -if (weight <=cpumask_weight (sched_domain_span (tmp))) +if (weight <= tmp->span_weight)break ;if (tmp->flags & sd_flag) sd = tmp;
PATCH 110/123 sched: Fix select_idle_sibling() logic in select_task_rq_fair()
In reply to Greg KHFrom: Suresh Siddha <[email protected]>
commit 99bd5e2f245d8cd17d040c82d40becdb3efd9b69 upstream
Issues in the current select_idle_sibling() logic in select_task_rq_fair() in the context of a task wake-up:
a) Once we select the idle sibling, we use that domain (spanning the cpu that the task is currently woken-up and the idle sibling that we found) in our wake_affine() decisions. This domain is completely different from the domain(we are supposed to use) that spans the cpu that the task currently woken-up and the cpu where the task previously ran.
b) We do select_idle_sibling() check only for the cpu that the task is currently woken-up on. If select_task_rq_fair() selects the previously run cpu for waking the task, doing a select_idle_sibling() check for that cpu also helps and we don't do this currently.
c) In the scenarios where the cpu that the task is woken-up is busy but with its HT siblings are idle, we are selecting the task be woken-up on the idle HT sibling instead of a core that it previously ran and currently completely idle. i.e., we are not taking decisions based on wake_affine() but directly selecting an idle sibling that can cause an imbalance at the SMT/MC level which will be later corrected by the periodic load balancer.
Fix this by first going through the load imbalance calculations using wake_affine() and once we make a decision of woken-up cpu vs previously-ran cpu, then choose a possible idle sibling for waking up the task on.
LKML-Reference: <[email protected]>
--- kernel/sched_fair.c | 82 +++++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 42 deletions(-)
kernel/sched_fair.c +40 -42
@@ -1386,29 +1386,48 @@ find_idlest_cpu(struct sched_group *grou/* * Try and locate an idle CPU in the sched_domain. */ -static int -select_idle_sibling (struct task_struct *p,struct sched_domain *sd,int target) +static int select_idle_sibling (struct task_struct *p,int target) {int cpu =smp_processor_id ();int prev_cpu =task_cpu (p); +struct sched_domain *sd;int i;/* -* If this domain spans both cpu and prev_cpu (see the SD_WAKE_AFFINE -* test in select_task_rq_fair) and the prev_cpu is idle then that's -* always a better target than the current cpu. +* If the task is going to be woken-up on this cpu and if it is +* already idle, then it is the right target. +*/ +if (target == cpu &&idle_cpu (cpu)) +return cpu; + +/* +* If the task is going to be woken-up on the cpu where it previously +* ran and if it is currently idle, then it the right target. */ -if (target == cpu && !cpu_rq (prev_cpu)->cfs.nr_running) +if (target == prev_cpu &&idle_cpu (prev_cpu))return prev_cpu;/* -* Otherwise, iterate the domain and find an elegible idle cpu. +* Otherwise, iterate the domains and find an elegible idle cpu. */ -for_each_cpu_and (i,sched_domain_span (sd), &p->cpus_allowed) { -if (!cpu_rq (i)->cfs.nr_running) { - target = i; +for_each_domain (target, sd) { +if (!(sd->flags &SD_SHARE_PKG_RESOURCES ))break ; + +for_each_cpu_and (i,sched_domain_span (sd), &p->cpus_allowed) { +if (idle_cpu (i)) { + target = i; +break ; + } } + +/* +* Lets stop looking for an idle sibling when we reached +* the domain that spans the current cpu and prev_cpu. +*/ +if (cpumask_test_cpu (cpu,sched_domain_span (sd)) && +cpumask_test_cpu (prev_cpu,sched_domain_span (sd))) +break ; }return target;
@@ -1432,7 +1451,7 @@ select_task_rq_fair(struct rq *rq, strucint cpu =smp_processor_id ();int prev_cpu =task_cpu (p);int new_cpu = cpu; -int want_affine =0 , cpu_idle = !current->pid; +int want_affine =0 ;int want_sd =1 ;int sync = wake_flags &WF_SYNC ;
@@ -1472,36 +1491,13 @@ select_task_rq_fair(struct rq *rq, struc }/* -* While iterating the domains looking for a spanning -* WAKE_AFFINE domain, adjust the affine target to any idle cpu -* in cache sharing domains along the way. +* If both cpu and prev_cpu are part of this domain, +* cpu is a valid SD_WAKE_AFFINE target. */ -if (want_affine) { -int target =-1 ; - -/* -* If both cpu and prev_cpu are part of this domain, -* cpu is a valid SD_WAKE_AFFINE target. -*/ -if (cpumask_test_cpu (prev_cpu,sched_domain_span (tmp))) - target = cpu; - -/* -* If there's an idle sibling in this domain, make that -* the wake_affine target instead of the current cpu. -*/ -if (!cpu_idle && tmp->flags &SD_SHARE_PKG_RESOURCES ) - target =select_idle_sibling (p, tmp, target); - -if (target >=0 ) { -if (tmp->flags &SD_WAKE_AFFINE ) { - affine_sd = tmp; - want_affine =0 ; -if (target != cpu) - cpu_idle =1 ; - } - cpu = target; - } +if (want_affine && (tmp->flags &SD_WAKE_AFFINE ) && +cpumask_test_cpu (prev_cpu,sched_domain_span (tmp))) { + affine_sd = tmp; + want_affine =0 ; }if (!want_sd && !want_affine)
@@ -1532,8 +1528,10 @@ select_task_rq_fair(struct rq *rq, struc#endif if (affine_sd) { -if (cpu_idle || cpu == prev_cpu ||wake_affine (affine_sd, p, sync)) -return cpu; +if (cpu == prev_cpu ||wake_affine (affine_sd, p, sync)) +return select_idle_sibling (p, cpu); +else +return select_idle_sibling (p, prev_cpu); }while (sd) {
PATCH 111/123 sched: cpuacct: Use bigger percpu counter batch values for stats counters
In reply to Greg KHFrom: Anton Blanchard <[email protected]>
commit fa535a77bd3fa32b9215ba375d6a202fe73e1dd6 upstream
When CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT are enabled we can call cpuacct_update_stats with values much larger than percpu_counter_batch. This means the call to percpu_counter_add will always add to the global count which is protected by a spinlock and we end up with a global spinlock in the scheduler.
Based on an idea by KOSAKI Motohiro, this patch scales the batch value by cputime_one_jiffy such that we have the same batch limit as we would if CONFIG_VIRT_CPU_ACCOUNTING was disabled. His patch did this once at boot but that initialisation happened too early on PowerPC (before time_init) and it was never updated at runtime as a result of a hotplug cpu add/remove.
This patch instead scales percpu_counter_batch by cputime_one_jiffy at runtime, which keeps the batch correct even after cpu hotplug operations. We cap it at INT_MAX in case of overflow.
For architectures that do not support CONFIG_VIRT_CPU_ACCOUNTING, cputime_one_jiffy is the constant 1 and gcc is smart enough to optimise min(s32 percpu_counter_batch, INT_MAX) to just percpu_counter_batch at least on x86 and PowerPC. So there is no need to add an #ifdef.
On a 64 thread PowerPC box with CONFIG_VIRT_CPU_ACCOUNTING and CONFIG_CGROUP_CPUACCT enabled, a context switch microbenchmark is 234x faster and almost matches a CONFIG_CGROUP_CPUACCT disabled kernel:
CONFIG_CGROUP_CPUACCT disabled: 16906698 ctx switches/sec
CONFIG_CGROUP_CPUACCT enabled: 61720 ctx switches/sec
CONFIG_CGROUP_CPUACCT + patch: 16663217 ctx switches/sec
Tested with:
wget http://ozlabs.org/~anton/junkcode/context_switch.c
make context_switch
for i in seq 0 63; do taskset -c $i ./context_switch & done vmstat 1
--- kernel/sched.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
kernel/sched.c +19 -1
@@ -10934,12 +10934,30 @@ static void cpuacct_charge(struct task_s }/* +* When CONFIG_VIRT_CPU_ACCOUNTING is enabled one jiffy can be very large +* in cputime_t units. As a result, cpuacct_update_stats calls +* percpu_counter_add with values large enough to always overflow the +* per cpu batch limit causing bad SMP scalability. +* +* To fix this we scale percpu_counter_batch by cputime_one_jiffy so we +* batch the same amount of time with CONFIG_VIRT_CPU_ACCOUNTING disabled +* and enabled. We cap it at INT_MAX which is the largest allowed batch value. +*/ +#ifdef CONFIG_SMP +#define CPUACCT_BATCH \ + min_t(long, percpu_counter_batch * cputime_one_jiffy, INT_MAX) +#else +#define CPUACCT_BATCH 0 +#endif + +/* * Charge the system/user time to the task's accounting group. */ static void cpuacct_update_stats (struct task_struct *tsk,enum cpuacct_stat_index idx,cputime_t val) {struct cpuacct *ca; +int batch =CPUACCT_BATCH ;if (unlikely (!cpuacct_subsys.active))return ;
@@ -10948,7 +10966,7 @@ static void cpuacct_update_stats(struct ca =task_ca (tsk);do { -percpu_counter_add (&ca->cpustat[idx], val); +__percpu_counter_add (&ca->cpustat[idx], val, batch); ca = ca->parent; }while (ca);rcu_read_unlock ();
PATCH 112/123 ALSA: hda - Handle missing NID 0x1b on ALC259 codec
In reply to Greg KHFrom: Takashi Iwai <[email protected]>
commit 5d4abf93ea3192cc666430225a29a4978c97c57d upstream.
Since ALC259/269 use the same parser of ALC268, the pin 0x1b was ignored as an invalid widget. Just add this NID to handle properly. This will add the missing mixer controls for some devices.
--- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+)
sound/pci/hda/patch_realtek.c +1 -0
@@ -12389,6 +12389,7 @@ static int alc268_new_analog_output(stru dac =0x02 ;break ;case 0x15 : +case 0x1b :case 0x21 :/* ALC269vb has this pin, too */ dac =0x03 ;break ;
PATCH 113/123 ALSA: hda - Handle pin NID 0x1a on ALC259/269
In reply to Greg KHFrom: Takashi Iwai <[email protected]>
commit b08b1637ce1c0196970348bcabf40f04b6b3d58e upstream.
The pin NID 0x1a should be handled as well as NID 0x1b. Also added comments.
--- sound/pci/hda/patch_realtek.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
sound/pci/hda/patch_realtek.c +2 -1
@@ -12389,7 +12389,8 @@ static int alc268_new_analog_output(stru dac =0x02 ;break ;case 0x15 : -case 0x1b : +case 0x1a :/* ALC259/269 only */ +case 0x1b :/* ALC259/269 only */ case 0x21 :/* ALC269vb has this pin, too */ dac =0x03 ;break ;
PATCH 114/123 arm: fix really nasty sigreturn bug
In reply to Greg KHFrom: Al Viro <[email protected]>
commit 653d48b22166db2d8b1515ebe6f9f0f7c95dfc86 upstream.
If a signal hits us outside of a syscall and another gets delivered when we are in sigreturn (e.g. because it had been in sa_mask for the first one and got sent to us while we'd been in the first handler), we have a chance of returning from the second handler to location one insn prior to where we ought to return. If r0 happens to contain -513 (-ERESTARTNOINTR), sigreturn will get confused into doing restart syscall song and dance.
Incredible joy to debug, since it manifests as random, infrequent and very hard to reproduce double execution of instructions in userland code...
The fix is simple - mark it "don't bother with restarts" in wrapper, i.e. set r8 to 0 in sys_sigreturn and sys_rt_sigreturn wrappers, suppressing the syscall restart handling on return from these guys. They can't legitimately return a restart-worthy error anyway.
Testcase:
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/time.h>
#include <errno.h>
void f(int n)
{
__asm__ __volatile__(
"ldr r0, [%0]\n"
"b 1f\n"
"b 2f\n"
"1:b .\n"
"2:\n" : : "r"(&n));
}
void handler1(int sig) { }
void handler2(int sig) { raise(1); }
void handler3(int sig) { exit(0); }
main()
{
struct sigaction s = {.sa_handler = handler2};
struct itimerval t1 = { .it_value = {1} };
struct itimerval t2 = { .it_value = {2} };
signal(1, handler1);
sigemptyset(&s.sa_mask);
sigaddset(&s.sa_mask, 1);
sigaction(SIGALRM, &s, NULL);
signal(SIGVTALRM, handler3);
setitimer(ITIMER_REAL, &t1, NULL);
setitimer(ITIMER_VIRTUAL, &t2, NULL);
f(-513); /* -ERESTARTNOINTR */
write(1, "buggered\n", 9);
return 1;
}--- arch/arm/kernel/entry-common.S | 2 ++ 1 file changed, 2 insertions(+)
arch/arm/kernel/entry-common.S +2 -0
@@ -382,11 +382,13 @@ ENDPROC(sys_clone_wrapper) sys_sigreturn_wrapper: add r0, sp, #S_OFF + mov why, #0 @ prevent syscall restart handling b sys_sigreturn ENDPROC(sys_sigreturn_wrapper) sys_rt_sigreturn_wrapper: add r0, sp, #S_OFF + mov why, #0 @ prevent syscall restart handling b sys_rt_sigreturn ENDPROC(sys_rt_sigreturn_wrapper)
PATCH 115/123 hwmon: (f75375s) Shift control mode to the correct bit position
In reply to Greg KHFrom: Guillem Jover <[email protected]>
commit 96f3640894012be7dd15a384566bfdc18297bc6c upstream.
The spec notes that fan0 and fan1 control mode bits are located in bits 7-6 and 5-4 respectively, but the FAN_CTRL_MODE macro was making the bits shift by 5 instead of by 4.
--- drivers/hwmon/f75375s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/f75375s.c +1 -1
@@ -79,7 +79,7 @@ I2C_CLIENT_INSMOD_2(f75373, f75375);#define F75375_REG_PWM2_DROP_DUTY 0x6C#define FAN_CTRL_LINEAR (nr) (4 + nr) -#define FAN_CTRL_MODE (nr) (5 + ((nr) * 2)) +#define FAN_CTRL_MODE (nr) (4 + ((nr) * 2))/* * Data structures and manipulation thereof
PATCH 116/123 hwmon: (f75375s) Do not overwrite values read from registers
In reply to Greg KHFrom: Guillem Jover <[email protected]>
commit c3b327d60bbba3f5ff8fd87d1efc0e95eb6c121b upstream.
All bits in the values read from registers to be used for the next write were getting overwritten, avoid doing so to not mess with the current configuration.
--- drivers/hwmon/f75375s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/hwmon/f75375s.c +2 -2
@@ -298,7 +298,7 @@ static int set_pwm_enable_direct(structreturn -EINVAL ; fanmode =f75375_read8 (client,F75375_REG_FAN_TIMER ); - fanmode = ~(3 <<FAN_CTRL_MODE (nr)); + fanmode &= ~(3 <<FAN_CTRL_MODE (nr));switch (val) {case 0 :/* Full speed */
@@ -350,7 +350,7 @@ static ssize_t set_pwm_mode(struct devicmutex_lock (&data->update_lock); conf =f75375_read8 (client,F75375_REG_CONFIG1 ); - conf = ~(1 <<FAN_CTRL_LINEAR (nr)); + conf &= ~(1 <<FAN_CTRL_LINEAR (nr));if (val ==0 ) conf |= (1 <<FAN_CTRL_LINEAR (nr)) ;
PATCH 117/123 apm_power: Add missing break statement
In reply to Greg KHFrom: Anton Vorontsov <[email protected]>
commit 1d220334d6a8a711149234dc5f98d34ae02226b8 upstream.
The missing break statement causes wrong capacity calculation for batteries that report energy.
--- drivers/power/apm_power.c | 1 + 1 file changed, 1 insertion(+)
drivers/power/apm_power.c +1 -0
@@ -233,6 +233,7 @@ static int calculate_capacity(enum apm_s empty_design_prop =POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN ; now_prop =POWER_SUPPLY_PROP_ENERGY_NOW ; avg_prop =POWER_SUPPLY_PROP_ENERGY_AVG ; +break ;case SOURCE_VOLTAGE : full_prop =POWER_SUPPLY_PROP_VOLTAGE_MAX ; empty_prop =POWER_SUPPLY_PROP_VOLTAGE_MIN ;
PATCH 118/123 NFS: Fix a typo in nfs_sockaddr_match_ipaddr6
In reply to Greg KHFrom: Trond Myklebust <[email protected]>
commit b20d37ca9561711c6a3c4b859c2855f49565e061 upstream.
--- fs/nfs/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfs/client.c +1 -1
@@ -273,7 +273,7 @@ static int nfs_sockaddr_match_ipaddr6(co sin1->sin6_scope_id != sin2->sin6_scope_id)return 0 ; -return ipv6_addr_equal (&sin1->sin6_addr, &sin1->sin6_addr); +return ipv6_addr_equal (&sin1->sin6_addr, &sin2->sin6_addr); }#else /* !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) */ static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1,
PATCH 119/123 SUNRPC: Fix race corrupting rpc upcall
In reply to Greg KHFrom: Trond Myklebust <[email protected]>
commit 5a67657a2e90c9e4a48518f95d4ba7777aa20fbb upstream.
If rpc_queue_upcall() adds a new upcall to the rpci->pipe list just after rpc_pipe_release calls rpc_purge_list(), but before it calls gss_pipe_release (as rpci->ops->release_pipe(inode)), then the latter will free a message without deleting it from the rpci->pipe list.
We will be left with a freed object on the rpc->pipe list. Most frequent symptoms are kernel crashes in rpc.gssd system calls on the pipe in question.
--- net/sunrpc/auth_gss/auth_gss.c | 9 +++++---- net/sunrpc/rpc_pipe.c | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-)
net/sunrpc/auth_gss/auth_gss.c +5 -4
@@ -717,17 +717,18 @@ gss_pipe_release(struct inode *inode)struct rpc_inode *rpci =RPC_I (inode);struct gss_upcall_msg *gss_msg; +restart:spin_lock (&inode->i_lock); -while (!list_empty (&rpci->in_downcall)) { +list_for_each_entry (gss_msg, &rpci->in_downcall, list) { - gss_msg =list_entry (rpci->in_downcall.next, - struct gss_upcall_msg, list); +if (!list_empty (&gss_msg->msg.list)) +continue ; gss_msg->msg.errno = -EPIPE ;atomic_inc (&gss_msg->count);__gss_unhash_msg (gss_msg);spin_unlock (&inode->i_lock);gss_release_msg (gss_msg); -spin_lock (&inode->i_lock); + goto restart; }spin_unlock (&inode->i_lock);
net/sunrpc/rpc_pipe.c +3 -3
@@ -47,7 +47,7 @@ static void rpc_purge_list(struct rpc_inreturn ;do { msg = list_entry(head->next, struct rpc_pipe_msg, list); -list_del (&msg->list); +list_del_init (&msg->list); msg->errno = err;destroy_msg (msg); }while (!list_empty (head));
@@ -207,7 +207,7 @@ rpc_pipe_release(struct inode *inode, stif (msg !=NULL ) {spin_lock (&inode->i_lock); msg->errno = -EAGAIN ; -list_del (&msg->list); +list_del_init (&msg->list);spin_unlock (&inode->i_lock); rpci->ops->destroy_msg (msg); }
@@ -267,7 +267,7 @@ rpc_pipe_read(struct file *filp, char __if (res <0 || msg->len == msg->copied) { filp->private_data =NULL ;spin_lock (&inode->i_lock); -list_del (&msg->list); +list_del_init (&msg->list);spin_unlock (&inode->i_lock); rpci->ops->destroy_msg (msg); }
PATCH 120/123 i915: return -EFAULT if copy_to_user fails
In reply to Greg KHFrom: Dan Carpenter <[email protected]>
commit 9927a403ca8c97798129953fa9cbb5dc259c7cb9 upstream.
copy_to_user returns the number of bytes remaining to be copied, but we want to return a negative error code here. These are returned to userspace.
--- drivers/gpu/drm/i915/i915_dma.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
drivers/gpu/drm/i915/i915_dma.c +9 -3
@@ -683,8 +683,10 @@ static int i915_batchbuffer(struct drm_d ret =copy_from_user (cliprects, batch->cliprects, batch->num_cliprects *sizeof (struct drm_clip_rect )); -if (ret !=0 ) +if (ret !=0 ) { + ret = -EFAULT ; goto fail_free; + } }mutex_lock (&dev->struct_mutex);
@@ -725,8 +727,10 @@ static int i915_cmdbuffer(struct drm_devreturn -ENOMEM ; ret =copy_from_user (batch_data, cmdbuf->buf, cmdbuf->sz); -if (ret !=0 ) +if (ret !=0 ) { + ret = -EFAULT ; goto fail_batch_free; + }if (cmdbuf->num_cliprects) { cliprects = kcalloc(cmdbuf->num_cliprects,
@@ -737,8 +741,10 @@ static int i915_cmdbuffer(struct drm_dev ret =copy_from_user (cliprects, cmdbuf->cliprects, cmdbuf->num_cliprects *sizeof (struct drm_clip_rect )); -if (ret !=0 ) +if (ret !=0 ) { + ret = -EFAULT ; goto fail_clip_free; + } }mutex_lock (&dev->struct_mutex);
PATCH 121/123 i915_gem: return -EFAULT if copy_to_user fails
In reply to Greg KHFrom: Dan Carpenter <[email protected]>
commit c877cdce93a44eea96f6cf7fc04be7d0372db2be upstream.
copy_to_user() returns the number of bytes remaining to be copied and I'm pretty sure we want to return a negative error code here.
--- drivers/gpu/drm/i915/i915_gem.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/i915/i915_gem.c +1 -0
@@ -3667,6 +3667,7 @@ i915_gem_execbuffer(struct drm_device *dif (ret !=0 ) {DRM_ERROR ("copy %d cliprects failed: %d\n" , args->num_cliprects, ret); + ret = -EFAULT ; goto pre_mutex_err; } }
PATCH 122/123 drm/i915: Prevent double dpms on
In reply to Greg KHFrom: Chris Wilson <[email protected]>
commit 032d2a0d068b0368296a56469761394ef03207c3 upstream.
Arguably this is a bug in drm-core in that we should not be called twice in succession with DPMS_ON, however this is still occuring and we see FDI link training failures on the second call leading to the occassional blank display. For the time being ignore the repeated call.
Original patch by Dave Airlie <[email protected]>
--- drivers/gpu/drm/i915/intel_display.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/intel_display.c +4 -1
@@ -1954,6 +1954,9 @@ static void intel_crtc_dpms(struct drm_cint pipe = intel_crtc->pipe;bool enabled; +if (intel_crtc->dpms_mode == mode) +return ; + dev_priv->display.dpms (crtc, mode); intel_crtc->dpms_mode = mode;
@@ -4000,7 +4003,7 @@ static void intel_crtc_init(struct drm_d } intel_crtc->cursor_addr =0 ; - intel_crtc->dpms_mode =DRM_MODE_DPMS_OFF ; + intel_crtc->dpms_mode =-1 ;drm_crtc_helper_add (&intel_crtc->base, &intel_helper_funcs); intel_crtc->busy = false;
PATCH 123/123 drm: Only decouple the old_fb from the crtc is we call mode_set*
In reply to Greg KHFrom: Chris Wilson <[email protected]>
commit 356ad3cd616185631235ffb48b3efbf39f9923b3 upstream.
Otherwise when disabling the output we switch to the new fb (which is likely NULL) and skip the call to mode_set -- leaking driver private state on the old_fb.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=29857
--- drivers/gpu/drm/drm_crtc_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/drm_crtc_helper.c +2 -2
@@ -925,13 +925,13 @@ int drm_crtc_helper_set_config(struct dr mode_changed = true;if (mode_changed) { - old_fb = set->crtc->fb; - set->crtc->fb = set->fb; set->crtc->enabled = (set->mode !=NULL );if (set->mode !=NULL ) {DRM_DEBUG_KMS ("attempting to set mode from" " userspace\n" );drm_mode_debug_printmodeline (set->mode); + old_fb = set->crtc->fb; + set->crtc->fb = set->fb;if (!drm_crtc_helper_set_mode (set->crtc, set->mode, set->x, set->y, old_fb)) {
Hi Greg,
Quoted 5 lines · Greg KH
[Note, I do still have patches that people have sent me for inclusion in the .32-stable tree in my queue, but I figured this series was already big enough that it should go out now. If you notice, I _did_ apply all patches that went through Linus's tree with a [email protected] marking on it, so people might consider using that method instead...]
I'll give this a try, however I really miss the tcp_collapse() fix (baff42ab1494528907bf4d5870359e31711746ae) without which 2.6.32.21 panics several times a day when using splice().
I don't know if Davem had time to forward it to you though.
Regards,
Willy
Quoted 9 lines · Willy Tarreau
Hi Greg,
Quoted 5 lines · Greg KH
[Note, I do still have patches that people have sent me for inclusion in the .32-stable tree in my queue, but I figured this series was already big enough that it should go out now. If you notice, I _did_ apply all patches that went through Linus's tree with a [email protected] marking on it, so people might consider using that method instead...]
Quoted 5 lines
I'll give this a try, however I really miss the
tcp_collapse()fix (baff42ab1494528907bf4d5870359e31711746ae) without which 2.6.32.21 panics several times a day when usingsplice().I don't know if Davem had time to forward it to you though.
He has not done so yet. I think this is a big enough series for now this releaase :)
thanks,
greg k-h
Quoted 10 lines · Greg KH
Quoted 9 lines · Willy Tarreau
Hi Greg,
Quoted 5 lines · Greg KH
[Note, I do still have patches that people have sent me for inclusion in the .32-stable tree in my queue, but I figured this series was already big enough that it should go out now. If you notice, I _did_ apply all patches that went through Linus's tree with a [email protected] marking on it, so people might consider using that method instead...]
Quoted 8 lines
Quoted 5 lines
I'll give this a try, however I really miss the
tcp_collapse()fix (baff42ab1494528907bf4d5870359e31711746ae) without which 2.6.32.21 panics several times a day when usingsplice().I don't know if Davem had time to forward it to you though.
He has not done so yet. I think this is a big enough series for now this releaase :)
Yes, I certainly share your concerns with the size of the release. I just wanted to ensure we don't delay that fix too much because it's always very embarrassing to have a userland triggerable panic. I've seen David's mail so I assume we'll have that in .23 which is fine.
Thanks,
Willy
David Miller
maintainerFrom: Willy Tarreau <[email protected]>
Date: Sat, 18 Sep 2010 23:39:30 +0200
Quoted 9 lines
Hi Greg,
Quoted 5 lines · Greg KH
[Note, I do still have patches that people have sent me for inclusion in the .32-stable tree in my queue, but I figured this series was already big enough that it should go out now. If you notice, I _did_ apply all patches that went through Linus's tree with a [email protected] marking on it, so people might consider using that method instead...]
Quoted 5 lines
I'll give this a try, however I really miss the
tcp_collapse()fix (baff42ab1494528907bf4d5870359e31711746ae) without which 2.6.32.21 panics several times a day when usingsplice().I don't know if Davem had time to forward it to you though.
I planned to push things to Greg for -stable Sunday evening.