[kernel] r12488 - in dists/trunk/linux-2.6/debian: . patches/bugfix/all/stable patches/series

Maximilian Attems maks at alioth.debian.org
Tue Dec 9 17:09:15 UTC 2008


Author: maks
Date: Tue Dec  9 17:09:14 2008
New Revision: 12488

Log:
add stable 2.6.27.8

Added:
   dists/trunk/linux-2.6/debian/patches/bugfix/all/stable/patch-2.6.27.8
Modified:
   dists/trunk/linux-2.6/debian/changelog
   dists/trunk/linux-2.6/debian/patches/series/1~experimental.1

Modified: dists/trunk/linux-2.6/debian/changelog
==============================================================================
--- dists/trunk/linux-2.6/debian/changelog	(original)
+++ dists/trunk/linux-2.6/debian/changelog	Tue Dec  9 17:09:14 2008
@@ -18,7 +18,7 @@
     EDAC_I5100, RTC_DRV_M41T94, RTC_DRV_DS1305, UBIFS.
   * [x86] set MOUSE_BCM5974, X86_RESERVE_LOW_64K.
   * [x86_64] set AMD_IOMMU, MTRR_SANITIZER.
-  * Add stable releases 2.6.27.1-2.6.27.7.
+  * Add stable releases 2.6.27.1-2.6.27.8.
 
   [ Martin Michlmayr ]
   * [mips/r4k-ip22, mips/sb1-bcm91250a] Don't build in ISO9660.

Added: dists/trunk/linux-2.6/debian/patches/bugfix/all/stable/patch-2.6.27.8
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/all/stable/patch-2.6.27.8	Tue Dec  9 17:09:14 2008
@@ -0,0 +1,7559 @@
+diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
+index f566ad9..23f3edc 100644
+--- a/Documentation/filesystems/proc.txt
++++ b/Documentation/filesystems/proc.txt
+@@ -44,6 +44,7 @@ Table of Contents
+   2.14	/proc/<pid>/io - Display the IO accounting fields
+   2.15	/proc/<pid>/coredump_filter - Core dump filtering settings
+   2.16	/proc/<pid>/mountinfo - Information about mounts
++  2.17	/proc/sys/fs/epoll - Configuration options for the epoll interface
+ 
+ ------------------------------------------------------------------------------
+ Preface
+@@ -2471,4 +2472,30 @@ For more information on mount propagation see:
+ 
+   Documentation/filesystems/sharedsubtree.txt
+ 
++2.17	/proc/sys/fs/epoll - Configuration options for the epoll interface
++--------------------------------------------------------
++
++This directory contains configuration options for the epoll(7) interface.
++
++max_user_instances
++------------------
++
++This is the maximum number of epoll file descriptors that a single user can
++have open at a given time. The default value is 128, and should be enough
++for normal users.
++
++max_user_watches
++----------------
++
++Every epoll file descriptor can store a number of files to be monitored
++for event readiness. Each one of these monitored files constitutes a "watch".
++This configuration option sets the maximum number of "watches" that are
++allowed for each user.
++Each "watch" costs roughly 90 bytes on a 32bit kernel, and roughly 160 bytes
++on a 64bit one.
++The current default value for  max_user_watches  is the 1/32 of the available
++low memory, divided for the "watch" cost in bytes.
++
++
+ ------------------------------------------------------------------------------
++
+diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
+index 5d1eb7e..8a7e508 100644
+--- a/arch/ia64/kernel/acpi.c
++++ b/arch/ia64/kernel/acpi.c
+@@ -656,6 +656,30 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table)
+ 	return 0;
+ }
+ 
++int __init early_acpi_boot_init(void)
++{
++	int ret;
++
++	/*
++	 * do a partial walk of MADT to determine how many CPUs
++	 * we have including offline CPUs
++	 */
++	if (acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) {
++		printk(KERN_ERR PREFIX "Can't find MADT\n");
++		return 0;
++	}
++
++	ret = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC,
++		acpi_parse_lsapic, NR_CPUS);
++	if (ret < 1)
++		printk(KERN_ERR PREFIX
++		       "Error parsing MADT - no LAPIC entries\n");
++
++	return 0;
++}
++
++
++
+ int __init acpi_boot_init(void)
+ {
+ 
+@@ -679,11 +703,6 @@ int __init acpi_boot_init(void)
+ 		printk(KERN_ERR PREFIX
+ 		       "Error parsing LAPIC address override entry\n");
+ 
+-	if (acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC, acpi_parse_lsapic, NR_CPUS)
+-	    < 1)
+-		printk(KERN_ERR PREFIX
+-		       "Error parsing MADT - no LAPIC entries\n");
+-
+ 	if (acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0)
+ 	    < 0)
+ 		printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
+diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
+index de636b2..6030236 100644
+--- a/arch/ia64/kernel/setup.c
++++ b/arch/ia64/kernel/setup.c
+@@ -549,8 +549,12 @@ setup_arch (char **cmdline_p)
+ #ifdef CONFIG_ACPI
+ 	/* Initialize the ACPI boot-time table parser */
+ 	acpi_table_init();
++	early_acpi_boot_init();
+ # ifdef CONFIG_ACPI_NUMA
+ 	acpi_numa_init();
++#ifdef CONFIG_ACPI_HOTPLUG_CPU
++	prefill_possible_map();
++#endif
+ 	per_cpu_scan_finalize((cpus_weight(early_cpu_possible_map) == 0 ?
+ 		32 : cpus_weight(early_cpu_possible_map)),
+ 		additional_cpus > 0 ? additional_cpus : 0);
+@@ -841,9 +845,6 @@ void __init
+ setup_per_cpu_areas (void)
+ {
+ 	/* start_kernel() requires this... */
+-#ifdef CONFIG_ACPI_HOTPLUG_CPU
+-	prefill_possible_map();
+-#endif
+ }
+ 
+ /*
+diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
+index 675f1d0..4c771cd 100644
+--- a/arch/parisc/kernel/traps.c
++++ b/arch/parisc/kernel/traps.c
+@@ -24,7 +24,6 @@
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
+ #include <linux/console.h>
+-#include <linux/kallsyms.h>
+ #include <linux/bug.h>
+ 
+ #include <asm/assembly.h>
+@@ -51,7 +50,7 @@
+ DEFINE_SPINLOCK(pa_dbit_lock);
+ #endif
+ 
+-void parisc_show_stack(struct task_struct *t, unsigned long *sp,
++static void parisc_show_stack(struct task_struct *task, unsigned long *sp,
+ 	struct pt_regs *regs);
+ 
+ static int printbinary(char *buf, unsigned long x, int nbits)
+@@ -121,18 +120,19 @@ static void print_fr(char *level, struct pt_regs *regs)
+ 
+ void show_regs(struct pt_regs *regs)
+ {
+-	int i;
++	int i, user;
+ 	char *level;
+ 	unsigned long cr30, cr31;
+ 
+-	level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT;
++	user = user_mode(regs);
++	level = user ? KERN_DEBUG : KERN_CRIT;
+ 
+ 	print_gr(level, regs);
+ 
+ 	for (i = 0; i < 8; i += 4)
+ 		PRINTREGS(level, regs->sr, "sr", RFMT, i);
+ 
+-	if (user_mode(regs))
++	if (user)
+ 		print_fr(level, regs);
+ 
+ 	cr30 = mfctl(30);
+@@ -145,14 +145,18 @@ void show_regs(struct pt_regs *regs)
+ 	printk("%s CPU: %8d   CR30: " RFMT " CR31: " RFMT "\n",
+ 	       level, current_thread_info()->cpu, cr30, cr31);
+ 	printk("%s ORIG_R28: " RFMT "\n", level, regs->orig_r28);
+-	printk(level);
+-	print_symbol(" IAOQ[0]: %s\n", regs->iaoq[0]);
+-	printk(level);
+-	print_symbol(" IAOQ[1]: %s\n", regs->iaoq[1]);
+-	printk(level);
+-	print_symbol(" RP(r2): %s\n", regs->gr[2]);
+-
+-	parisc_show_stack(current, NULL, regs);
++
++	if (user) {
++		printk("%s IAOQ[0]: " RFMT "\n", level, regs->iaoq[0]);
++		printk("%s IAOQ[1]: " RFMT "\n", level, regs->iaoq[1]);
++		printk("%s RP(r2): " RFMT "\n", level, regs->gr[2]);
++	} else {
++		printk("%s IAOQ[0]: %pS\n", level, (void *) regs->iaoq[0]);
++		printk("%s IAOQ[1]: %pS\n", level, (void *) regs->iaoq[1]);
++		printk("%s RP(r2): %pS\n", level, (void *) regs->gr[2]);
++
++		parisc_show_stack(current, NULL, regs);
++	}
+ }
+ 
+ 
+@@ -173,20 +177,15 @@ static void do_show_stack(struct unwind_frame_info *info)
+ 			break;
+ 
+ 		if (__kernel_text_address(info->ip)) {
+-			printk("%s [<" RFMT ">] ", (i&0x3)==1 ? KERN_CRIT : "", info->ip);
+-#ifdef CONFIG_KALLSYMS
+-			print_symbol("%s\n", info->ip);
+-#else
+-			if ((i & 0x03) == 0)
+-				printk("\n");
+-#endif
++			printk(KERN_CRIT " [<" RFMT ">] %pS\n",
++				info->ip, (void *) info->ip);
+ 			i++;
+ 		}
+ 	}
+-	printk("\n");
++	printk(KERN_CRIT "\n");
+ }
+ 
+-void parisc_show_stack(struct task_struct *task, unsigned long *sp,
++static void parisc_show_stack(struct task_struct *task, unsigned long *sp,
+ 	struct pt_regs *regs)
+ {
+ 	struct unwind_frame_info info;
+diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
+index 010a51f..d5c3b45 100644
+--- a/arch/powerpc/platforms/cell/spufs/file.c
++++ b/arch/powerpc/platforms/cell/spufs/file.c
+@@ -390,6 +390,9 @@ static int spufs_ps_fault(struct vm_area_struct *vma,
+ 	if (offset >= ps_size)
+ 		return VM_FAULT_SIGBUS;
+ 
++	if (fatal_signal_pending(current))
++		return VM_FAULT_SIGBUS;
++
+ 	/*
+ 	 * Because we release the mmap_sem, the context may be destroyed while
+ 	 * we're in spu_wait. Grab an extra reference so it isn't destroyed
+diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
+index 690ca7b..5c73b62 100644
+--- a/arch/powerpc/platforms/cell/spufs/inode.c
++++ b/arch/powerpc/platforms/cell/spufs/inode.c
+@@ -496,6 +496,8 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
+ 	ret = spufs_context_open(dget(dentry), mntget(mnt));
+ 	if (ret < 0) {
+ 		WARN_ON(spufs_rmdir(inode, dentry));
++		if (affinity)
++			mutex_unlock(&gang->aff_mutex);
+ 		mutex_unlock(&inode->i_mutex);
+ 		spu_forget(SPUFS_I(dentry->d_inode)->i_ctx);
+ 		goto out;
+diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
+index c102af8..7d58e7f 100644
+--- a/arch/x86/kernel/acpi/boot.c
++++ b/arch/x86/kernel/acpi/boot.c
+@@ -1593,6 +1593,11 @@ static struct dmi_system_id __initdata acpi_dmi_table[] = {
+ 		     DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
+ 		     },
+ 	 },
++	{}
++};
++
++/* second table for DMI checks that should run after early-quirks */
++static struct dmi_system_id __initdata acpi_dmi_table_late[] = {
+ 	/*
+ 	 * HP laptops which use a DSDT reporting as HP/SB400/10000,
+ 	 * which includes some code which overrides all temperature
+@@ -1721,6 +1726,9 @@ int __init early_acpi_boot_init(void)
+ 
+ int __init acpi_boot_init(void)
+ {
++	/* those are executed after early-quirks are executed */
++	dmi_check_system(acpi_dmi_table_late);
++
+ 	/*
+ 	 * If acpi_disabled, bail out
+ 	 * One exception: acpi=ht continues far enough to enumerate LAPICs
+diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
+index 84bb395..20bda8c 100644
+--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
++++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
+@@ -116,9 +116,20 @@ static int query_current_values_with_pending_wait(struct powernow_k8_data *data)
+ 	u32 i = 0;
+ 
+ 	if (cpu_family == CPU_HW_PSTATE) {
+-		rdmsr(MSR_PSTATE_STATUS, lo, hi);
+-		i = lo & HW_PSTATE_MASK;
+-		data->currpstate = i;
++		if (data->currpstate == HW_PSTATE_INVALID) {
++			/* read (initial) hw pstate if not yet set */
++			rdmsr(MSR_PSTATE_STATUS, lo, hi);
++			i = lo & HW_PSTATE_MASK;
++
++			/*
++			 * a workaround for family 11h erratum 311 might cause
++			 * an "out-of-range Pstate if the core is in Pstate-0
++			 */
++			if (i >= data->numps)
++				data->currpstate = HW_PSTATE_0;
++			else
++				data->currpstate = i;
++		}
+ 		return 0;
+ 	}
+ 	do {
+@@ -1117,6 +1128,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
+ 	}
+ 
+ 	data->cpu = pol->cpu;
++	data->currpstate = HW_PSTATE_INVALID;
+ 
+ 	if (powernow_k8_cpu_init_acpi(data)) {
+ 		/*
+diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.h b/arch/x86/kernel/cpu/cpufreq/powernow-k8.h
+index ab48cfe..65cfb5d 100644
+--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.h
++++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.h
+@@ -5,6 +5,19 @@
+  *  http://www.gnu.org/licenses/gpl.html
+  */
+ 
++
++enum pstate {
++	HW_PSTATE_INVALID = 0xff,
++	HW_PSTATE_0 = 0,
++	HW_PSTATE_1 = 1,
++	HW_PSTATE_2 = 2,
++	HW_PSTATE_3 = 3,
++	HW_PSTATE_4 = 4,
++	HW_PSTATE_5 = 5,
++	HW_PSTATE_6 = 6,
++	HW_PSTATE_7 = 7,
++};
++
+ struct powernow_k8_data {
+ 	unsigned int cpu;
+ 
+@@ -23,7 +36,9 @@ struct powernow_k8_data {
+         u32 exttype; /* extended interface = 1 */
+ 
+ 	/* keep track of the current fid / vid or pstate */
+-	u32 currvid, currfid, currpstate;
++	u32 currvid;
++	u32 currfid;
++	enum pstate currpstate;
+ 
+ 	/* the powernow_table includes all frequency and vid/fid pairings:
+ 	 * fid are the lower 8 bits of the index, vid are the upper 8 bits.
+diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
+index 6b839b1..1b894b7 100644
+--- a/arch/x86/kernel/early-quirks.c
++++ b/arch/x86/kernel/early-quirks.c
+@@ -95,7 +95,8 @@ static void __init nvidia_bugs(int num, int slot, int func)
+ 
+ }
+ 
+-static u32 ati_ixp4x0_rev(int num, int slot, int func)
++#if defined(CONFIG_ACPI) && defined(CONFIG_X86_IO_APIC)
++static u32 __init ati_ixp4x0_rev(int num, int slot, int func)
+ {
+ 	u32 d;
+ 	u8  b;
+@@ -115,7 +116,6 @@ static u32 ati_ixp4x0_rev(int num, int slot, int func)
+ 
+ static void __init ati_bugs(int num, int slot, int func)
+ {
+-#if defined(CONFIG_ACPI) && defined (CONFIG_X86_IO_APIC)
+ 	u32 d;
+ 	u8  b;
+ 
+@@ -138,9 +138,56 @@ static void __init ati_bugs(int num, int slot, int func)
+ 		printk(KERN_INFO "If you got timer trouble "
+ 		       "try acpi_use_timer_override\n");
+ 	}
+-#endif
+ }
+ 
++static u32 __init ati_sbx00_rev(int num, int slot, int func)
++{
++	u32 old, d;
++
++	d = read_pci_config(num, slot, func, 0x70);
++	old = d;
++	d &= ~(1<<8);
++	write_pci_config(num, slot, func, 0x70, d);
++	d = read_pci_config(num, slot, func, 0x8);
++	d &= 0xff;
++	write_pci_config(num, slot, func, 0x70, old);
++
++	return d;
++}
++
++static void __init ati_bugs_contd(int num, int slot, int func)
++{
++	u32 d, rev;
++
++	if (acpi_use_timer_override)
++		return;
++
++	rev = ati_sbx00_rev(num, slot, func);
++	if (rev > 0x13)
++		return;
++
++	/* check for IRQ0 interrupt swap */
++	d = read_pci_config(num, slot, func, 0x64);
++	if (!(d & (1<<14)))
++		acpi_skip_timer_override = 1;
++
++	if (acpi_skip_timer_override) {
++		printk(KERN_INFO "SB600 revision 0x%x\n", rev);
++		printk(KERN_INFO "Ignoring ACPI timer override.\n");
++		printk(KERN_INFO "If you got timer trouble "
++		       "try acpi_use_timer_override\n");
++	}
++}
++#else
++static void __init ati_bugs(int num, int slot, int func)
++{
++}
++
++static void __init ati_bugs_contd(int num, int slot, int func)
++{
++}
++#endif
++
+ #define QFLAG_APPLY_ONCE 	0x1
+ #define QFLAG_APPLIED		0x2
+ #define QFLAG_DONE		(QFLAG_APPLY_ONCE|QFLAG_APPLIED)
+@@ -162,6 +209,8 @@ static struct chipset early_qrk[] __initdata = {
+ 	  PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, fix_hypertransport_config },
+ 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS,
+ 	  PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs },
++	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS,
++	  PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs_contd },
+ 	{}
+ };
+ 
+diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
+index 64b5c42..7667443 100644
+--- a/arch/x86/kernel/setup.c
++++ b/arch/x86/kernel/setup.c
+@@ -604,7 +604,7 @@ static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
+ 		.callback = dmi_low_memory_corruption,
+ 		.ident = "Phoenix BIOS",
+ 		.matches = {
+-			DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
++			DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies"),
+ 		},
+ 	},
+ #endif
+diff --git a/arch/x86/mm/discontig_32.c b/arch/x86/mm/discontig_32.c
+index 62fa440..62aec7e 100644
+--- a/arch/x86/mm/discontig_32.c
++++ b/arch/x86/mm/discontig_32.c
+@@ -222,6 +222,41 @@ static void __init remap_numa_kva(void)
+ 	}
+ }
+ 
++#ifdef CONFIG_HIBERNATION
++/**
++ * resume_map_numa_kva - add KVA mapping to the temporary page tables created
++ *                       during resume from hibernation
++ * @pgd_base - temporary resume page directory
++ */
++void resume_map_numa_kva(pgd_t *pgd_base)
++{
++	int node;
++
++	for_each_online_node(node) {
++		unsigned long start_va, start_pfn, size, pfn;
++
++		start_va = (unsigned long)node_remap_start_vaddr[node];
++		start_pfn = node_remap_start_pfn[node];
++		size = node_remap_size[node];
++
++		printk(KERN_DEBUG "%s: node %d\n", __FUNCTION__, node);
++
++		for (pfn = 0; pfn < size; pfn += PTRS_PER_PTE) {
++			unsigned long vaddr = start_va + (pfn << PAGE_SHIFT);
++			pgd_t *pgd = pgd_base + pgd_index(vaddr);
++			pud_t *pud = pud_offset(pgd, vaddr);
++			pmd_t *pmd = pmd_offset(pud, vaddr);
++
++			set_pmd(pmd, pfn_pmd(start_pfn + pfn,
++						PAGE_KERNEL_LARGE_EXEC));
++
++			printk(KERN_DEBUG "%s: %08lx -> pfn %08lx\n",
++				__FUNCTION__, vaddr, start_pfn + pfn);
++		}
++	}
++}
++#endif
++
+ static unsigned long calculate_numa_remap_pages(void)
+ {
+ 	int nid;
+diff --git a/arch/x86/power/hibernate_32.c b/arch/x86/power/hibernate_32.c
+index f2b6e3f..81197c6 100644
+--- a/arch/x86/power/hibernate_32.c
++++ b/arch/x86/power/hibernate_32.c
+@@ -12,6 +12,7 @@
+ #include <asm/system.h>
+ #include <asm/page.h>
+ #include <asm/pgtable.h>
++#include <asm/mmzone.h>
+ 
+ /* Defined in hibernate_asm_32.S */
+ extern int restore_image(void);
+@@ -127,6 +128,9 @@ static int resume_physical_mapping_init(pgd_t *pgd_base)
+ 			}
+ 		}
+ 	}
++
++	resume_map_numa_kva(pgd_base);
++
+ 	return 0;
+ }
+ 
+diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
+index a4e201b..6bbcf8a 100644
+--- a/arch/x86/xen/enlighten.c
++++ b/arch/x86/xen/enlighten.c
+@@ -1413,7 +1413,7 @@ static void __init xen_reserve_top(void)
+ 	if (HYPERVISOR_xen_version(XENVER_platform_parameters, &pp) == 0)
+ 		top = pp.virt_start;
+ 
+-	reserve_top_address(-top + 2 * PAGE_SIZE);
++	reserve_top_address(-top);
+ #endif	/* CONFIG_X86_32 */
+ }
+ 
+diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
+index 41b8e7c..9ab3fb9 100644
+--- a/drivers/acpi/ec.c
++++ b/drivers/acpi/ec.c
+@@ -219,7 +219,8 @@ static void gpe_transaction(struct acpi_ec *ec, u8 status)
+ 	goto unlock;
+ err:
+ 	/* false interrupt, state didn't change */
+-	++ec->curr->irq_count;
++	if (in_interrupt())
++		++ec->curr->irq_count;
+ unlock:
+ 	spin_unlock_irqrestore(&ec->curr_lock, flags);
+ }
+diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c
+index d5b4ef8..8d4a568 100644
+--- a/drivers/acpi/pci_slot.c
++++ b/drivers/acpi/pci_slot.c
+@@ -150,7 +150,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
+ 	}
+ 
+ 	snprintf(name, sizeof(name), "%u", (u32)sun);
+-	pci_slot = pci_create_slot(pci_bus, device, name);
++	pci_slot = pci_create_slot(pci_bus, device, name, NULL);
+ 	if (IS_ERR(pci_slot)) {
+ 		err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot));
+ 		kfree(slot);
+diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
+index 8228ae3..b551cda 100644
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -551,7 +551,7 @@ u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev)
+ 		if (tf->flags & ATA_TFLAG_LBA48) {
+ 			block |= (u64)tf->hob_lbah << 40;
+ 			block |= (u64)tf->hob_lbam << 32;
+-			block |= tf->hob_lbal << 24;
++			block |= (u64)tf->hob_lbal << 24;
+ 		} else
+ 			block |= (tf->device & 0xf) << 24;
+ 
+@@ -1207,7 +1207,7 @@ u64 ata_tf_to_lba48(const struct ata_taskfile *tf)
+ 
+ 	sectors |= ((u64)(tf->hob_lbah & 0xff)) << 40;
+ 	sectors |= ((u64)(tf->hob_lbam & 0xff)) << 32;
+-	sectors |= (tf->hob_lbal & 0xff) << 24;
++	sectors |= ((u64)(tf->hob_lbal & 0xff)) << 24;
+ 	sectors |= (tf->lbah & 0xff) << 16;
+ 	sectors |= (tf->lbam & 0xff) << 8;
+ 	sectors |= (tf->lbal & 0xff);
+@@ -2428,6 +2428,13 @@ int ata_dev_configure(struct ata_device *dev)
+ 		}
+ 	}
+ 
++	if ((dev->horkage & ATA_HORKAGE_FIRMWARE_WARN) && print_info) {
++		ata_dev_printk(dev, KERN_WARNING, "WARNING: device requires "
++			       "firmware update to be fully functional.\n");
++		ata_dev_printk(dev, KERN_WARNING, "         contact the vendor "
++			       "or visit http://ata.wiki.kernel.org.\n");
++	}
++
+ 	return 0;
+ 
+ err_out_nosup:
+@@ -3971,6 +3978,20 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
+ 	{ "ST380817AS",		"3.42",		ATA_HORKAGE_NONCQ },
+ 	{ "ST3160023AS",	"3.42",		ATA_HORKAGE_NONCQ },
+ 
++	/* Seagate NCQ + FLUSH CACHE firmware bug */
++	{ "ST31500341AS",	"9JU138",	ATA_HORKAGE_NONCQ |
++						ATA_HORKAGE_FIRMWARE_WARN },
++	{ "ST31000333AS",	"9FZ136",	ATA_HORKAGE_NONCQ |
++						ATA_HORKAGE_FIRMWARE_WARN },
++	{ "ST3640623AS",	"9FZ164",	ATA_HORKAGE_NONCQ |
++						ATA_HORKAGE_FIRMWARE_WARN },
++	{ "ST3640323AS",	"9FZ134",	ATA_HORKAGE_NONCQ |
++						ATA_HORKAGE_FIRMWARE_WARN },
++	{ "ST3320813AS",	"9FZ182",	ATA_HORKAGE_NONCQ |
++						ATA_HORKAGE_FIRMWARE_WARN },
++	{ "ST3320613AS",	"9FZ162",	ATA_HORKAGE_NONCQ |
++						ATA_HORKAGE_FIRMWARE_WARN },
++
+ 	/* Blacklist entries taken from Silicon Image 3124/3132
+ 	   Windows driver .inf file - also several Linux problem reports */
+ 	{ "HTS541060G9SA00",    "MB3OC60D",     ATA_HORKAGE_NONCQ, },
+diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
+index 4f73537..64142c1 100644
+--- a/drivers/firewire/fw-sbp2.c
++++ b/drivers/firewire/fw-sbp2.c
+@@ -365,6 +365,11 @@ static const struct {
+ 	},
+ 	/* iPod mini */ {
+ 		.firmware_revision	= 0x0a2700,
++		.model			= 0x000022,
++		.workarounds		= SBP2_WORKAROUND_FIX_CAPACITY,
++	},
++	/* iPod mini */ {
++		.firmware_revision	= 0x0a2700,
+ 		.model			= 0x000023,
+ 		.workarounds		= SBP2_WORKAROUND_FIX_CAPACITY,
+ 	},
+diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
+index 59f6ad8..9ed5947 100644
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -1049,7 +1049,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+ 			continue;
+ 
+ 		is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
+-		seq_printf(s, " gpio-%-3d (%-12s) %s %s",
++		seq_printf(s, " gpio-%-3d (%-20.20s) %s %s",
+ 			gpio, gdesc->label,
+ 			is_out ? "out" : "in ",
+ 			chip->get
+diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
+index 1d6ad34..bad46ea 100644
+--- a/drivers/ieee1394/sbp2.c
++++ b/drivers/ieee1394/sbp2.c
+@@ -402,6 +402,11 @@ static const struct {
+ 	},
+ 	/* iPod mini */ {
+ 		.firmware_revision	= 0x0a2700,
++		.model_id		= 0x000022,
++		.workarounds		= SBP2_WORKAROUND_FIX_CAPACITY,
++	},
++	/* iPod mini */ {
++		.firmware_revision	= 0x0a2700,
+ 		.model_id		= 0x000023,
+ 		.workarounds		= SBP2_WORKAROUND_FIX_CAPACITY,
+ 	},
+diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
+index d0866a3..1830849 100644
+--- a/drivers/infiniband/hw/mlx4/cq.c
++++ b/drivers/infiniband/hw/mlx4/cq.c
+@@ -343,6 +343,7 @@ int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
+ {
+ 	struct mlx4_ib_dev *dev = to_mdev(ibcq->device);
+ 	struct mlx4_ib_cq *cq = to_mcq(ibcq);
++	struct mlx4_mtt mtt;
+ 	int outst_cqe;
+ 	int err;
+ 
+@@ -376,10 +377,13 @@ int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
+ 			goto out;
+ 	}
+ 
++	mtt = cq->buf.mtt;
++
+ 	err = mlx4_cq_resize(dev->dev, &cq->mcq, entries, &cq->resize_buf->buf.mtt);
+ 	if (err)
+ 		goto err_buf;
+ 
++	mlx4_mtt_cleanup(dev->dev, &mtt);
+ 	if (ibcq->uobject) {
+ 		cq->buf      = cq->resize_buf->buf;
+ 		cq->ibcq.cqe = cq->resize_buf->cqe;
+@@ -406,6 +410,7 @@ int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
+ 	goto out;
+ 
+ err_buf:
++	mlx4_mtt_cleanup(dev->dev, &cq->resize_buf->buf.mtt);
+ 	if (!ibcq->uobject)
+ 		mlx4_ib_free_cq_buf(dev, &cq->resize_buf->buf,
+ 				    cq->resize_buf->cqe);
+diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
+index e32c24d..c694eaa 100644
+--- a/drivers/input/keyboard/atkbd.c
++++ b/drivers/input/keyboard/atkbd.c
+@@ -868,6 +868,22 @@ static void atkbd_hp_keymap_fixup(struct atkbd *atkbd)
+ }
+ 
+ /*
++ * Inventec system with broken key release on volume keys
++ */
++static void atkbd_inventec_keymap_fixup(struct atkbd *atkbd)
++{
++	const unsigned int forced_release_keys[] = {
++		0xae, 0xb0,
++	};
++	int i;
++
++	if (atkbd->set == 2)
++		for (i = 0; i < ARRAY_SIZE(forced_release_keys); i++)
++			__set_bit(forced_release_keys[i],
++				  atkbd->force_release_mask);
++}
++
++/*
+  * atkbd_set_keycode_table() initializes keyboard's keycode table
+  * according to the selected scancode set
+  */
+@@ -1478,6 +1494,15 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
+ 		.callback = atkbd_setup_fixup,
+ 		.driver_data = atkbd_hp_keymap_fixup,
+ 	},
++	{
++		.ident = "Inventec Symphony",
++		.matches = {
++			DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"),
++			DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"),
++		},
++		.callback = atkbd_setup_fixup,
++		.driver_data = atkbd_inventec_keymap_fixup,
++	},
+ 	{ }
+ };
+ 
+diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
+index bd5d9de..e6ca401 100644
+--- a/drivers/media/video/compat_ioctl32.c
++++ b/drivers/media/video/compat_ioctl32.c
+@@ -867,6 +867,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
+ 	case VIDIOC_STREAMON32:
+ 	case VIDIOC_STREAMOFF32:
+ 	case VIDIOC_G_PARM:
++	case VIDIOC_S_PARM:
+ 	case VIDIOC_G_STD:
+ 	case VIDIOC_S_STD:
+ 	case VIDIOC_G_TUNER:
+@@ -885,6 +886,8 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
+ 	case VIDIOC_S_INPUT32:
+ 	case VIDIOC_TRY_FMT32:
+ 	case VIDIOC_S_HW_FREQ_SEEK:
++	case VIDIOC_ENUM_FRAMESIZES:
++	case VIDIOC_ENUM_FRAMEINTERVALS:
+ 		ret = do_video_ioctl(file, cmd, arg);
+ 		break;
+ 
+diff --git a/drivers/net/atl1e/atl1e_hw.c b/drivers/net/atl1e/atl1e_hw.c
+index 949e753..c0d5f7c 100644
+--- a/drivers/net/atl1e/atl1e_hw.c
++++ b/drivers/net/atl1e/atl1e_hw.c
+@@ -163,9 +163,6 @@ int atl1e_read_mac_addr(struct atl1e_hw *hw)
+  * atl1e_hash_mc_addr
+  *  purpose
+  *      set hash value for a multicast address
+- *      hash calcu processing :
+- *          1. calcu 32bit CRC for multicast address
+- *          2. reverse crc with MSB to LSB
+  */
+ u32 atl1e_hash_mc_addr(struct atl1e_hw *hw, u8 *mc_addr)
+ {
+@@ -174,7 +171,6 @@ u32 atl1e_hash_mc_addr(struct atl1e_hw *hw, u8 *mc_addr)
+ 	int i;
+ 
+ 	crc32 = ether_crc_le(6, mc_addr);
+-	crc32 = ~crc32;
+ 	for (i = 0; i < 32; i++)
+ 		value |= (((crc32 >> i) & 1) << (31 - i));
+ 
+diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
+index 6a3893a..c854c96 100644
+--- a/drivers/net/e1000/e1000_ethtool.c
++++ b/drivers/net/e1000/e1000_ethtool.c
+@@ -1774,7 +1774,8 @@ static void e1000_get_wol(struct net_device *netdev,
+ 
+ 	/* this function will set ->supported = 0 and return 1 if wol is not
+ 	 * supported by this hardware */
+-	if (e1000_wol_exclusion(adapter, wol))
++	if (e1000_wol_exclusion(adapter, wol) ||
++	    !device_can_wakeup(&adapter->pdev->dev))
+ 		return;
+ 
+ 	/* apply any specific unsupported masks here */
+@@ -1811,7 +1812,8 @@ static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+ 	if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+ 		return -EOPNOTSUPP;
+ 
+-	if (e1000_wol_exclusion(adapter, wol))
++	if (e1000_wol_exclusion(adapter, wol) ||
++	    !device_can_wakeup(&adapter->pdev->dev))
+ 		return wol->wolopts ? -EOPNOTSUPP : 0;
+ 
+ 	switch (hw->device_id) {
+@@ -1838,6 +1840,8 @@ static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+ 	if (wol->wolopts & WAKE_MAGIC)
+ 		adapter->wol |= E1000_WUFC_MAG;
+ 
++	device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
++
+ 	return 0;
+ }
+ 
+diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
+index ad6da7b..872ea58 100644
+--- a/drivers/net/e1000/e1000_main.c
++++ b/drivers/net/e1000/e1000_main.c
+@@ -1180,6 +1180,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
+ 
+ 	/* initialize the wol settings based on the eeprom settings */
+ 	adapter->wol = adapter->eeprom_wol;
++	device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+ 
+ 	/* print bus type/speed/width info */
+ 	DPRINTK(PROBE, INFO, "(PCI%s:%s:%s) ",
+diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
+index 33a3ff1..e2a30dd 100644
+--- a/drivers/net/e1000e/ethtool.c
++++ b/drivers/net/e1000e/ethtool.c
+@@ -1681,7 +1681,8 @@ static void e1000_get_wol(struct net_device *netdev,
+ 	wol->supported = 0;
+ 	wol->wolopts = 0;
+ 
+-	if (!(adapter->flags & FLAG_HAS_WOL))
++	if (!(adapter->flags & FLAG_HAS_WOL) ||
++	    !device_can_wakeup(&adapter->pdev->dev))
+ 		return;
+ 
+ 	wol->supported = WAKE_UCAST | WAKE_MCAST |
+@@ -1719,7 +1720,8 @@ static int e1000_set_wol(struct net_device *netdev,
+ 	if (wol->wolopts & WAKE_MAGICSECURE)
+ 		return -EOPNOTSUPP;
+ 
+-	if (!(adapter->flags & FLAG_HAS_WOL))
++	if (!(adapter->flags & FLAG_HAS_WOL) ||
++	    !device_can_wakeup(&adapter->pdev->dev))
+ 		return wol->wolopts ? -EOPNOTSUPP : 0;
+ 
+ 	/* these settings will always override what we currently have */
+@@ -1738,6 +1740,8 @@ static int e1000_set_wol(struct net_device *netdev,
+ 	if (wol->wolopts & WAKE_ARP)
+ 		adapter->wol |= E1000_WUFC_ARP;
+ 
++	device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
++
+ 	return 0;
+ }
+ 
+diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
+index b81c423..660c85a 100644
+--- a/drivers/net/e1000e/netdev.c
++++ b/drivers/net/e1000e/netdev.c
+@@ -4616,6 +4616,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
+ 
+ 	/* initialize the wol settings based on the eeprom settings */
+ 	adapter->wol = adapter->eeprom_wol;
++	device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+ 
+ 	/* reset the hardware with the new settings */
+ 	e1000e_reset(adapter);
+diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
+index 58906c9..89964fa 100644
+--- a/drivers/net/igb/igb_ethtool.c
++++ b/drivers/net/igb/igb_ethtool.c
+@@ -1776,7 +1776,8 @@ static void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+ 
+ 	/* this function will set ->supported = 0 and return 1 if wol is not
+ 	 * supported by this hardware */
+-	if (igb_wol_exclusion(adapter, wol))
++	if (igb_wol_exclusion(adapter, wol) ||
++	    !device_can_wakeup(&adapter->pdev->dev))
+ 		return;
+ 
+ 	/* apply any specific unsupported masks here */
+@@ -1805,7 +1806,8 @@ static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+ 	if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+ 		return -EOPNOTSUPP;
+ 
+-	if (igb_wol_exclusion(adapter, wol))
++	if (igb_wol_exclusion(adapter, wol) ||
++	    !device_can_wakeup(&adapter->pdev->dev))
+ 		return wol->wolopts ? -EOPNOTSUPP : 0;
+ 
+ 	switch (hw->device_id) {
+@@ -1825,6 +1827,8 @@ static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+ 	if (wol->wolopts & WAKE_MAGIC)
+ 		adapter->wol |= E1000_WUFC_MAG;
+ 
++	device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
++
+ 	return 0;
+ }
+ 
+diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
+index 634c4c9..11b5df3 100644
+--- a/drivers/net/igb/igb_main.c
++++ b/drivers/net/igb/igb_main.c
+@@ -1220,6 +1220,7 @@ static int __devinit igb_probe(struct pci_dev *pdev,
+ 
+ 	/* initialize the wol settings based on the eeprom settings */
+ 	adapter->wol = adapter->eeprom_wol;
++	device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+ 
+ 	/* reset the hardware with the new settings */
+ 	igb_reset(adapter);
+diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
+index 52bf11b..2f68295 100644
+--- a/drivers/net/pcmcia/axnet_cs.c
++++ b/drivers/net/pcmcia/axnet_cs.c
+@@ -787,6 +787,7 @@ static struct pcmcia_device_id axnet_ids[] = {
+ 	PCMCIA_DEVICE_PROD_ID12("IO DATA", "ETXPCM", 0x547e66dc, 0x233adac2),
+ 	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V3)", 0x0733cc81, 0x232019a8),
+ 	PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC3-TX", 0x481e0094, 0xf91af609),
++	PCMCIA_DEVICE_PROD_ID12("NETGEAR", "FA411", 0x9aa79dc3, 0x40fad875),
+ 	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "100BASE", 0x281f1c5d, 0x7c2add04),
+ 	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEtherCard", 0x281f1c5d, 0x7ef26116),
+ 	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FEP501", 0x281f1c5d, 0x2e272058),
+diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
+index ebc1ae6..7d6cf02 100644
+--- a/drivers/net/pcmcia/pcnet_cs.c
++++ b/drivers/net/pcmcia/pcnet_cs.c
+@@ -1697,7 +1697,6 @@ static struct pcmcia_device_id pcnet_ids[] = {
+ 	PCMCIA_DEVICE_PROD_ID12("National Semiconductor", "InfoMover NE4100", 0x36e1191f, 0xa6617ec8),
+ 	PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J12", 0x18df0ba0, 0xbc912d76),
+ 	PCMCIA_DEVICE_PROD_ID12("NETGEAR", "FA410TX", 0x9aa79dc3, 0x60e5bc0e),
+-	PCMCIA_DEVICE_PROD_ID12("NETGEAR", "FA411", 0x9aa79dc3, 0x40fad875),
+ 	PCMCIA_DEVICE_PROD_ID12("Network Everywhere", "Fast Ethernet 10/100 PC Card", 0x820a67b6, 0x31ed1a5f),
+ 	PCMCIA_DEVICE_PROD_ID12("NextCom K.K.", "Next Hawk", 0xaedaec74, 0xad050ef1),
+ 	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "10/100Mbps Ethernet Card", 0x281f1c5d, 0x6e41773b),
+diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c
+index 20ddb7a..0941589 100644
+--- a/drivers/net/wireless/ath9k/recv.c
++++ b/drivers/net/wireless/ath9k/recv.c
+@@ -52,7 +52,7 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
+ 	/* setup rx descriptors */
+ 	ath9k_hw_setuprxdesc(ah,
+ 			     ds,
+-			     skb_tailroom(skb),   /* buffer size */
++			     sc->sc_rxbufsize,
+ 			     0);
+ 
+ 	if (sc->sc_rxlink == NULL)
+@@ -1011,7 +1011,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
+ 
+ 		pci_dma_sync_single_for_cpu(sc->pdev,
+ 					    bf->bf_buf_addr,
+-					    skb_tailroom(skb),
++					    sc->sc_rxbufsize,
+ 					    PCI_DMA_FROMDEVICE);
+ 		pci_unmap_single(sc->pdev,
+ 				 bf->bf_buf_addr,
+@@ -1303,8 +1303,7 @@ dma_addr_t ath_skb_map_single(struct ath_softc *sc,
+ 	 * NB: do NOT use skb->len, which is 0 on initialization.
+ 	 * Use skb's entire data area instead.
+ 	 */
+-	*pa = pci_map_single(sc->pdev, skb->data,
+-		skb_end_pointer(skb) - skb->head, direction);
++	*pa = pci_map_single(sc->pdev, skb->data, sc->sc_rxbufsize, direction);
+ 	return *pa;
+ }
+ 
+@@ -1314,6 +1313,5 @@ void ath_skb_unmap_single(struct ath_softc *sc,
+ 			  dma_addr_t *pa)
+ {
+ 	/* Unmap skb's entire data area */
+-	pci_unmap_single(sc->pdev, *pa,
+-		skb_end_pointer(skb) - skb->head, direction);
++	pci_unmap_single(sc->pdev, *pa, sc->sc_rxbufsize, direction);
+ }
+diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
+index 0cebbc4..1640096 100644
+--- a/drivers/net/wireless/rtl8187_dev.c
++++ b/drivers/net/wireless/rtl8187_dev.c
+@@ -33,10 +33,13 @@ MODULE_LICENSE("GPL");
+ static struct usb_device_id rtl8187_table[] __devinitdata = {
+ 	/* Asus */
+ 	{USB_DEVICE(0x0b05, 0x171d), .driver_info = DEVICE_RTL8187},
++	/* Belkin */
++	{USB_DEVICE(0x050d, 0x705e), .driver_info = DEVICE_RTL8187B},
+ 	/* Realtek */
+ 	{USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187},
+ 	{USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B},
+ 	{USB_DEVICE(0x0bda, 0x8197), .driver_info = DEVICE_RTL8187B},
++	{USB_DEVICE(0x0bda, 0x8198), .driver_info = DEVICE_RTL8187B},
+ 	/* Netgear */
+ 	{USB_DEVICE(0x0846, 0x6100), .driver_info = DEVICE_RTL8187},
+ 	{USB_DEVICE(0x0846, 0x6a00), .driver_info = DEVICE_RTL8187},
+diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
+index e2e95b3..101ed49 100644
+--- a/drivers/parport/parport_serial.c
++++ b/drivers/parport/parport_serial.c
+@@ -70,6 +70,8 @@ static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc
+ 	 * parallel ports and <S> is the number of serial ports.
+ 	 */
+ 	card->numports = (dev->subsystem_device & 0xf0) >> 4;
++	if (card->numports > ARRAY_SIZE(card->addr))
++		card->numports = ARRAY_SIZE(card->addr);
+ 	return 0;
+ }
+ 
+diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
+index 5a58b07..f9e244d 100644
+--- a/drivers/pci/hotplug/acpiphp.h
++++ b/drivers/pci/hotplug/acpiphp.h
+@@ -50,9 +50,6 @@
+ #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+ #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+ 
+-/* name size which is used for entries in pcihpfs */
+-#define SLOT_NAME_SIZE	20		/* {_SUN} */
+-
+ struct acpiphp_bridge;
+ struct acpiphp_slot;
+ 
+@@ -63,9 +60,13 @@ struct slot {
+ 	struct hotplug_slot	*hotplug_slot;
+ 	struct acpiphp_slot	*acpi_slot;
+ 	struct hotplug_slot_info info;
+-	char name[SLOT_NAME_SIZE];
+ };
+ 
++static inline const char *slot_name(struct slot *slot)
++{
++	return hotplug_slot_name(slot->hotplug_slot);
++}
++
+ /*
+  * struct acpiphp_bridge - PCI bridge information
+  *
+diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
+index 0e496e8..95b536a 100644
+--- a/drivers/pci/hotplug/acpiphp_core.c
++++ b/drivers/pci/hotplug/acpiphp_core.c
+@@ -44,6 +44,9 @@
+ 
+ #define MY_NAME	"acpiphp"
+ 
++/* name size which is used for entries in pcihpfs */
++#define SLOT_NAME_SIZE  21              /* {_SUN} */
++
+ static int debug;
+ int acpiphp_debug;
+ 
+@@ -84,7 +87,6 @@ static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
+ 	.get_adapter_status	= get_adapter_status,
+ };
+ 
+-
+ /**
+  * acpiphp_register_attention - set attention LED callback
+  * @info: must be completely filled with LED callbacks
+@@ -136,7 +138,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
+ {
+ 	struct slot *slot = hotplug_slot->private;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	/* enable the specified slot */
+ 	return acpiphp_enable_slot(slot->acpi_slot);
+@@ -154,7 +156,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
+ 	struct slot *slot = hotplug_slot->private;
+ 	int retval;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	/* disable the specified slot */
+ 	retval = acpiphp_disable_slot(slot->acpi_slot);
+@@ -177,7 +179,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
+  {
+ 	int retval = -ENODEV;
+ 
+- 	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot));
+  
+ 	if (attention_info && try_module_get(attention_info->owner)) {
+ 		retval = attention_info->set_attn(hotplug_slot, status);
+@@ -200,7 +202,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
+ {
+ 	struct slot *slot = hotplug_slot->private;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	*value = acpiphp_get_power_status(slot->acpi_slot);
+ 
+@@ -222,7 +224,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
+ {
+ 	int retval = -EINVAL;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot));
+ 
+ 	if (attention_info && try_module_get(attention_info->owner)) {
+ 		retval = attention_info->get_attn(hotplug_slot, value);
+@@ -245,7 +247,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
+ {
+ 	struct slot *slot = hotplug_slot->private;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	*value = acpiphp_get_latch_status(slot->acpi_slot);
+ 
+@@ -265,7 +267,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
+ {
+ 	struct slot *slot = hotplug_slot->private;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	*value = acpiphp_get_adapter_status(slot->acpi_slot);
+ 
+@@ -299,7 +301,7 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
+ {
+ 	struct slot *slot = hotplug_slot->private;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	kfree(slot->hotplug_slot);
+ 	kfree(slot);
+@@ -310,6 +312,7 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
+ {
+ 	struct slot *slot;
+ 	int retval = -ENOMEM;
++	char name[SLOT_NAME_SIZE];
+ 
+ 	slot = kzalloc(sizeof(*slot), GFP_KERNEL);
+ 	if (!slot)
+@@ -321,8 +324,6 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
+ 
+ 	slot->hotplug_slot->info = &slot->info;
+ 
+-	slot->hotplug_slot->name = slot->name;
+-
+ 	slot->hotplug_slot->private = slot;
+ 	slot->hotplug_slot->release = &release_slot;
+ 	slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
+@@ -336,11 +337,12 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
+ 	slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
+ 
+ 	acpiphp_slot->slot = slot;
+-	snprintf(slot->name, sizeof(slot->name), "%u", slot->acpi_slot->sun);
++	snprintf(name, SLOT_NAME_SIZE, "%u", slot->acpi_slot->sun);
+ 
+ 	retval = pci_hp_register(slot->hotplug_slot,
+ 					acpiphp_slot->bridge->pci_bus,
+-					acpiphp_slot->device);
++					acpiphp_slot->device,
++					name);
+ 	if (retval == -EBUSY)
+ 		goto error_hpslot;
+ 	if (retval) {
+@@ -348,7 +350,7 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
+ 		goto error_hpslot;
+  	}
+ 
+-	info("Slot [%s] registered\n", slot->hotplug_slot->name);
++	info("Slot [%s] registered\n", slot_name(slot));
+ 
+ 	return 0;
+ error_hpslot:
+@@ -365,7 +367,7 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
+ 	struct slot *slot = acpiphp_slot->slot;
+ 	int retval = 0;
+ 
+-	info ("Slot [%s] unregistered\n", slot->hotplug_slot->name);
++	info("Slot [%s] unregistered\n", slot_name(slot));
+ 
+ 	retval = pci_hp_deregister(slot->hotplug_slot);
+ 	if (retval)
+diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h
+index d9769b3..9fff878 100644
+--- a/drivers/pci/hotplug/cpci_hotplug.h
++++ b/drivers/pci/hotplug/cpci_hotplug.h
+@@ -30,6 +30,7 @@
+ 
+ #include <linux/types.h>
+ #include <linux/pci.h>
++#include <linux/pci_hotplug.h>
+ 
+ /* PICMG 2.1 R2.0 HS CSR bits: */
+ #define HS_CSR_INS	0x0080
+@@ -69,6 +70,11 @@ struct cpci_hp_controller {
+ 	struct cpci_hp_controller_ops *ops;
+ };
+ 
++static inline const char *slot_name(struct slot *slot)
++{
++	return hotplug_slot_name(slot->hotplug_slot);
++}
++
+ extern int cpci_hp_register_controller(struct cpci_hp_controller *controller);
+ extern int cpci_hp_unregister_controller(struct cpci_hp_controller *controller);
+ extern int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last);
+diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
+index 9359479..de94f4f 100644
+--- a/drivers/pci/hotplug/cpci_hotplug_core.c
++++ b/drivers/pci/hotplug/cpci_hotplug_core.c
+@@ -108,7 +108,7 @@ enable_slot(struct hotplug_slot *hotplug_slot)
+ 	struct slot *slot = hotplug_slot->private;
+ 	int retval = 0;
+ 
+-	dbg("%s - physical_slot = %s", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s", __func__, slot_name(slot));
+ 
+ 	if (controller->ops->set_power)
+ 		retval = controller->ops->set_power(slot, 1);
+@@ -121,25 +121,23 @@ disable_slot(struct hotplug_slot *hotplug_slot)
+ 	struct slot *slot = hotplug_slot->private;
+ 	int retval = 0;
+ 
+-	dbg("%s - physical_slot = %s", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s", __func__, slot_name(slot));
+ 
+ 	down_write(&list_rwsem);
+ 
+ 	/* Unconfigure device */
+-	dbg("%s - unconfiguring slot %s",
+-	    __func__, slot->hotplug_slot->name);
++	dbg("%s - unconfiguring slot %s", __func__, slot_name(slot));
+ 	if ((retval = cpci_unconfigure_slot(slot))) {
+ 		err("%s - could not unconfigure slot %s",
+-		    __func__, slot->hotplug_slot->name);
++		    __func__, slot_name(slot));
+ 		goto disable_error;
+ 	}
+-	dbg("%s - finished unconfiguring slot %s",
+-	    __func__, slot->hotplug_slot->name);
++	dbg("%s - finished unconfiguring slot %s", __func__, slot_name(slot));
+ 
+ 	/* Clear EXT (by setting it) */
+ 	if (cpci_clear_ext(slot)) {
+ 		err("%s - could not clear EXT for slot %s",
+-		    __func__, slot->hotplug_slot->name);
++		    __func__, slot_name(slot));
+ 		retval = -ENODEV;
+ 		goto disable_error;
+ 	}
+@@ -214,7 +212,6 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
+ 	struct slot *slot = hotplug_slot->private;
+ 
+ 	kfree(slot->hotplug_slot->info);
+-	kfree(slot->hotplug_slot->name);
+ 	kfree(slot->hotplug_slot);
+ 	if (slot->dev)
+ 		pci_dev_put(slot->dev);
+@@ -222,12 +219,6 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
+ }
+ 
+ #define SLOT_NAME_SIZE	6
+-static void
+-make_slot_name(struct slot *slot)
+-{
+-	snprintf(slot->hotplug_slot->name,
+-		 SLOT_NAME_SIZE, "%02x:%02x", slot->bus->number, slot->number);
+-}
+ 
+ int
+ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
+@@ -235,7 +226,7 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
+ 	struct slot *slot;
+ 	struct hotplug_slot *hotplug_slot;
+ 	struct hotplug_slot_info *info;
+-	char *name;
++	char name[SLOT_NAME_SIZE];
+ 	int status = -ENOMEM;
+ 	int i;
+ 
+@@ -262,34 +253,31 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
+ 			goto error_hpslot;
+ 		hotplug_slot->info = info;
+ 
+-		name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
+-		if (!name)
+-			goto error_info;
+-		hotplug_slot->name = name;
+-
+ 		slot->bus = bus;
+ 		slot->number = i;
+ 		slot->devfn = PCI_DEVFN(i, 0);
+ 
++		snprintf(name, SLOT_NAME_SIZE, "%02x:%02x", bus->number, i);
++
+ 		hotplug_slot->private = slot;
+ 		hotplug_slot->release = &release_slot;
+-		make_slot_name(slot);
+ 		hotplug_slot->ops = &cpci_hotplug_slot_ops;
+ 
+ 		/*
+ 		 * Initialize the slot info structure with some known
+ 		 * good values.
+ 		 */
+-		dbg("initializing slot %s", slot->hotplug_slot->name);
++		dbg("initializing slot %s", name);
+ 		info->power_status = cpci_get_power_status(slot);
+ 		info->attention_status = cpci_get_attention_status(slot);
+ 
+-		dbg("registering slot %s", slot->hotplug_slot->name);
+-		status = pci_hp_register(slot->hotplug_slot, bus, i);
++		dbg("registering slot %s", name);
++		status = pci_hp_register(slot->hotplug_slot, bus, i, name);
+ 		if (status) {
+ 			err("pci_hp_register failed with error %d", status);
+-			goto error_name;
++			goto error_info;
+ 		}
++		dbg("slot registered with name: %s", slot_name(slot));
+ 
+ 		/* Add slot to our internal list */
+ 		down_write(&list_rwsem);
+@@ -298,8 +286,6 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
+ 		up_write(&list_rwsem);
+ 	}
+ 	return 0;
+-error_name:
+-	kfree(name);
+ error_info:
+ 	kfree(info);
+ error_hpslot:
+@@ -327,7 +313,7 @@ cpci_hp_unregister_bus(struct pci_bus *bus)
+ 			list_del(&slot->slot_list);
+ 			slots--;
+ 
+-			dbg("deregistering slot %s", slot->hotplug_slot->name);
++			dbg("deregistering slot %s", slot_name(slot));
+ 			status = pci_hp_deregister(slot->hotplug_slot);
+ 			if (status) {
+ 				err("pci_hp_deregister failed with error %d",
+@@ -379,11 +365,10 @@ init_slots(int clear_ins)
+ 		return -1;
+ 	}
+ 	list_for_each_entry(slot, &slot_list, slot_list) {
+-		dbg("%s - looking at slot %s",
+-		    __func__, slot->hotplug_slot->name);
++		dbg("%s - looking at slot %s", __func__, slot_name(slot));
+ 		if (clear_ins && cpci_check_and_clear_ins(slot))
+ 			dbg("%s - cleared INS for slot %s",
+-			    __func__, slot->hotplug_slot->name);
++			    __func__, slot_name(slot));
+ 		dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0));
+ 		if (dev) {
+ 			if (update_adapter_status(slot->hotplug_slot, 1))
+@@ -414,8 +399,7 @@ check_slots(void)
+ 	}
+ 	extracted = inserted = 0;
+ 	list_for_each_entry(slot, &slot_list, slot_list) {
+-		dbg("%s - looking at slot %s",
+-		    __func__, slot->hotplug_slot->name);
++		dbg("%s - looking at slot %s", __func__, slot_name(slot));
+ 		if (cpci_check_and_clear_ins(slot)) {
+ 			/*
+ 			 * Some broken hardware (e.g. PLX 9054AB) asserts
+@@ -423,35 +407,34 @@ check_slots(void)
+ 			 */
+ 			if (slot->dev) {
+ 				warn("slot %s already inserted",
+-				     slot->hotplug_slot->name);
++				     slot_name(slot));
+ 				inserted++;
+ 				continue;
+ 			}
+ 
+ 			/* Process insertion */
+-			dbg("%s - slot %s inserted",
+-			    __func__, slot->hotplug_slot->name);
++			dbg("%s - slot %s inserted", __func__, slot_name(slot));
+ 
+ 			/* GSM, debug */
+ 			hs_csr = cpci_get_hs_csr(slot);
+ 			dbg("%s - slot %s HS_CSR (1) = %04x",
+-			    __func__, slot->hotplug_slot->name, hs_csr);
++			    __func__, slot_name(slot), hs_csr);
+ 
+ 			/* Configure device */
+ 			dbg("%s - configuring slot %s",
+-			    __func__, slot->hotplug_slot->name);
++			    __func__, slot_name(slot));
+ 			if (cpci_configure_slot(slot)) {
+ 				err("%s - could not configure slot %s",
+-				    __func__, slot->hotplug_slot->name);
++				    __func__, slot_name(slot));
+ 				continue;
+ 			}
+ 			dbg("%s - finished configuring slot %s",
+-			    __func__, slot->hotplug_slot->name);
++			    __func__, slot_name(slot));
+ 
+ 			/* GSM, debug */
+ 			hs_csr = cpci_get_hs_csr(slot);
+ 			dbg("%s - slot %s HS_CSR (2) = %04x",
+-			    __func__, slot->hotplug_slot->name, hs_csr);
++			    __func__, slot_name(slot), hs_csr);
+ 
+ 			if (update_latch_status(slot->hotplug_slot, 1))
+ 				warn("failure to update latch file");
+@@ -464,18 +447,18 @@ check_slots(void)
+ 			/* GSM, debug */
+ 			hs_csr = cpci_get_hs_csr(slot);
+ 			dbg("%s - slot %s HS_CSR (3) = %04x",
+-			    __func__, slot->hotplug_slot->name, hs_csr);
++			    __func__, slot_name(slot), hs_csr);
+ 
+ 			inserted++;
+ 		} else if (cpci_check_ext(slot)) {
+ 			/* Process extraction request */
+ 			dbg("%s - slot %s extracted",
+-			    __func__, slot->hotplug_slot->name);
++			    __func__, slot_name(slot));
+ 
+ 			/* GSM, debug */
+ 			hs_csr = cpci_get_hs_csr(slot);
+ 			dbg("%s - slot %s HS_CSR = %04x",
+-			    __func__, slot->hotplug_slot->name, hs_csr);
++			    __func__, slot_name(slot), hs_csr);
+ 
+ 			if (!slot->extracting) {
+ 				if (update_latch_status(slot->hotplug_slot, 0)) {
+@@ -493,7 +476,7 @@ check_slots(void)
+ 				 * bother trying to tell the driver or not?
+ 				 */
+ 				err("card in slot %s was improperly removed",
+-				    slot->hotplug_slot->name);
++				    slot_name(slot));
+ 				if (update_adapter_status(slot->hotplug_slot, 0))
+ 					warn("failure to update adapter file");
+ 				slot->extracting = 0;
+diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
+index df82b95..829c327 100644
+--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
++++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
+@@ -209,7 +209,7 @@ int cpci_led_on(struct slot* slot)
+ 					      hs_cap + 2,
+ 					      hs_csr)) {
+ 			err("Could not set LOO for slot %s",
+-			    slot->hotplug_slot->name);
++			    hotplug_slot_name(slot->hotplug_slot));
+ 			return -ENODEV;
+ 		}
+ 	}
+@@ -238,7 +238,7 @@ int cpci_led_off(struct slot* slot)
+ 					      hs_cap + 2,
+ 					      hs_csr)) {
+ 			err("Could not clear LOO for slot %s",
+-			    slot->hotplug_slot->name);
++			    hotplug_slot_name(slot->hotplug_slot));
+ 			return -ENODEV;
+ 		}
+ 	}
+diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h
+index b1decfa..afaf8f6 100644
+--- a/drivers/pci/hotplug/cpqphp.h
++++ b/drivers/pci/hotplug/cpqphp.h
+@@ -449,6 +449,11 @@ extern u8 cpqhp_disk_irq;
+ 
+ /* inline functions */
+ 
++static inline char *slot_name(struct slot *slot)
++{
++	return hotplug_slot_name(slot->hotplug_slot);
++}
++
+ /*
+  * return_resource
+  *
+@@ -696,14 +701,6 @@ static inline int get_presence_status(struct controller *ctrl, struct slot *slot
+ 	return presence_save;
+ }
+ 
+-#define SLOT_NAME_SIZE 10
+-
+-static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
+-{
+-	snprintf(buffer, buffer_size, "%d", slot->number);
+-}
+-
+-
+ static inline int wait_for_ctrl_irq(struct controller *ctrl)
+ {
+         DECLARE_WAITQUEUE(wait, current);
+diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
+index 87a68d2..8514c3a 100644
+--- a/drivers/pci/hotplug/cpqphp_core.c
++++ b/drivers/pci/hotplug/cpqphp_core.c
+@@ -315,14 +315,15 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
+ {
+ 	struct slot *slot = hotplug_slot->private;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	kfree(slot->hotplug_slot->info);
+-	kfree(slot->hotplug_slot->name);
+ 	kfree(slot->hotplug_slot);
+ 	kfree(slot);
+ }
+ 
++#define SLOT_NAME_SIZE 10
++
+ static int ctrl_slot_setup(struct controller *ctrl,
+ 			void __iomem *smbios_start,
+ 			void __iomem *smbios_table)
+@@ -335,6 +336,7 @@ static int ctrl_slot_setup(struct controller *ctrl,
+ 	u8 slot_number;
+ 	u8 ctrl_slot;
+ 	u32 tempdword;
++	char name[SLOT_NAME_SIZE];
+ 	void __iomem *slot_entry= NULL;
+ 	int result = -ENOMEM;
+ 
+@@ -363,16 +365,12 @@ static int ctrl_slot_setup(struct controller *ctrl,
+ 		if (!hotplug_slot->info)
+ 			goto error_hpslot;
+ 		hotplug_slot_info = hotplug_slot->info;
+-		hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
+-
+-		if (!hotplug_slot->name)
+-			goto error_info;
+ 
+ 		slot->ctrl = ctrl;
+ 		slot->bus = ctrl->bus;
+ 		slot->device = slot_device;
+ 		slot->number = slot_number;
+-		dbg("slot->number = %d\n", slot->number);
++		dbg("slot->number = %u\n", slot->number);
+ 
+ 		slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9,
+ 					slot_entry);
+@@ -418,9 +416,9 @@ static int ctrl_slot_setup(struct controller *ctrl,
+ 		/* register this slot with the hotplug pci core */
+ 		hotplug_slot->release = &release_slot;
+ 		hotplug_slot->private = slot;
+-		make_slot_name(hotplug_slot->name, SLOT_NAME_SIZE, slot);
++		snprintf(name, SLOT_NAME_SIZE, "%u", slot->number);
+ 		hotplug_slot->ops = &cpqphp_hotplug_slot_ops;
+-		
++
+ 		hotplug_slot_info->power_status = get_slot_enabled(ctrl, slot);
+ 		hotplug_slot_info->attention_status =
+ 			cpq_get_attention_status(ctrl, slot);
+@@ -436,10 +434,11 @@ static int ctrl_slot_setup(struct controller *ctrl,
+ 				slot_number);
+ 		result = pci_hp_register(hotplug_slot,
+ 					 ctrl->pci_dev->bus,
+-					 slot->device);
++					 slot->device,
++					 name);
+ 		if (result) {
+ 			err("pci_hp_register failed with error %d\n", result);
+-			goto error_name;
++			goto error_info;
+ 		}
+ 		
+ 		slot->next = ctrl->slot;
+@@ -451,8 +450,6 @@ static int ctrl_slot_setup(struct controller *ctrl,
+ 	}
+ 
+ 	return 0;
+-error_name:
+-	kfree(hotplug_slot->name);
+ error_info:
+ 	kfree(hotplug_slot_info);
+ error_hpslot:
+@@ -638,7 +635,7 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
+ 	u8 device;
+ 	u8 function;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1)
+ 		return -ENODEV;
+@@ -665,7 +662,7 @@ static int process_SI(struct hotplug_slot *hotplug_slot)
+ 	u8 device;
+ 	u8 function;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1)
+ 		return -ENODEV;
+@@ -697,7 +694,7 @@ static int process_SS(struct hotplug_slot *hotplug_slot)
+ 	u8 device;
+ 	u8 function;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1)
+ 		return -ENODEV;
+@@ -720,7 +717,7 @@ static int hardware_test(struct hotplug_slot *hotplug_slot, u32 value)
+ 	struct slot *slot = hotplug_slot->private;
+ 	struct controller *ctrl = slot->ctrl;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	return cpqhp_hardware_test(ctrl, value);	
+ }
+@@ -731,7 +728,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
+ 	struct slot *slot = hotplug_slot->private;
+ 	struct controller *ctrl = slot->ctrl;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	*value = get_slot_enabled(ctrl, slot);
+ 	return 0;
+@@ -742,7 +739,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
+ 	struct slot *slot = hotplug_slot->private;
+ 	struct controller *ctrl = slot->ctrl;
+ 	
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	*value = cpq_get_attention_status(ctrl, slot);
+ 	return 0;
+@@ -753,7 +750,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
+ 	struct slot *slot = hotplug_slot->private;
+ 	struct controller *ctrl = slot->ctrl;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	*value = cpq_get_latch_status(ctrl, slot);
+ 
+@@ -765,7 +762,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
+ 	struct slot *slot = hotplug_slot->private;
+ 	struct controller *ctrl = slot->ctrl;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	*value = get_presence_status(ctrl, slot);
+ 
+@@ -777,7 +774,7 @@ static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
+ 	struct slot *slot = hotplug_slot->private;
+ 	struct controller *ctrl = slot->ctrl;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	*value = ctrl->speed_capability;
+ 
+@@ -789,7 +786,7 @@ static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
+ 	struct slot *slot = hotplug_slot->private;
+ 	struct controller *ctrl = slot->ctrl;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	*value = ctrl->speed;
+ 
+diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
+index 146ca9c..24dcbf1 100644
+--- a/drivers/pci/hotplug/fakephp.c
++++ b/drivers/pci/hotplug/fakephp.c
+@@ -66,7 +66,6 @@ struct dummy_slot {
+ 	struct pci_dev *dev;
+ 	struct work_struct remove_work;
+ 	unsigned long removed;
+-	char name[8];
+ };
+ 
+ static int debug;
+@@ -96,10 +95,13 @@ static void dummy_release(struct hotplug_slot *slot)
+ 	kfree(dslot);
+ }
+ 
++#define SLOT_NAME_SIZE	8
++
+ static int add_slot(struct pci_dev *dev)
+ {
+ 	struct dummy_slot *dslot;
+ 	struct hotplug_slot *slot;
++	char name[SLOT_NAME_SIZE];
+ 	int retval = -ENOMEM;
+ 	static int count = 1;
+ 
+@@ -119,19 +121,18 @@ static int add_slot(struct pci_dev *dev)
+ 	if (!dslot)
+ 		goto error_info;
+ 
+-	slot->name = dslot->name;
+-	snprintf(slot->name, sizeof(dslot->name), "fake%d", count++);
+-	dbg("slot->name = %s\n", slot->name);
++	snprintf(name, SLOT_NAME_SIZE, "fake%d", count++);
+ 	slot->ops = &dummy_hotplug_slot_ops;
+ 	slot->release = &dummy_release;
+ 	slot->private = dslot;
+ 
+-	retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn));
++	retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn), name);
+ 	if (retval) {
+ 		err("pci_hp_register failed with error %d\n", retval);
+ 		goto error_dslot;
+ 	}
+ 
++	dbg("slot->name = %s\n", hotplug_slot_name(slot));
+ 	dslot->slot = slot;
+ 	dslot->dev = pci_dev_get(dev);
+ 	list_add (&dslot->node, &slot_list);
+@@ -167,10 +168,11 @@ static void remove_slot(struct dummy_slot *dslot)
+ {
+ 	int retval;
+ 
+-	dbg("removing slot %s\n", dslot->slot->name);
++	dbg("removing slot %s\n", hotplug_slot_name(dslot->slot));
+ 	retval = pci_hp_deregister(dslot->slot);
+ 	if (retval)
+-		err("Problem unregistering a slot %s\n", dslot->slot->name);
++		err("Problem unregistering a slot %s\n",
++			hotplug_slot_name(dslot->slot));
+ }
+ 
+ /* called from the single-threaded workqueue handler to remove a slot */
+@@ -308,7 +310,7 @@ static int disable_slot(struct hotplug_slot *slot)
+ 		return -ENODEV;
+ 	dslot = slot->private;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(slot));
+ 
+ 	for (func = 7; func >= 0; func--) {
+ 		dev = pci_get_slot(dslot->dev->bus, dslot->dev->devfn + func);
+diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h
+index 612d963..a8d391a 100644
+--- a/drivers/pci/hotplug/ibmphp.h
++++ b/drivers/pci/hotplug/ibmphp.h
+@@ -707,17 +707,16 @@ struct slot {
+ 	u8 device;
+ 	u8 number;
+ 	u8 real_physical_slot_num;
+-	char name[100];
+ 	u32 capabilities;
+ 	u8 supported_speed;
+ 	u8 supported_bus_mode;
++	u8 flag;		/* this is for disable slot and polling */
++	u8 ctlr_index;
+ 	struct hotplug_slot *hotplug_slot;
+ 	struct controller *ctrl;
+ 	struct pci_func *func;
+ 	u8 irq[4];
+-	u8 flag;		/* this is for disable slot and polling */
+ 	int bit_mode;		/* 0 = 32, 1 = 64 */
+-	u8 ctlr_index;
+ 	struct bus_info *bus_on;
+ 	struct list_head ibm_slot_list;
+ 	u8 status;
+diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c
+index 8467d02..8431246 100644
+--- a/drivers/pci/hotplug/ibmphp_ebda.c
++++ b/drivers/pci/hotplug/ibmphp_ebda.c
+@@ -620,11 +620,14 @@ static u8 calculate_first_slot (u8 slot_num)
+ 	return first_slot + 1;
+ 
+ }
++
++#define SLOT_NAME_SIZE 30
++
+ static char *create_file_name (struct slot * slot_cur)
+ {
+ 	struct opt_rio *opt_vg_ptr = NULL;
+ 	struct opt_rio_lo *opt_lo_ptr = NULL;
+-	static char str[30];
++	static char str[SLOT_NAME_SIZE];
+ 	int which = 0; /* rxe = 1, chassis = 0 */
+ 	u8 number = 1; /* either chassis or rxe # */
+ 	u8 first_slot = 1;
+@@ -736,7 +739,6 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
+ 
+ 	slot = hotplug_slot->private;
+ 	kfree(slot->hotplug_slot->info);
+-	kfree(slot->hotplug_slot->name);
+ 	kfree(slot->hotplug_slot);
+ 	slot->ctrl = NULL;
+ 	slot->bus_on = NULL;
+@@ -768,6 +770,7 @@ static int __init ebda_rsrc_controller (void)
+ 	int rc;
+ 	struct slot *tmp_slot;
+ 	struct list_head *list;
++	char name[SLOT_NAME_SIZE];
+ 
+ 	addr = hpc_list_ptr->phys_addr;
+ 	for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) {
+@@ -931,12 +934,6 @@ static int __init ebda_rsrc_controller (void)
+ 				goto error_no_hp_info;
+ 			}
+ 
+-			hp_slot_ptr->name = kmalloc(30, GFP_KERNEL);
+-			if (!hp_slot_ptr->name) {
+-				rc = -ENOMEM;
+-				goto error_no_hp_name;
+-			}
+-
+ 			tmp_slot = kzalloc(sizeof(*tmp_slot), GFP_KERNEL);
+ 			if (!tmp_slot) {
+ 				rc = -ENOMEM;
+@@ -1000,9 +997,9 @@ static int __init ebda_rsrc_controller (void)
+ 	list_for_each (list, &ibmphp_slot_head) {
+ 		tmp_slot = list_entry (list, struct slot, ibm_slot_list);
+ 
+-		snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot));
++		snprintf(name, SLOT_NAME_SIZE, "%s", create_file_name(tmp_slot));
+ 		pci_hp_register(tmp_slot->hotplug_slot,
+-			pci_find_bus(0, tmp_slot->bus), tmp_slot->device);
++			pci_find_bus(0, tmp_slot->bus), tmp_slot->device, name);
+ 	}
+ 
+ 	print_ebda_hpc ();
+@@ -1012,8 +1009,6 @@ static int __init ebda_rsrc_controller (void)
+ error:
+ 	kfree (hp_slot_ptr->private);
+ error_no_slot:
+-	kfree (hp_slot_ptr->name);
+-error_no_hp_name:
+ 	kfree (hp_slot_ptr->info);
+ error_no_hp_info:
+ 	kfree (hp_slot_ptr);
+diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
+index 5f85b1b..4871b96 100644
+--- a/drivers/pci/hotplug/pci_hotplug_core.c
++++ b/drivers/pci/hotplug/pci_hotplug_core.c
+@@ -37,6 +37,7 @@
+ #include <linux/init.h>
+ #include <linux/mount.h>
+ #include <linux/namei.h>
++#include <linux/mutex.h>
+ #include <linux/pci.h>
+ #include <linux/pci_hotplug.h>
+ #include <asm/uaccess.h>
+@@ -61,7 +62,7 @@ static int debug;
+ //////////////////////////////////////////////////////////////////
+ 
+ static LIST_HEAD(pci_hotplug_slot_list);
+-static DEFINE_SPINLOCK(pci_hotplug_slot_list_lock);
++static DEFINE_MUTEX(pci_hp_mutex);
+ 
+ /* these strings match up with the values in pci_bus_speed */
+ static char *pci_bus_speed_strings[] = {
+@@ -530,16 +531,12 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
+ 	struct hotplug_slot *slot;
+ 	struct list_head *tmp;
+ 
+-	spin_lock(&pci_hotplug_slot_list_lock);
+ 	list_for_each (tmp, &pci_hotplug_slot_list) {
+ 		slot = list_entry (tmp, struct hotplug_slot, slot_list);
+-		if (strcmp(slot->name, name) == 0)
+-			goto out;
++		if (strcmp(hotplug_slot_name(slot), name) == 0)
++			return slot;
+ 	}
+-	slot = NULL;
+-out:
+-	spin_unlock(&pci_hotplug_slot_list_lock);
+-	return slot;
++	return NULL;
+ }
+ 
+ /**
+@@ -547,13 +544,15 @@ out:
+  * @bus: bus this slot is on
+  * @slot: pointer to the &struct hotplug_slot to register
+  * @slot_nr: slot number
++ * @name: name registered with kobject core
+  *
+  * Registers a hotplug slot with the pci hotplug subsystem, which will allow
+  * userspace interaction to the slot.
+  *
+  * Returns 0 if successful, anything else for an error.
+  */
+-int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr)
++int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr,
++			const char *name)
+ {
+ 	int result;
+ 	struct pci_slot *pci_slot;
+@@ -568,48 +567,29 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr)
+ 		return -EINVAL;
+ 	}
+ 
+-	/* Check if we have already registered a slot with the same name. */
+-	if (get_slot_from_name(slot->name))
+-		return -EEXIST;
++	mutex_lock(&pci_hp_mutex);
+ 
+ 	/*
+ 	 * No problems if we call this interface from both ACPI_PCI_SLOT
+ 	 * driver and call it here again. If we've already created the
+ 	 * pci_slot, the interface will simply bump the refcount.
+ 	 */
+-	pci_slot = pci_create_slot(bus, slot_nr, slot->name);
+-	if (IS_ERR(pci_slot))
+-		return PTR_ERR(pci_slot);
+-
+-	if (pci_slot->hotplug) {
+-		dbg("%s: already claimed\n", __func__);
+-		pci_destroy_slot(pci_slot);
+-		return -EBUSY;
++	pci_slot = pci_create_slot(bus, slot_nr, name, slot);
++	if (IS_ERR(pci_slot)) {
++		result = PTR_ERR(pci_slot);
++		goto out;
+ 	}
+ 
+ 	slot->pci_slot = pci_slot;
+ 	pci_slot->hotplug = slot;
+ 
+-	/*
+-	 * Allow pcihp drivers to override the ACPI_PCI_SLOT name.
+-	 */
+-	if (strcmp(kobject_name(&pci_slot->kobj), slot->name)) {
+-		result = kobject_rename(&pci_slot->kobj, slot->name);
+-		if (result) {
+-			pci_destroy_slot(pci_slot);
+-			return result;
+-		}
+-	}
+-
+-	spin_lock(&pci_hotplug_slot_list_lock);
+ 	list_add(&slot->slot_list, &pci_hotplug_slot_list);
+-	spin_unlock(&pci_hotplug_slot_list_lock);
+ 
+ 	result = fs_add_slot(pci_slot);
+ 	kobject_uevent(&pci_slot->kobj, KOBJ_ADD);
+-	dbg("Added slot %s to the list\n", slot->name);
+-
+-
++	dbg("Added slot %s to the list\n", name);
++out:
++	mutex_unlock(&pci_hp_mutex);
+ 	return result;
+ }
+ 
+@@ -630,21 +610,23 @@ int pci_hp_deregister(struct hotplug_slot *hotplug)
+ 	if (!hotplug)
+ 		return -ENODEV;
+ 
+-	temp = get_slot_from_name(hotplug->name);
+-	if (temp != hotplug)
++	mutex_lock(&pci_hp_mutex);
++	temp = get_slot_from_name(hotplug_slot_name(hotplug));
++	if (temp != hotplug) {
++		mutex_unlock(&pci_hp_mutex);
+ 		return -ENODEV;
++	}
+ 
+-	spin_lock(&pci_hotplug_slot_list_lock);
+ 	list_del(&hotplug->slot_list);
+-	spin_unlock(&pci_hotplug_slot_list_lock);
+ 
+ 	slot = hotplug->pci_slot;
+ 	fs_remove_slot(slot);
+-	dbg("Removed slot %s from the list\n", hotplug->name);
++	dbg("Removed slot %s from the list\n", hotplug_slot_name(hotplug));
+ 
+ 	hotplug->release(hotplug);
+ 	slot->hotplug = NULL;
+ 	pci_destroy_slot(slot);
++	mutex_unlock(&pci_hp_mutex);
+ 
+ 	return 0;
+ }
+diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
+index 9e6cec6..0187af7 100644
+--- a/drivers/pci/hotplug/pciehp.h
++++ b/drivers/pci/hotplug/pciehp.h
+@@ -61,15 +61,13 @@ extern struct workqueue_struct *pciehp_wq;
+ struct slot {
+ 	u8 bus;
+ 	u8 device;
+-	u32 number;
+ 	u8 state;
+-	struct timer_list task_event;
+ 	u8 hp_slot;
++	u32 number;
+ 	struct controller *ctrl;
+ 	struct hpc_ops *hpc_ops;
+ 	struct hotplug_slot *hotplug_slot;
+ 	struct list_head	slot_list;
+-	char name[SLOT_NAME_SIZE];
+ 	unsigned long last_emi_toggle;
+ 	struct delayed_work work;	/* work for button event */
+ 	struct mutex lock;
+@@ -161,6 +159,11 @@ int pciehp_enable_slot(struct slot *p_slot);
+ int pciehp_disable_slot(struct slot *p_slot);
+ int pcie_enable_notification(struct controller *ctrl);
+ 
++static inline const char *slot_name(struct slot *slot)
++{
++	return hotplug_slot_name(slot->hotplug_slot);
++}
++
+ static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
+ {
+ 	struct slot *slot;
+diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
+index 4fd5355..6e18736 100644
+--- a/drivers/pci/hotplug/pciehp_core.c
++++ b/drivers/pci/hotplug/pciehp_core.c
+@@ -180,7 +180,8 @@ static struct hotplug_slot_attribute hotplug_slot_attr_lock = {
+  */
+ static void release_slot(struct hotplug_slot *hotplug_slot)
+ {
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__,
++	    hotplug_slot_name(hotplug_slot));
+ 
+ 	kfree(hotplug_slot->info);
+ 	kfree(hotplug_slot);
+@@ -191,7 +192,7 @@ static int init_slots(struct controller *ctrl)
+ 	struct slot *slot;
+ 	struct hotplug_slot *hotplug_slot;
+ 	struct hotplug_slot_info *info;
+-	int len, dup = 1;
++	char name[SLOT_NAME_SIZE];
+ 	int retval = -ENOMEM;
+ 
+ 	list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
+@@ -205,39 +206,27 @@ static int init_slots(struct controller *ctrl)
+ 
+ 		/* register this slot with the hotplug pci core */
+ 		hotplug_slot->info = info;
+-		hotplug_slot->name = slot->name;
+ 		hotplug_slot->private = slot;
+ 		hotplug_slot->release = &release_slot;
+ 		hotplug_slot->ops = &pciehp_hotplug_slot_ops;
+-		get_power_status(hotplug_slot, &info->power_status);
+-		get_attention_status(hotplug_slot, &info->attention_status);
+-		get_latch_status(hotplug_slot, &info->latch_status);
+-		get_adapter_status(hotplug_slot, &info->adapter_status);
+ 		slot->hotplug_slot = hotplug_slot;
++		snprintf(name, SLOT_NAME_SIZE, "%u", slot->number);
+ 
+ 		dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
+ 		    "slot_device_offset=%x\n", slot->bus, slot->device,
+ 		    slot->hp_slot, slot->number, ctrl->slot_device_offset);
+-duplicate_name:
+ 		retval = pci_hp_register(hotplug_slot,
+ 					 ctrl->pci_dev->subordinate,
+-					 slot->device);
++					 slot->device,
++					 name);
+ 		if (retval) {
+-			/*
+-			 * If slot N already exists, we'll try to create
+-			 * slot N-1, N-2 ... N-M, until we overflow.
+-			 */
+-			if (retval == -EEXIST) {
+-				len = snprintf(slot->name, SLOT_NAME_SIZE,
+-					       "%d-%d", slot->number, dup++);
+-				if (len < SLOT_NAME_SIZE)
+-					goto duplicate_name;
+-				else
+-					err("duplicate slot name overflow\n");
+-			}
+ 			err("pci_hp_register failed with error %d\n", retval);
+ 			goto error_info;
+ 		}
++		get_power_status(hotplug_slot, &info->power_status);
++		get_attention_status(hotplug_slot, &info->attention_status);
++		get_latch_status(hotplug_slot, &info->latch_status);
++		get_adapter_status(hotplug_slot, &info->adapter_status);
+ 		/* create additional sysfs entries */
+ 		if (EMI(ctrl)) {
+ 			retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj,
+@@ -278,7 +267,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
+ {
+ 	struct slot *slot = hotplug_slot->private;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	hotplug_slot->info->attention_status = status;
+ 
+@@ -293,7 +282,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
+ {
+ 	struct slot *slot = hotplug_slot->private;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	return pciehp_sysfs_enable_slot(slot);
+ }
+@@ -303,7 +292,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
+ {
+ 	struct slot *slot = hotplug_slot->private;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	return pciehp_sysfs_disable_slot(slot);
+ }
+@@ -313,7 +302,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
+ 	struct slot *slot = hotplug_slot->private;
+ 	int retval;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	retval = slot->hpc_ops->get_power_status(slot, value);
+ 	if (retval < 0)
+@@ -327,7 +316,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
+ 	struct slot *slot = hotplug_slot->private;
+ 	int retval;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	retval = slot->hpc_ops->get_attention_status(slot, value);
+ 	if (retval < 0)
+@@ -341,7 +330,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
+ 	struct slot *slot = hotplug_slot->private;
+ 	int retval;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	retval = slot->hpc_ops->get_latch_status(slot, value);
+ 	if (retval < 0)
+@@ -355,7 +344,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
+ 	struct slot *slot = hotplug_slot->private;
+ 	int retval;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	retval = slot->hpc_ops->get_adapter_status(slot, value);
+ 	if (retval < 0)
+@@ -370,7 +359,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot,
+ 	struct slot *slot = hotplug_slot->private;
+ 	int retval;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	retval = slot->hpc_ops->get_max_bus_speed(slot, value);
+ 	if (retval < 0)
+@@ -384,7 +373,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
+ 	struct slot *slot = hotplug_slot->private;
+ 	int retval;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
+ 	if (retval < 0)
+diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
+index 96a5d55..7266fbd 100644
+--- a/drivers/pci/hotplug/pciehp_ctrl.c
++++ b/drivers/pci/hotplug/pciehp_ctrl.c
+@@ -65,7 +65,7 @@ u8 pciehp_handle_attention_button(struct slot *p_slot)
+ 	/*
+ 	 *  Button pressed - See if need to TAKE ACTION!!!
+ 	 */
+-	info("Button pressed on Slot(%s)\n", p_slot->name);
++	info("Button pressed on Slot(%s)\n", slot_name(p_slot));
+ 	event_type = INT_BUTTON_PRESS;
+ 
+ 	queue_interrupt_event(p_slot, event_type);
+@@ -86,13 +86,13 @@ u8 pciehp_handle_switch_change(struct slot *p_slot)
+ 		/*
+ 		 * Switch opened
+ 		 */
+-		info("Latch open on Slot(%s)\n", p_slot->name);
++		info("Latch open on Slot(%s)\n", slot_name(p_slot));
+ 		event_type = INT_SWITCH_OPEN;
+ 	} else {
+ 		/*
+ 		 *  Switch closed
+ 		 */
+-		info("Latch close on Slot(%s)\n", p_slot->name);
++		info("Latch close on Slot(%s)\n", slot_name(p_slot));
+ 		event_type = INT_SWITCH_CLOSE;
+ 	}
+ 
+@@ -117,13 +117,13 @@ u8 pciehp_handle_presence_change(struct slot *p_slot)
+ 		/*
+ 		 * Card Present
+ 		 */
+-		info("Card present on Slot(%s)\n", p_slot->name);
++		info("Card present on Slot(%s)\n", slot_name(p_slot));
+ 		event_type = INT_PRESENCE_ON;
+ 	} else {
+ 		/*
+ 		 * Not Present
+ 		 */
+-		info("Card not present on Slot(%s)\n", p_slot->name);
++		info("Card not present on Slot(%s)\n", slot_name(p_slot));
+ 		event_type = INT_PRESENCE_OFF;
+ 	}
+ 
+@@ -143,13 +143,13 @@ u8 pciehp_handle_power_fault(struct slot *p_slot)
+ 		/*
+ 		 * power fault Cleared
+ 		 */
+-		info("Power fault cleared on Slot(%s)\n", p_slot->name);
++		info("Power fault cleared on Slot(%s)\n", slot_name(p_slot));
+ 		event_type = INT_POWER_FAULT_CLEAR;
+ 	} else {
+ 		/*
+ 		 *   power fault
+ 		 */
+-		info("Power fault on Slot(%s)\n", p_slot->name);
++		info("Power fault on Slot(%s)\n", slot_name(p_slot));
+ 		event_type = INT_POWER_FAULT;
+ 		info("power fault bit %x set\n", 0);
+ 	}
+@@ -404,11 +404,11 @@ static void handle_button_press_event(struct slot *p_slot)
+ 		if (getstatus) {
+ 			p_slot->state = BLINKINGOFF_STATE;
+ 			info("PCI slot #%s - powering off due to button "
+-			     "press.\n", p_slot->name);
++			     "press.\n", slot_name(p_slot));
+ 		} else {
+ 			p_slot->state = BLINKINGON_STATE;
+ 			info("PCI slot #%s - powering on due to button "
+-			     "press.\n", p_slot->name);
++			     "press.\n", slot_name(p_slot));
+ 		}
+ 		/* blink green LED and turn off amber */
+ 		if (PWR_LED(ctrl))
+@@ -425,7 +425,7 @@ static void handle_button_press_event(struct slot *p_slot)
+ 		 * press the attention again before the 5 sec. limit
+ 		 * expires to cancel hot-add or hot-remove
+ 		 */
+-		info("Button cancel on Slot(%s)\n", p_slot->name);
++		info("Button cancel on Slot(%s)\n", slot_name(p_slot));
+ 		dbg("%s: button cancel\n", __func__);
+ 		cancel_delayed_work(&p_slot->work);
+ 		if (p_slot->state == BLINKINGOFF_STATE) {
+@@ -438,7 +438,7 @@ static void handle_button_press_event(struct slot *p_slot)
+ 		if (ATTN_LED(ctrl))
+ 			p_slot->hpc_ops->set_attention_status(p_slot, 0);
+ 		info("PCI slot #%s - action canceled due to button press\n",
+-		     p_slot->name);
++		     slot_name(p_slot));
+ 		p_slot->state = STATIC_STATE;
+ 		break;
+ 	case POWEROFF_STATE:
+@@ -448,7 +448,7 @@ static void handle_button_press_event(struct slot *p_slot)
+ 		 * this means that the previous attention button action
+ 		 * to hot-add or hot-remove is undergoing
+ 		 */
+-		info("Button ignore on Slot(%s)\n", p_slot->name);
++		info("Button ignore on Slot(%s)\n", slot_name(p_slot));
+ 		update_slot_info(p_slot);
+ 		break;
+ 	default:
+@@ -529,7 +529,7 @@ int pciehp_enable_slot(struct slot *p_slot)
+ 	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+ 	if (rc || !getstatus) {
+ 		info("%s: no adapter on slot(%s)\n", __func__,
+-		     p_slot->name);
++		     slot_name(p_slot));
+ 		mutex_unlock(&p_slot->ctrl->crit_sect);
+ 		return -ENODEV;
+ 	}
+@@ -537,7 +537,7 @@ int pciehp_enable_slot(struct slot *p_slot)
+ 		rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+ 		if (rc || getstatus) {
+ 			info("%s: latch open on slot(%s)\n", __func__,
+-			     p_slot->name);
++			     slot_name(p_slot));
+ 			mutex_unlock(&p_slot->ctrl->crit_sect);
+ 			return -ENODEV;
+ 		}
+@@ -547,7 +547,7 @@ int pciehp_enable_slot(struct slot *p_slot)
+ 		rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+ 		if (rc || getstatus) {
+ 			info("%s: already enabled on slot(%s)\n", __func__,
+-			     p_slot->name);
++			     slot_name(p_slot));
+ 			mutex_unlock(&p_slot->ctrl->crit_sect);
+ 			return -EINVAL;
+ 		}
+@@ -582,7 +582,7 @@ int pciehp_disable_slot(struct slot *p_slot)
+ 		ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+ 		if (ret || !getstatus) {
+ 			info("%s: no adapter on slot(%s)\n", __func__,
+-			     p_slot->name);
++			     slot_name(p_slot));
+ 			mutex_unlock(&p_slot->ctrl->crit_sect);
+ 			return -ENODEV;
+ 		}
+@@ -592,7 +592,7 @@ int pciehp_disable_slot(struct slot *p_slot)
+ 		ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+ 		if (ret || getstatus) {
+ 			info("%s: latch open on slot(%s)\n", __func__,
+-			     p_slot->name);
++			     slot_name(p_slot));
+ 			mutex_unlock(&p_slot->ctrl->crit_sect);
+ 			return -ENODEV;
+ 		}
+@@ -602,7 +602,7 @@ int pciehp_disable_slot(struct slot *p_slot)
+ 		ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+ 		if (ret || !getstatus) {
+ 			info("%s: already disabled slot(%s)\n", __func__,
+-			     p_slot->name);
++			     slot_name(p_slot));
+ 			mutex_unlock(&p_slot->ctrl->crit_sect);
+ 			return -EINVAL;
+ 		}
+@@ -632,14 +632,14 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot)
+ 		break;
+ 	case POWERON_STATE:
+ 		info("Slot %s is already in powering on state\n",
+-		     p_slot->name);
++		     slot_name(p_slot));
+ 		break;
+ 	case BLINKINGOFF_STATE:
+ 	case POWEROFF_STATE:
+-		info("Already enabled on slot %s\n", p_slot->name);
++		info("Already enabled on slot %s\n", slot_name(p_slot));
+ 		break;
+ 	default:
+-		err("Not a valid state on slot %s\n", p_slot->name);
++		err("Not a valid state on slot %s\n", slot_name(p_slot));
+ 		break;
+ 	}
+ 	mutex_unlock(&p_slot->lock);
+@@ -664,14 +664,14 @@ int pciehp_sysfs_disable_slot(struct slot *p_slot)
+ 		break;
+ 	case POWEROFF_STATE:
+ 		info("Slot %s is already in powering off state\n",
+-		     p_slot->name);
++		     slot_name(p_slot));
+ 		break;
+ 	case BLINKINGON_STATE:
+ 	case POWERON_STATE:
+-		info("Already disabled on slot %s\n", p_slot->name);
++		info("Already disabled on slot %s\n", slot_name(p_slot));
+ 		break;
+ 	default:
+-		err("Not a valid state on slot %s\n", p_slot->name);
++		err("Not a valid state on slot %s\n", slot_name(p_slot));
+ 		break;
+ 	}
+ 	mutex_unlock(&p_slot->lock);
+diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
+index 9d934dd..d3cf6f9 100644
+--- a/drivers/pci/hotplug/pciehp_hpc.c
++++ b/drivers/pci/hotplug/pciehp_hpc.c
+@@ -1044,7 +1044,6 @@ static int pcie_init_slot(struct controller *ctrl)
+ 	slot->device = ctrl->slot_device_offset + slot->hp_slot;
+ 	slot->hpc_ops = ctrl->hpc_ops;
+ 	slot->number = ctrl->first_slot;
+-	snprintf(slot->name, SLOT_NAME_SIZE, "%d", slot->number);
+ 	mutex_init(&slot->lock);
+ 	INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
+ 	list_add(&slot->slot_list, &ctrl->slot_list);
+diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
+index 9b714ea..23be8a2 100644
+--- a/drivers/pci/hotplug/rpaphp_slot.c
++++ b/drivers/pci/hotplug/rpaphp_slot.c
+@@ -43,7 +43,7 @@ static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot)
+ void dealloc_slot_struct(struct slot *slot)
+ {
+ 	kfree(slot->hotplug_slot->info);
+-	kfree(slot->hotplug_slot->name);
++	kfree(slot->name);
+ 	kfree(slot->hotplug_slot);
+ 	kfree(slot);
+ }
+@@ -63,11 +63,9 @@ struct slot *alloc_slot_struct(struct device_node *dn,
+ 					   GFP_KERNEL);
+ 	if (!slot->hotplug_slot->info)
+ 		goto error_hpslot;
+-	slot->hotplug_slot->name = kmalloc(strlen(drc_name) + 1, GFP_KERNEL);
+-	if (!slot->hotplug_slot->name)
++	slot->name = kstrdup(drc_name, GFP_KERNEL);
++	if (!slot->name)
+ 		goto error_info;	
+-	slot->name = slot->hotplug_slot->name;
+-	strcpy(slot->name, drc_name);
+ 	slot->dn = dn;
+ 	slot->index = drc_index;
+ 	slot->power_domain = power_domain;
+@@ -137,7 +135,7 @@ int rpaphp_register_slot(struct slot *slot)
+ 		slotno = PCI_SLOT(PCI_DN(slot->dn->child)->devfn);
+ 	else
+ 		slotno = -1;
+-	retval = pci_hp_register(php_slot, slot->bus, slotno);
++	retval = pci_hp_register(php_slot, slot->bus, slotno, slot->name);
+ 	if (retval) {
+ 		err("pci_hp_register failed with error %d\n", retval);
+ 		return retval;
+diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
+index 410fe03..d748698 100644
+--- a/drivers/pci/hotplug/sgi_hotplug.c
++++ b/drivers/pci/hotplug/sgi_hotplug.c
+@@ -161,7 +161,8 @@ static int sn_pci_bus_valid(struct pci_bus *pci_bus)
+ }
+ 
+ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot,
+-				    struct pci_bus *pci_bus, int device)
++				    struct pci_bus *pci_bus, int device,
++				    char *name)
+ {
+ 	struct pcibus_info *pcibus_info;
+ 	struct slot *slot;
+@@ -173,15 +174,9 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot,
+ 		return -ENOMEM;
+ 	bss_hotplug_slot->private = slot;
+ 
+-	bss_hotplug_slot->name = kmalloc(SN_SLOT_NAME_SIZE, GFP_KERNEL);
+-	if (!bss_hotplug_slot->name) {
+-		kfree(bss_hotplug_slot->private);
+-		return -ENOMEM;
+-	}
+-
+ 	slot->device_num = device;
+ 	slot->pci_bus = pci_bus;
+-	sprintf(bss_hotplug_slot->name, "%04x:%02x:%02x",
++	sprintf(name, "%04x:%02x:%02x",
+ 		pci_domain_nr(pci_bus),
+ 		((u16)pcibus_info->pbi_buscommon.bs_persist_busnum),
+ 		device + 1);
+@@ -608,7 +603,6 @@ static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot,
+ static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot)
+ {
+ 	kfree(bss_hotplug_slot->info);
+-	kfree(bss_hotplug_slot->name);
+ 	kfree(bss_hotplug_slot->private);
+ 	kfree(bss_hotplug_slot);
+ }
+@@ -618,6 +612,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
+ 	int device;
+ 	struct pci_slot *pci_slot;
+ 	struct hotplug_slot *bss_hotplug_slot;
++	char name[SN_SLOT_NAME_SIZE];
+ 	int rc = 0;
+ 
+ 	/*
+@@ -645,15 +640,14 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
+ 		}
+ 
+ 		if (sn_hp_slot_private_alloc(bss_hotplug_slot,
+-					     pci_bus, device)) {
++					     pci_bus, device, name)) {
+ 			rc = -ENOMEM;
+ 			goto alloc_err;
+ 		}
+-
+ 		bss_hotplug_slot->ops = &sn_hotplug_slot_ops;
+ 		bss_hotplug_slot->release = &sn_release_slot;
+ 
+-		rc = pci_hp_register(bss_hotplug_slot, pci_bus, device);
++		rc = pci_hp_register(bss_hotplug_slot, pci_bus, device, name);
+ 		if (rc)
+ 			goto register_err;
+ 
+diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
+index 8a026f7..4d9fed0 100644
+--- a/drivers/pci/hotplug/shpchp.h
++++ b/drivers/pci/hotplug/shpchp.h
+@@ -69,15 +69,13 @@ struct slot {
+ 	u8 state;
+ 	u8 presence_save;
+ 	u8 pwr_save;
+-	struct timer_list task_event;
+-	u8 hp_slot;
+ 	struct controller *ctrl;
+ 	struct hpc_ops *hpc_ops;
+ 	struct hotplug_slot *hotplug_slot;
+ 	struct list_head	slot_list;
+-	char name[SLOT_NAME_SIZE];
+ 	struct delayed_work work;	/* work for button event */
+ 	struct mutex lock;
++	u8 hp_slot;
+ };
+ 
+ struct event_info {
+@@ -169,6 +167,11 @@ extern void cleanup_slots(struct controller *ctrl);
+ extern void shpchp_queue_pushbutton_work(struct work_struct *work);
+ extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev);
+ 
++static inline const char *slot_name(struct slot *slot)
++{
++	return hotplug_slot_name(slot->hotplug_slot);
++}
++
+ #ifdef CONFIG_ACPI
+ #include <linux/pci-acpi.h>
+ static inline int get_hp_params_from_firmware(struct pci_dev *dev,
+diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
+index cc38615..7af9191 100644
+--- a/drivers/pci/hotplug/shpchp_core.c
++++ b/drivers/pci/hotplug/shpchp_core.c
+@@ -89,7 +89,7 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
+ {
+ 	struct slot *slot = hotplug_slot->private;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	kfree(slot->hotplug_slot->info);
+ 	kfree(slot->hotplug_slot);
+@@ -101,8 +101,9 @@ static int init_slots(struct controller *ctrl)
+ 	struct slot *slot;
+ 	struct hotplug_slot *hotplug_slot;
+ 	struct hotplug_slot_info *info;
++	char name[SLOT_NAME_SIZE];
+ 	int retval = -ENOMEM;
+-	int i, len, dup = 1;
++	int i;
+ 
+ 	for (i = 0; i < ctrl->num_slots; i++) {
+ 		slot = kzalloc(sizeof(*slot), GFP_KERNEL);
+@@ -119,8 +120,6 @@ static int init_slots(struct controller *ctrl)
+ 			goto error_hpslot;
+ 		hotplug_slot->info = info;
+ 
+-		hotplug_slot->name = slot->name;
+-
+ 		slot->hp_slot = i;
+ 		slot->ctrl = ctrl;
+ 		slot->bus = ctrl->pci_dev->subordinate->number;
+@@ -133,37 +132,24 @@ static int init_slots(struct controller *ctrl)
+ 		/* register this slot with the hotplug pci core */
+ 		hotplug_slot->private = slot;
+ 		hotplug_slot->release = &release_slot;
+-		snprintf(slot->name, SLOT_NAME_SIZE, "%d", slot->number);
++		snprintf(name, SLOT_NAME_SIZE, "%d", slot->number);
+ 		hotplug_slot->ops = &shpchp_hotplug_slot_ops;
+ 
+-		get_power_status(hotplug_slot, &info->power_status);
+-		get_attention_status(hotplug_slot, &info->attention_status);
+-		get_latch_status(hotplug_slot, &info->latch_status);
+-		get_adapter_status(hotplug_slot, &info->adapter_status);
+-
+ 		dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
+ 		    "slot_device_offset=%x\n", slot->bus, slot->device,
+ 		    slot->hp_slot, slot->number, ctrl->slot_device_offset);
+-duplicate_name:
+ 		retval = pci_hp_register(slot->hotplug_slot,
+-				ctrl->pci_dev->subordinate, slot->device);
++				ctrl->pci_dev->subordinate, slot->device, name);
+ 		if (retval) {
+-			/*
+-			 * If slot N already exists, we'll try to create
+-			 * slot N-1, N-2 ... N-M, until we overflow.
+-			 */
+-			if (retval == -EEXIST) {
+-				len = snprintf(slot->name, SLOT_NAME_SIZE,
+-					       "%d-%d", slot->number, dup++);
+-				if (len < SLOT_NAME_SIZE)
+-					goto duplicate_name;
+-				else
+-					err("duplicate slot name overflow\n");
+-			}
+ 			err("pci_hp_register failed with error %d\n", retval);
+ 			goto error_info;
+ 		}
+ 
++		get_power_status(hotplug_slot, &info->power_status);
++		get_attention_status(hotplug_slot, &info->attention_status);
++		get_latch_status(hotplug_slot, &info->latch_status);
++		get_adapter_status(hotplug_slot, &info->adapter_status);
++
+ 		list_add(&slot->slot_list, &ctrl->slot_list);
+ 	}
+ 
+@@ -201,7 +187,7 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
+ {
+ 	struct slot *slot = get_slot(hotplug_slot);
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	hotplug_slot->info->attention_status = status;
+ 	slot->hpc_ops->set_attention_status(slot, status);
+@@ -213,7 +199,7 @@ static int enable_slot (struct hotplug_slot *hotplug_slot)
+ {
+ 	struct slot *slot = get_slot(hotplug_slot);
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	return shpchp_sysfs_enable_slot(slot);
+ }
+@@ -222,7 +208,7 @@ static int disable_slot (struct hotplug_slot *hotplug_slot)
+ {
+ 	struct slot *slot = get_slot(hotplug_slot);
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	return shpchp_sysfs_disable_slot(slot);
+ }
+@@ -232,7 +218,7 @@ static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
+ 	struct slot *slot = get_slot(hotplug_slot);
+ 	int retval;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	retval = slot->hpc_ops->get_power_status(slot, value);
+ 	if (retval < 0)
+@@ -246,7 +232,7 @@ static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
+ 	struct slot *slot = get_slot(hotplug_slot);
+ 	int retval;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	retval = slot->hpc_ops->get_attention_status(slot, value);
+ 	if (retval < 0)
+@@ -260,7 +246,7 @@ static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
+ 	struct slot *slot = get_slot(hotplug_slot);
+ 	int retval;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	retval = slot->hpc_ops->get_latch_status(slot, value);
+ 	if (retval < 0)
+@@ -274,7 +260,7 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
+ 	struct slot *slot = get_slot(hotplug_slot);
+ 	int retval;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	retval = slot->hpc_ops->get_adapter_status(slot, value);
+ 	if (retval < 0)
+@@ -289,7 +275,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot,
+ 	struct slot *slot = get_slot(hotplug_slot);
+ 	int retval;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	retval = slot->hpc_ops->get_max_bus_speed(slot, value);
+ 	if (retval < 0)
+@@ -303,7 +289,7 @@ static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
+ 	struct slot *slot = get_slot(hotplug_slot);
+ 	int retval;
+ 
+-	dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name);
++	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
+ 
+ 	retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
+ 	if (retval < 0)
+diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
+index dfb5393..919b1ee 100644
+--- a/drivers/pci/hotplug/shpchp_ctrl.c
++++ b/drivers/pci/hotplug/shpchp_ctrl.c
+@@ -70,7 +70,7 @@ u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
+ 	/*
+ 	 *  Button pressed - See if need to TAKE ACTION!!!
+ 	 */
+-	info("Button pressed on Slot(%s)\n", p_slot->name);
++	info("Button pressed on Slot(%s)\n", slot_name(p_slot));
+ 	event_type = INT_BUTTON_PRESS;
+ 
+ 	queue_interrupt_event(p_slot, event_type);
+@@ -98,7 +98,7 @@ u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
+ 		/*
+ 		 * Switch opened
+ 		 */
+-		info("Latch open on Slot(%s)\n", p_slot->name);
++		info("Latch open on Slot(%s)\n", slot_name(p_slot));
+ 		event_type = INT_SWITCH_OPEN;
+ 		if (p_slot->pwr_save && p_slot->presence_save) {
+ 			event_type = INT_POWER_FAULT;
+@@ -108,7 +108,7 @@ u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
+ 		/*
+ 		 *  Switch closed
+ 		 */
+-		info("Latch close on Slot(%s)\n", p_slot->name);
++		info("Latch close on Slot(%s)\n", slot_name(p_slot));
+ 		event_type = INT_SWITCH_CLOSE;
+ 	}
+ 
+@@ -135,13 +135,13 @@ u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
+ 		/*
+ 		 * Card Present
+ 		 */
+-		info("Card present on Slot(%s)\n", p_slot->name);
++		info("Card present on Slot(%s)\n", slot_name(p_slot));
+ 		event_type = INT_PRESENCE_ON;
+ 	} else {
+ 		/*
+ 		 * Not Present
+ 		 */
+-		info("Card not present on Slot(%s)\n", p_slot->name);
++		info("Card not present on Slot(%s)\n", slot_name(p_slot));
+ 		event_type = INT_PRESENCE_OFF;
+ 	}
+ 
+@@ -164,14 +164,14 @@ u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
+ 		/*
+ 		 * Power fault Cleared
+ 		 */
+-		info("Power fault cleared on Slot(%s)\n", p_slot->name);
++		info("Power fault cleared on Slot(%s)\n", slot_name(p_slot));
+ 		p_slot->status = 0x00;
+ 		event_type = INT_POWER_FAULT_CLEAR;
+ 	} else {
+ 		/*
+ 		 *   Power fault
+ 		 */
+-		info("Power fault on Slot(%s)\n", p_slot->name);
++		info("Power fault on Slot(%s)\n", slot_name(p_slot));
+ 		event_type = INT_POWER_FAULT;
+ 		/* set power fault status for this board */
+ 		p_slot->status = 0xFF;
+@@ -493,11 +493,11 @@ static void handle_button_press_event(struct slot *p_slot)
+ 		if (getstatus) {
+ 			p_slot->state = BLINKINGOFF_STATE;
+ 			info("PCI slot #%s - powering off due to button "
+-			     "press.\n", p_slot->name);
++			     "press.\n", slot_name(p_slot));
+ 		} else {
+ 			p_slot->state = BLINKINGON_STATE;
+ 			info("PCI slot #%s - powering on due to button "
+-			     "press.\n", p_slot->name);
++			     "press.\n", slot_name(p_slot));
+ 		}
+ 		/* blink green LED and turn off amber */
+ 		p_slot->hpc_ops->green_led_blink(p_slot);
+@@ -512,7 +512,7 @@ static void handle_button_press_event(struct slot *p_slot)
+ 		 * press the attention again before the 5 sec. limit
+ 		 * expires to cancel hot-add or hot-remove
+ 		 */
+-		info("Button cancel on Slot(%s)\n", p_slot->name);
++		info("Button cancel on Slot(%s)\n", slot_name(p_slot));
+ 		dbg("%s: button cancel\n", __func__);
+ 		cancel_delayed_work(&p_slot->work);
+ 		if (p_slot->state == BLINKINGOFF_STATE)
+@@ -521,7 +521,7 @@ static void handle_button_press_event(struct slot *p_slot)
+ 			p_slot->hpc_ops->green_led_off(p_slot);
+ 		p_slot->hpc_ops->set_attention_status(p_slot, 0);
+ 		info("PCI slot #%s - action canceled due to button press\n",
+-		     p_slot->name);
++		     slot_name(p_slot));
+ 		p_slot->state = STATIC_STATE;
+ 		break;
+ 	case POWEROFF_STATE:
+@@ -531,7 +531,7 @@ static void handle_button_press_event(struct slot *p_slot)
+ 		 * this means that the previous attention button action
+ 		 * to hot-add or hot-remove is undergoing
+ 		 */
+-		info("Button ignore on Slot(%s)\n", p_slot->name);
++		info("Button ignore on Slot(%s)\n", slot_name(p_slot));
+ 		update_slot_info(p_slot);
+ 		break;
+ 	default:
+@@ -574,17 +574,17 @@ static int shpchp_enable_slot (struct slot *p_slot)
+ 	mutex_lock(&p_slot->ctrl->crit_sect);
+ 	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+ 	if (rc || !getstatus) {
+-		info("No adapter on slot(%s)\n", p_slot->name);
++		info("No adapter on slot(%s)\n", slot_name(p_slot));
+ 		goto out;
+ 	}
+ 	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+ 	if (rc || getstatus) {
+-		info("Latch open on slot(%s)\n", p_slot->name);
++		info("Latch open on slot(%s)\n", slot_name(p_slot));
+ 		goto out;
+ 	}
+ 	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+ 	if (rc || getstatus) {
+-		info("Already enabled on slot(%s)\n", p_slot->name);
++		info("Already enabled on slot(%s)\n", slot_name(p_slot));
+ 		goto out;
+ 	}
+ 
+@@ -633,17 +633,17 @@ static int shpchp_disable_slot (struct slot *p_slot)
+ 
+ 	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+ 	if (rc || !getstatus) {
+-		info("No adapter on slot(%s)\n", p_slot->name);
++		info("No adapter on slot(%s)\n", slot_name(p_slot));
+ 		goto out;
+ 	}
+ 	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+ 	if (rc || getstatus) {
+-		info("Latch open on slot(%s)\n", p_slot->name);
++		info("Latch open on slot(%s)\n", slot_name(p_slot));
+ 		goto out;
+ 	}
+ 	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+ 	if (rc || !getstatus) {
+-		info("Already disabled slot(%s)\n", p_slot->name);
++		info("Already disabled slot(%s)\n", slot_name(p_slot));
+ 		goto out;
+ 	}
+ 
+@@ -671,14 +671,14 @@ int shpchp_sysfs_enable_slot(struct slot *p_slot)
+ 		break;
+ 	case POWERON_STATE:
+ 		info("Slot %s is already in powering on state\n",
+-		     p_slot->name);
++		     slot_name(p_slot));
+ 		break;
+ 	case BLINKINGOFF_STATE:
+ 	case POWEROFF_STATE:
+-		info("Already enabled on slot %s\n", p_slot->name);
++		info("Already enabled on slot %s\n", slot_name(p_slot));
+ 		break;
+ 	default:
+-		err("Not a valid state on slot %s\n", p_slot->name);
++		err("Not a valid state on slot %s\n", slot_name(p_slot));
+ 		break;
+ 	}
+ 	mutex_unlock(&p_slot->lock);
+@@ -703,14 +703,14 @@ int shpchp_sysfs_disable_slot(struct slot *p_slot)
+ 		break;
+ 	case POWEROFF_STATE:
+ 		info("Slot %s is already in powering off state\n",
+-		     p_slot->name);
++		     slot_name(p_slot));
+ 		break;
+ 	case BLINKINGON_STATE:
+ 	case POWERON_STATE:
+-		info("Already disabled on slot %s\n", p_slot->name);
++		info("Already disabled on slot %s\n", slot_name(p_slot));
+ 		break;
+ 	default:
+-		err("Not a valid state on slot %s\n", p_slot->name);
++		err("Not a valid state on slot %s\n", slot_name(p_slot));
+ 		break;
+ 	}
+ 	mutex_unlock(&p_slot->lock);
+diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
+index 7e5b85c..b703b09 100644
+--- a/drivers/pci/slot.c
++++ b/drivers/pci/slot.c
+@@ -73,18 +73,100 @@ static struct kobj_type pci_slot_ktype = {
+ 	.default_attrs = pci_slot_default_attrs,
+ };
+ 
++static char *make_slot_name(const char *name)
++{
++	char *new_name;
++	int len, max, dup;
++
++	new_name = kstrdup(name, GFP_KERNEL);
++	if (!new_name)
++		return NULL;
++
++	/*
++	 * Make sure we hit the realloc case the first time through the
++	 * loop.  'len' will be strlen(name) + 3 at that point which is
++	 * enough space for "name-X" and the trailing NUL.
++	 */
++	len = strlen(name) + 2;
++	max = 1;
++	dup = 1;
++
++	for (;;) {
++		struct kobject *dup_slot;
++		dup_slot = kset_find_obj(pci_slots_kset, new_name);
++		if (!dup_slot)
++			break;
++		kobject_put(dup_slot);
++		if (dup == max) {
++			len++;
++			max *= 10;
++			kfree(new_name);
++			new_name = kmalloc(len, GFP_KERNEL);
++			if (!new_name)
++				break;
++		}
++		sprintf(new_name, "%s-%d", name, dup++);
++	}
++
++	return new_name;
++}
++
++static int rename_slot(struct pci_slot *slot, const char *name)
++{
++	int result = 0;
++	char *slot_name;
++
++	if (strcmp(pci_slot_name(slot), name) == 0)
++		return result;
++
++	slot_name = make_slot_name(name);
++	if (!slot_name)
++		return -ENOMEM;
++
++	result = kobject_rename(&slot->kobj, slot_name);
++	kfree(slot_name);
++
++	return result;
++}
++
++static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr)
++{
++	struct pci_slot *slot;
++	/*
++	 * We already hold pci_bus_sem so don't worry
++	 */
++	list_for_each_entry(slot, &parent->slots, list)
++		if (slot->number == slot_nr) {
++			kobject_get(&slot->kobj);
++			return slot;
++		}
++
++	return NULL;
++}
++
+ /**
+  * pci_create_slot - create or increment refcount for physical PCI slot
+  * @parent: struct pci_bus of parent bridge
+  * @slot_nr: PCI_SLOT(pci_dev->devfn) or -1 for placeholder
+  * @name: user visible string presented in /sys/bus/pci/slots/<name>
++ * @hotplug: set if caller is hotplug driver, NULL otherwise
+  *
+  * PCI slots have first class attributes such as address, speed, width,
+  * and a &struct pci_slot is used to manage them. This interface will
+  * either return a new &struct pci_slot to the caller, or if the pci_slot
+  * already exists, its refcount will be incremented.
+  *
+- * Slots are uniquely identified by a @pci_bus, @slot_nr, @name tuple.
++ * Slots are uniquely identified by a @pci_bus, @slot_nr tuple.
++ *
++ * There are known platforms with broken firmware that assign the same
++ * name to multiple slots. Workaround these broken platforms by renaming
++ * the slots on behalf of the caller. If firmware assigns name N to
++ * multiple slots:
++ *
++ * The first slot is assigned N
++ * The second slot is assigned N-1
++ * The third slot is assigned N-2
++ * etc.
+  *
+  * Placeholder slots:
+  * In most cases, @pci_bus, @slot_nr will be sufficient to uniquely identify
+@@ -93,12 +175,8 @@ static struct kobj_type pci_slot_ktype = {
+  * the slot. In this scenario, the caller may pass -1 for @slot_nr.
+  *
+  * The following semantics are imposed when the caller passes @slot_nr ==
+- * -1. First, the check for existing %struct pci_slot is skipped, as the
+- * caller may know about several unpopulated slots on a given %struct
+- * pci_bus, and each slot would have a @slot_nr of -1.  Uniqueness for
+- * these slots is then determined by the @name parameter. We expect
+- * kobject_init_and_add() to warn us if the caller attempts to create
+- * multiple slots with the same name. The other change in semantics is
++ * -1. First, we no longer check for an existing %struct pci_slot, as there
++ * may be many slots with @slot_nr of -1.  The other change in semantics is
+  * user-visible, which is the 'address' parameter presented in sysfs will
+  * consist solely of a dddd:bb tuple, where dddd is the PCI domain of the
+  * %struct pci_bus and bb is the bus number. In other words, the devfn of
+@@ -106,47 +184,57 @@ static struct kobj_type pci_slot_ktype = {
+  */
+ 
+ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
+-				 const char *name)
++				 const char *name,
++				 struct hotplug_slot *hotplug)
+ {
+ 	struct pci_slot *slot;
+-	int err;
++	int err = 0;
++	char *slot_name = NULL;
+ 
+ 	down_write(&pci_bus_sem);
+ 
+ 	if (slot_nr == -1)
+ 		goto placeholder;
+ 
+-	/* If we've already created this slot, bump refcount and return. */
+-	list_for_each_entry(slot, &parent->slots, list) {
+-		if (slot->number == slot_nr) {
+-			kobject_get(&slot->kobj);
+-			pr_debug("%s: inc refcount to %d on %04x:%02x:%02x\n",
+-				 __func__,
+-				 atomic_read(&slot->kobj.kref.refcount),
+-				 pci_domain_nr(parent), parent->number,
+-				 slot_nr);
+-			goto out;
++	/*
++	 * Hotplug drivers are allowed to rename an existing slot,
++	 * but only if not already claimed.
++	 */
++	slot = get_slot(parent, slot_nr);
++	if (slot) {
++		if (hotplug) {
++			if ((err = slot->hotplug ? -EBUSY : 0)
++			     || (err = rename_slot(slot, name))) {
++				kobject_put(&slot->kobj);
++				slot = NULL;
++				goto err;
++			}
+ 		}
++		goto out;
+ 	}
+ 
+ placeholder:
+ 	slot = kzalloc(sizeof(*slot), GFP_KERNEL);
+ 	if (!slot) {
+-		slot = ERR_PTR(-ENOMEM);
+-		goto out;
++		err = -ENOMEM;
++		goto err;
+ 	}
+ 
+ 	slot->bus = parent;
+ 	slot->number = slot_nr;
+ 
+ 	slot->kobj.kset = pci_slots_kset;
+-	err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL,
+-				   "%s", name);
+-	if (err) {
+-		printk(KERN_ERR "Unable to register kobject %s\n", name);
++	slot_name = make_slot_name(name);
++	if (!slot_name) {
++		err = -ENOMEM;
+ 		goto err;
+ 	}
+ 
++	err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL,
++				   "%s", slot_name);
++	if (err)
++		goto err;
++
+ 	INIT_LIST_HEAD(&slot->list);
+ 	list_add(&slot->list, &parent->slots);
+ 
+@@ -154,10 +242,10 @@ placeholder:
+ 	pr_debug("%s: created pci_slot on %04x:%02x:%02x\n",
+ 		 __func__, pci_domain_nr(parent), parent->number, slot_nr);
+ 
+- out:
++out:
+ 	up_write(&pci_bus_sem);
+ 	return slot;
+- err:
++err:
+ 	kfree(slot);
+ 	slot = ERR_PTR(err);
+ 	goto out;
+@@ -203,7 +291,6 @@ EXPORT_SYMBOL_GPL(pci_update_slot_number);
+  * just call kobject_put on its kobj and let our release methods do the
+  * rest.
+  */
+-
+ void pci_destroy_slot(struct pci_slot *slot)
+ {
+ 	pr_debug("%s: dec refcount to %d on %04x:%02x:%02x\n", __func__,
+diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
+index d47d363..b5fc978 100644
+--- a/drivers/spi/pxa2xx_spi.c
++++ b/drivers/spi/pxa2xx_spi.c
+@@ -348,21 +348,21 @@ static int map_dma_buffers(struct driver_data *drv_data)
+ 	} else
+ 		drv_data->tx_map_len = drv_data->len;
+ 
+-	/* Stream map the rx buffer */
+-	drv_data->rx_dma = dma_map_single(dev, drv_data->rx,
+-						drv_data->rx_map_len,
+-						DMA_FROM_DEVICE);
+-	if (dma_mapping_error(dev, drv_data->rx_dma))
+-		return 0;
+-
+-	/* Stream map the tx buffer */
++	/* Stream map the tx buffer. Always do DMA_TO_DEVICE first
++	 * so we flush the cache *before* invalidating it, in case
++	 * the tx and rx buffers overlap.
++	 */
+ 	drv_data->tx_dma = dma_map_single(dev, drv_data->tx,
+-						drv_data->tx_map_len,
+-						DMA_TO_DEVICE);
++					drv_data->tx_map_len, DMA_TO_DEVICE);
++	if (dma_mapping_error(dev, drv_data->tx_dma))
++		return 0;
+ 
+-	if (dma_mapping_error(dev, drv_data->tx_dma)) {
+-		dma_unmap_single(dev, drv_data->rx_dma,
++	/* Stream map the rx buffer */
++	drv_data->rx_dma = dma_map_single(dev, drv_data->rx,
+ 					drv_data->rx_map_len, DMA_FROM_DEVICE);
++	if (dma_mapping_error(dev, drv_data->rx_dma)) {
++		dma_unmap_single(dev, drv_data->tx_dma,
++					drv_data->tx_map_len, DMA_TO_DEVICE);
+ 		return 0;
+ 	}
+ 
+diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
+index 659b3d9..428b599 100644
+--- a/drivers/usb/gadget/f_rndis.c
++++ b/drivers/usb/gadget/f_rndis.c
+@@ -172,7 +172,6 @@ static struct usb_interface_descriptor rndis_data_intf __initdata = {
+ 	.bDescriptorType =	USB_DT_INTERFACE,
+ 
+ 	/* .bInterfaceNumber = DYNAMIC */
+-	.bAlternateSetting =	1,
+ 	.bNumEndpoints =	2,
+ 	.bInterfaceClass =	USB_CLASS_CDC_DATA,
+ 	.bInterfaceSubClass =	0,
+@@ -303,7 +302,7 @@ static void rndis_response_available(void *_rndis)
+ 	__le32				*data = req->buf;
+ 	int				status;
+ 
+-	if (atomic_inc_return(&rndis->notify_count))
++	if (atomic_inc_return(&rndis->notify_count) != 1)
+ 		return;
+ 
+ 	/* Send RNDIS RESPONSE_AVAILABLE notification; a
+diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
+index c46a58f..36864f9 100644
+--- a/drivers/usb/host/ehci-pci.c
++++ b/drivers/usb/host/ehci-pci.c
+@@ -66,6 +66,8 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
+ {
+ 	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
+ 	struct pci_dev		*pdev = to_pci_dev(hcd->self.controller);
++	struct pci_dev		*p_smbus;
++	u8			rev;
+ 	u32			temp;
+ 	int			retval;
+ 
+@@ -166,6 +168,28 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
+ 			pci_write_config_byte(pdev, 0x4b, tmp | 0x20);
+ 		}
+ 		break;
++	case PCI_VENDOR_ID_ATI:
++		/* SB600 and old version of SB700 have a bug in EHCI controller,
++		 * which causes usb devices lose response in some cases.
++		 */
++		if ((pdev->device == 0x4386) || (pdev->device == 0x4396)) {
++			p_smbus = pci_get_device(PCI_VENDOR_ID_ATI,
++						 PCI_DEVICE_ID_ATI_SBX00_SMBUS,
++						 NULL);
++			if (!p_smbus)
++				break;
++			rev = p_smbus->revision;
++			if ((pdev->device == 0x4386) || (rev == 0x3a)
++			    || (rev == 0x3b)) {
++				u8 tmp;
++				ehci_info(ehci, "applying AMD SB600/SB700 USB "
++					"freeze workaround\n");
++				pci_read_config_byte(pdev, 0x53, &tmp);
++				pci_write_config_byte(pdev, 0x53, tmp | (1<<3));
++			}
++			pci_dev_put(p_smbus);
++		}
++		break;
+ 	}
+ 
+ 	ehci_reset(ehci);
+diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
+index 6566fc0..0ada0fc 100644
+--- a/drivers/usb/mon/mon_bin.c
++++ b/drivers/usb/mon/mon_bin.c
+@@ -687,7 +687,10 @@ static ssize_t mon_bin_read(struct file *file, char __user *buf,
+ 	}
+ 
+ 	if (rp->b_read >= sizeof(struct mon_bin_hdr)) {
+-		step_len = min(nbytes, (size_t)ep->len_cap);
++		step_len = ep->len_cap;
++		step_len -= rp->b_read - sizeof(struct mon_bin_hdr);
++		if (step_len > nbytes)
++			step_len = nbytes;
+ 		offset = rp->b_out + PKT_SIZE;
+ 		offset += rp->b_read - sizeof(struct mon_bin_hdr);
+ 		if (offset >= rp->b_size)
+diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
+index 98843c2..3f050e2 100644
+--- a/drivers/video/fbmem.c
++++ b/drivers/video/fbmem.c
+@@ -232,7 +232,7 @@ static void fb_set_logo_directpalette(struct fb_info *info,
+ 	greenshift = info->var.green.offset;
+ 	blueshift = info->var.blue.offset;
+ 
+-	for (i = 32; i < logo->clutsize; i++)
++	for (i = 32; i < 32 + logo->clutsize; i++)
+ 		palette[i] = i << redshift | i << greenshift | i << blueshift;
+ }
+ 
+diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
+index a3765e0..763c1ea 100644
+--- a/drivers/watchdog/hpwdt.c
++++ b/drivers/watchdog/hpwdt.c
+@@ -40,6 +40,7 @@
+ #include <linux/bootmem.h>
+ #include <linux/slab.h>
+ #include <asm/desc.h>
++#include <asm/cacheflush.h>
+ 
+ #define PCI_BIOS32_SD_VALUE		0x5F32335F	/* "_32_" */
+ #define CRU_BIOS_SIGNATURE_VALUE	0x55524324
+@@ -394,6 +395,8 @@ static void __devinit dmi_find_cru(const struct dmi_header *dm)
+ 				smbios_cru64_ptr->double_offset;
+ 			cru_rom_addr = ioremap(cru_physical_address,
+ 				smbios_cru64_ptr->double_length);
++			set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK,
++				smbios_cru64_ptr->double_length >> PAGE_SHIFT);
+ 		}
+ 	}
+ }
+@@ -482,7 +485,7 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason,
+ 			"Management Log for details.\n");
+ 	}
+ 
+-	return NOTIFY_STOP;
++	return NOTIFY_OK;
+ }
+ 
+ /*
+diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
+index 69a12aa..490e34b 100644
+--- a/fs/cifs/cifs_debug.c
++++ b/fs/cifs/cifs_debug.c
+@@ -107,12 +107,13 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
+ #ifdef CONFIG_PROC_FS
+ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
+ {
+-	struct list_head *tmp;
+-	struct list_head *tmp1;
++	struct list_head *tmp1, *tmp2, *tmp3;
+ 	struct mid_q_entry *mid_entry;
++	struct TCP_Server_Info *server;
+ 	struct cifsSesInfo *ses;
+ 	struct cifsTconInfo *tcon;
+-	int i;
++	int i, j;
++	__u32 dev_type;
+ 
+ 	seq_puts(m,
+ 		    "Display Internal CIFS Data Structures for Debugging\n"
+@@ -122,46 +123,78 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
+ 	seq_printf(m, "Servers:");
+ 
+ 	i = 0;
+-	read_lock(&GlobalSMBSeslock);
+-	list_for_each(tmp, &GlobalSMBSessionList) {
++	read_lock(&cifs_tcp_ses_lock);
++	list_for_each(tmp1, &cifs_tcp_ses_list) {
++		server = list_entry(tmp1, struct TCP_Server_Info,
++				    tcp_ses_list);
+ 		i++;
+-		ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
+-		if ((ses->serverDomain == NULL) || (ses->serverOS == NULL) ||
+-		   (ses->serverNOS == NULL)) {
+-			seq_printf(m, "\nentry for %s not fully "
+-					"displayed\n\t", ses->serverName);
+-		} else {
+-			seq_printf(m,
+-				    "\n%d) Name: %s  Domain: %s Mounts: %d OS:"
+-				    " %s  \n\tNOS: %s\tCapability: 0x%x\n\tSMB"
++		list_for_each(tmp2, &server->smb_ses_list) {
++			ses = list_entry(tmp2, struct cifsSesInfo,
++					 smb_ses_list);
++			if ((ses->serverDomain == NULL) ||
++				(ses->serverOS == NULL) ||
++				(ses->serverNOS == NULL)) {
++				seq_printf(m, "\n%d) entry for %s not fully "
++					   "displayed\n\t", i, ses->serverName);
++			} else {
++				seq_printf(m,
++				    "\n%d) Name: %s  Domain: %s Uses: %d OS:"
++				    " %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB"
+ 				    " session status: %d\t",
+ 				i, ses->serverName, ses->serverDomain,
+-				atomic_read(&ses->inUse),
+-				ses->serverOS, ses->serverNOS,
++				ses->ses_count, ses->serverOS, ses->serverNOS,
+ 				ses->capabilities, ses->status);
+-		}
+-		if (ses->server) {
++			}
+ 			seq_printf(m, "TCP status: %d\n\tLocal Users To "
+-				    "Server: %d SecMode: 0x%x Req On Wire: %d",
+-				ses->server->tcpStatus,
+-				atomic_read(&ses->server->socketUseCount),
+-				ses->server->secMode,
+-				atomic_read(&ses->server->inFlight));
++				   "Server: %d SecMode: 0x%x Req On Wire: %d",
++				   server->tcpStatus, server->srv_count,
++				   server->secMode,
++				   atomic_read(&server->inFlight));
+ 
+ #ifdef CONFIG_CIFS_STATS2
+ 			seq_printf(m, " In Send: %d In MaxReq Wait: %d",
+-				atomic_read(&ses->server->inSend),
+-				atomic_read(&ses->server->num_waiters));
++				atomic_read(&server->inSend),
++				atomic_read(&server->num_waiters));
+ #endif
+ 
+-			seq_puts(m, "\nMIDs:\n");
++			seq_puts(m, "\n\tShares:");
++			j = 0;
++			list_for_each(tmp3, &ses->tcon_list) {
++				tcon = list_entry(tmp3, struct cifsTconInfo,
++						  tcon_list);
++				++j;
++				dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
++				seq_printf(m, "\n\t%d) %s Mounts: %d ", j,
++					   tcon->treeName, tcon->tc_count);
++				if (tcon->nativeFileSystem) {
++					seq_printf(m, "Type: %s ",
++						   tcon->nativeFileSystem);
++				}
++				seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x"
++					"\nPathComponentMax: %d Status: 0x%d",
++					le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
++					le32_to_cpu(tcon->fsAttrInfo.Attributes),
++					le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
++					tcon->tidStatus);
++				if (dev_type == FILE_DEVICE_DISK)
++					seq_puts(m, " type: DISK ");
++				else if (dev_type == FILE_DEVICE_CD_ROM)
++					seq_puts(m, " type: CDROM ");
++				else
++					seq_printf(m, " type: %d ", dev_type);
++
++				if (tcon->need_reconnect)
++					seq_puts(m, "\tDISCONNECTED ");
++				seq_putc(m, '\n');
++			}
++
++			seq_puts(m, "\n\tMIDs:\n");
+ 
+ 			spin_lock(&GlobalMid_Lock);
+-			list_for_each(tmp1, &ses->server->pending_mid_q) {
+-				mid_entry = list_entry(tmp1, struct
+-					mid_q_entry,
++			list_for_each(tmp3, &server->pending_mid_q) {
++				mid_entry = list_entry(tmp3, struct mid_q_entry,
+ 					qhead);
+-				seq_printf(m, "State: %d com: %d pid:"
++				seq_printf(m, "\tState: %d com: %d pid:"
+ 						" %d tsk: %p mid %d\n",
+ 						mid_entry->midState,
+ 						(int)mid_entry->command,
+@@ -171,44 +204,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
+ 			}
+ 			spin_unlock(&GlobalMid_Lock);
+ 		}
+-
+-	}
+-	read_unlock(&GlobalSMBSeslock);
+-	seq_putc(m, '\n');
+-
+-	seq_puts(m, "Shares:");
+-
+-	i = 0;
+-	read_lock(&GlobalSMBSeslock);
+-	list_for_each(tmp, &GlobalTreeConnectionList) {
+-		__u32 dev_type;
+-		i++;
+-		tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
+-		dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
+-		seq_printf(m, "\n%d) %s Uses: %d ", i,
+-				 tcon->treeName, atomic_read(&tcon->useCount));
+-		if (tcon->nativeFileSystem) {
+-			seq_printf(m, "Type: %s ",
+-					 tcon->nativeFileSystem);
+-		}
+-		seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x"
+-				 "\nPathComponentMax: %d Status: %d",
+-			    le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
+-			    le32_to_cpu(tcon->fsAttrInfo.Attributes),
+-			    le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
+-			    tcon->tidStatus);
+-		if (dev_type == FILE_DEVICE_DISK)
+-			seq_puts(m, " type: DISK ");
+-		else if (dev_type == FILE_DEVICE_CD_ROM)
+-			seq_puts(m, " type: CDROM ");
+-		else
+-			seq_printf(m, " type: %d ", dev_type);
+-
+-		if (tcon->tidStatus == CifsNeedReconnect)
+-			seq_puts(m, "\tDISCONNECTED ");
+ 	}
+-	read_unlock(&GlobalSMBSeslock);
+-
++	read_unlock(&cifs_tcp_ses_lock);
+ 	seq_putc(m, '\n');
+ 
+ 	/* BB add code to dump additional info such as TCP session info now */
+@@ -234,7 +231,9 @@ static ssize_t cifs_stats_proc_write(struct file *file,
+ {
+ 	char c;
+ 	int rc;
+-	struct list_head *tmp;
++	struct list_head *tmp1, *tmp2, *tmp3;
++	struct TCP_Server_Info *server;
++	struct cifsSesInfo *ses;
+ 	struct cifsTconInfo *tcon;
+ 
+ 	rc = get_user(c, buffer);
+@@ -242,33 +241,42 @@ static ssize_t cifs_stats_proc_write(struct file *file,
+ 		return rc;
+ 
+ 	if (c == '1' || c == 'y' || c == 'Y' || c == '0') {
+-		read_lock(&GlobalSMBSeslock);
+ #ifdef CONFIG_CIFS_STATS2
+ 		atomic_set(&totBufAllocCount, 0);
+ 		atomic_set(&totSmBufAllocCount, 0);
+ #endif /* CONFIG_CIFS_STATS2 */
+-		list_for_each(tmp, &GlobalTreeConnectionList) {
+-			tcon = list_entry(tmp, struct cifsTconInfo,
+-					cifsConnectionList);
+-			atomic_set(&tcon->num_smbs_sent, 0);
+-			atomic_set(&tcon->num_writes, 0);
+-			atomic_set(&tcon->num_reads, 0);
+-			atomic_set(&tcon->num_oplock_brks, 0);
+-			atomic_set(&tcon->num_opens, 0);
+-			atomic_set(&tcon->num_closes, 0);
+-			atomic_set(&tcon->num_deletes, 0);
+-			atomic_set(&tcon->num_mkdirs, 0);
+-			atomic_set(&tcon->num_rmdirs, 0);
+-			atomic_set(&tcon->num_renames, 0);
+-			atomic_set(&tcon->num_t2renames, 0);
+-			atomic_set(&tcon->num_ffirst, 0);
+-			atomic_set(&tcon->num_fnext, 0);
+-			atomic_set(&tcon->num_fclose, 0);
+-			atomic_set(&tcon->num_hardlinks, 0);
+-			atomic_set(&tcon->num_symlinks, 0);
+-			atomic_set(&tcon->num_locks, 0);
++		read_lock(&cifs_tcp_ses_lock);
++		list_for_each(tmp1, &cifs_tcp_ses_list) {
++			server = list_entry(tmp1, struct TCP_Server_Info,
++					    tcp_ses_list);
++			list_for_each(tmp2, &server->smb_ses_list) {
++				ses = list_entry(tmp2, struct cifsSesInfo,
++						 smb_ses_list);
++				list_for_each(tmp3, &ses->tcon_list) {
++					tcon = list_entry(tmp3,
++							  struct cifsTconInfo,
++							  tcon_list);
++					atomic_set(&tcon->num_smbs_sent, 0);
++					atomic_set(&tcon->num_writes, 0);
++					atomic_set(&tcon->num_reads, 0);
++					atomic_set(&tcon->num_oplock_brks, 0);
++					atomic_set(&tcon->num_opens, 0);
++					atomic_set(&tcon->num_closes, 0);
++					atomic_set(&tcon->num_deletes, 0);
++					atomic_set(&tcon->num_mkdirs, 0);
++					atomic_set(&tcon->num_rmdirs, 0);
++					atomic_set(&tcon->num_renames, 0);
++					atomic_set(&tcon->num_t2renames, 0);
++					atomic_set(&tcon->num_ffirst, 0);
++					atomic_set(&tcon->num_fnext, 0);
++					atomic_set(&tcon->num_fclose, 0);
++					atomic_set(&tcon->num_hardlinks, 0);
++					atomic_set(&tcon->num_symlinks, 0);
++					atomic_set(&tcon->num_locks, 0);
++				}
++			}
+ 		}
+-		read_unlock(&GlobalSMBSeslock);
++		read_unlock(&cifs_tcp_ses_lock);
+ 	}
+ 
+ 	return count;
+@@ -277,7 +285,9 @@ static ssize_t cifs_stats_proc_write(struct file *file,
+ static int cifs_stats_proc_show(struct seq_file *m, void *v)
+ {
+ 	int i;
+-	struct list_head *tmp;
++	struct list_head *tmp1, *tmp2, *tmp3;
++	struct TCP_Server_Info *server;
++	struct cifsSesInfo *ses;
+ 	struct cifsTconInfo *tcon;
+ 
+ 	seq_printf(m,
+@@ -306,44 +316,55 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
+ 		GlobalCurrentXid, GlobalMaxActiveXid);
+ 
+ 	i = 0;
+-	read_lock(&GlobalSMBSeslock);
+-	list_for_each(tmp, &GlobalTreeConnectionList) {
+-		i++;
+-		tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
+-		seq_printf(m, "\n%d) %s", i, tcon->treeName);
+-		if (tcon->tidStatus == CifsNeedReconnect)
+-			seq_puts(m, "\tDISCONNECTED ");
+-		seq_printf(m, "\nSMBs: %d Oplock Breaks: %d",
+-			atomic_read(&tcon->num_smbs_sent),
+-			atomic_read(&tcon->num_oplock_brks));
+-		seq_printf(m, "\nReads:  %d Bytes: %lld",
+-			atomic_read(&tcon->num_reads),
+-			(long long)(tcon->bytes_read));
+-		seq_printf(m, "\nWrites: %d Bytes: %lld",
+-			atomic_read(&tcon->num_writes),
+-			(long long)(tcon->bytes_written));
+-		seq_printf(m,
+-			"\nLocks: %d HardLinks: %d Symlinks: %d",
+-			atomic_read(&tcon->num_locks),
+-			atomic_read(&tcon->num_hardlinks),
+-			atomic_read(&tcon->num_symlinks));
+-
+-		seq_printf(m, "\nOpens: %d Closes: %d Deletes: %d",
+-			atomic_read(&tcon->num_opens),
+-			atomic_read(&tcon->num_closes),
+-			atomic_read(&tcon->num_deletes));
+-		seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
+-			atomic_read(&tcon->num_mkdirs),
+-			atomic_read(&tcon->num_rmdirs));
+-		seq_printf(m, "\nRenames: %d T2 Renames %d",
+-			atomic_read(&tcon->num_renames),
+-			atomic_read(&tcon->num_t2renames));
+-		seq_printf(m, "\nFindFirst: %d FNext %d FClose %d",
+-			atomic_read(&tcon->num_ffirst),
+-			atomic_read(&tcon->num_fnext),
+-			atomic_read(&tcon->num_fclose));
++	read_lock(&cifs_tcp_ses_lock);
++	list_for_each(tmp1, &cifs_tcp_ses_list) {
++		server = list_entry(tmp1, struct TCP_Server_Info,
++				    tcp_ses_list);
++		list_for_each(tmp2, &server->smb_ses_list) {
++			ses = list_entry(tmp2, struct cifsSesInfo,
++					 smb_ses_list);
++			list_for_each(tmp3, &ses->tcon_list) {
++				tcon = list_entry(tmp3,
++						  struct cifsTconInfo,
++						  tcon_list);
++				i++;
++				seq_printf(m, "\n%d) %s", i, tcon->treeName);
++				if (tcon->need_reconnect)
++					seq_puts(m, "\tDISCONNECTED ");
++				seq_printf(m, "\nSMBs: %d Oplock Breaks: %d",
++					atomic_read(&tcon->num_smbs_sent),
++					atomic_read(&tcon->num_oplock_brks));
++				seq_printf(m, "\nReads:  %d Bytes: %lld",
++					atomic_read(&tcon->num_reads),
++					(long long)(tcon->bytes_read));
++				seq_printf(m, "\nWrites: %d Bytes: %lld",
++					atomic_read(&tcon->num_writes),
++					(long long)(tcon->bytes_written));
++				seq_printf(m, "\nLocks: %d HardLinks: %d "
++					      "Symlinks: %d",
++					atomic_read(&tcon->num_locks),
++					atomic_read(&tcon->num_hardlinks),
++					atomic_read(&tcon->num_symlinks));
++				seq_printf(m, "\nOpens: %d Closes: %d"
++					      "Deletes: %d",
++					atomic_read(&tcon->num_opens),
++					atomic_read(&tcon->num_closes),
++					atomic_read(&tcon->num_deletes));
++				seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
++					atomic_read(&tcon->num_mkdirs),
++					atomic_read(&tcon->num_rmdirs));
++				seq_printf(m, "\nRenames: %d T2 Renames %d",
++					atomic_read(&tcon->num_renames),
++					atomic_read(&tcon->num_t2renames));
++				seq_printf(m, "\nFindFirst: %d FNext %d "
++					      "FClose %d",
++					atomic_read(&tcon->num_ffirst),
++					atomic_read(&tcon->num_fnext),
++					atomic_read(&tcon->num_fclose));
++			}
++		}
+ 	}
+-	read_unlock(&GlobalSMBSeslock);
++	read_unlock(&cifs_tcp_ses_lock);
+ 
+ 	seq_putc(m, '\n');
+ 	return 0;
+diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c
+index 117ef4b..d0758b2 100644
+--- a/fs/cifs/cifs_spnego.c
++++ b/fs/cifs/cifs_spnego.c
+@@ -70,7 +70,8 @@ struct key_type cifs_spnego_key_type = {
+ 				strlen("ver=0xFF") */
+ #define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg
+ 			       in future could have strlen(";sec=ntlmsspi") */
+-#define MAX_IPV6_ADDR_LEN 42 /* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */
++/* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/128 */
++#define MAX_IPV6_ADDR_LEN	43
+ /* get a key struct with a SPNEGO security blob, suitable for session setup */
+ struct key *
+ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
+diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
+index 25ecbd5..2fcc66c 100644
+--- a/fs/cifs/cifsfs.c
++++ b/fs/cifs/cifsfs.c
+@@ -510,10 +510,11 @@ static void cifs_umount_begin(struct super_block *sb)
+ 	tcon = cifs_sb->tcon;
+ 	if (tcon == NULL)
+ 		return;
+-	down(&tcon->tconSem);
+-	if (atomic_read(&tcon->useCount) == 1)
++
++	read_lock(&cifs_tcp_ses_lock);
++	if (tcon->tc_count == 1)
+ 		tcon->tidStatus = CifsExiting;
+-	up(&tcon->tconSem);
++	read_unlock(&cifs_tcp_ses_lock);
+ 
+ 	/* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
+ 	/* cancel_notify_requests(tcon); */
+@@ -967,7 +968,7 @@ static int cifs_oplock_thread(void *dummyarg)
+ 				not bother sending an oplock release if session
+ 				to server still is disconnected since oplock
+ 				already released by the server in that case */
+-			if (pTcon->tidStatus != CifsNeedReconnect) {
++			if (!pTcon->need_reconnect) {
+ 				rc = CIFSSMBLock(0, pTcon, netfid,
+ 						0 /* len */ , 0 /* offset */, 0,
+ 						0, LOCKING_ANDX_OPLOCK_RELEASE,
+@@ -985,24 +986,24 @@ static int cifs_oplock_thread(void *dummyarg)
+ static int cifs_dnotify_thread(void *dummyarg)
+ {
+ 	struct list_head *tmp;
+-	struct cifsSesInfo *ses;
++	struct TCP_Server_Info *server;
+ 
+ 	do {
+ 		if (try_to_freeze())
+ 			continue;
+ 		set_current_state(TASK_INTERRUPTIBLE);
+ 		schedule_timeout(15*HZ);
+-		read_lock(&GlobalSMBSeslock);
+ 		/* check if any stuck requests that need
+ 		   to be woken up and wakeq so the
+ 		   thread can wake up and error out */
+-		list_for_each(tmp, &GlobalSMBSessionList) {
+-			ses = list_entry(tmp, struct cifsSesInfo,
+-				cifsSessionList);
+-			if (ses->server && atomic_read(&ses->server->inFlight))
+-				wake_up_all(&ses->server->response_q);
++		read_lock(&cifs_tcp_ses_lock);
++		list_for_each(tmp, &cifs_tcp_ses_list) {
++			server = list_entry(tmp, struct TCP_Server_Info,
++					 tcp_ses_list);
++			if (atomic_read(&server->inFlight))
++				wake_up_all(&server->response_q);
+ 		}
+-		read_unlock(&GlobalSMBSeslock);
++		read_unlock(&cifs_tcp_ses_lock);
+ 	} while (!kthread_should_stop());
+ 
+ 	return 0;
+@@ -1013,9 +1014,7 @@ init_cifs(void)
+ {
+ 	int rc = 0;
+ 	cifs_proc_init();
+-/*	INIT_LIST_HEAD(&GlobalServerList);*/	/* BB not implemented yet */
+-	INIT_LIST_HEAD(&GlobalSMBSessionList);
+-	INIT_LIST_HEAD(&GlobalTreeConnectionList);
++	INIT_LIST_HEAD(&cifs_tcp_ses_list);
+ 	INIT_LIST_HEAD(&GlobalOplock_Q);
+ #ifdef CONFIG_CIFS_EXPERIMENTAL
+ 	INIT_LIST_HEAD(&GlobalDnotifyReqList);
+@@ -1043,6 +1042,7 @@ init_cifs(void)
+ 	GlobalMaxActiveXid = 0;
+ 	memset(Local_System_Name, 0, 15);
+ 	rwlock_init(&GlobalSMBSeslock);
++	rwlock_init(&cifs_tcp_ses_lock);
+ 	spin_lock_init(&GlobalMid_Lock);
+ 
+ 	if (cifs_max_pending < 2) {
+diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
+index 0d22479..1ae6314 100644
+--- a/fs/cifs/cifsglob.h
++++ b/fs/cifs/cifsglob.h
+@@ -85,8 +85,7 @@ enum securityEnum {
+ };
+ 
+ enum protocolEnum {
+-	IPV4 = 0,
+-	IPV6,
++	TCP = 0,
+ 	SCTP
+ 	/* Netbios frames protocol not supported at this time */
+ };
+@@ -122,6 +121,9 @@ struct cifs_cred {
+  */
+ 
+ struct TCP_Server_Info {
++	struct list_head tcp_ses_list;
++	struct list_head smb_ses_list;
++	int srv_count; /* reference counter */
+ 	/* 15 character server name + 0x20 16th byte indicating type = srv */
+ 	char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
+ 	char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
+@@ -141,7 +143,8 @@ struct TCP_Server_Info {
+ 	char versionMajor;
+ 	char versionMinor;
+ 	bool svlocal:1;			/* local server or remote */
+-	atomic_t socketUseCount; /* number of open cifs sessions on socket */
++	bool noblocksnd;		/* use blocking sendmsg */
++	bool noautotune;		/* do not autotune send buf sizes */
+ 	atomic_t inFlight;  /* number of requests on the wire to server */
+ #ifdef CONFIG_CIFS_STATS2
+ 	atomic_t inSend; /* requests trying to send */
+@@ -192,13 +195,14 @@ struct cifsUidInfo {
+  * Session structure.  One of these for each uid session with a particular host
+  */
+ struct cifsSesInfo {
+-	struct list_head cifsSessionList;
++	struct list_head smb_ses_list;
++	struct list_head tcon_list;
+ 	struct semaphore sesSem;
+ #if 0
+ 	struct cifsUidInfo *uidInfo;	/* pointer to user info */
+ #endif
+ 	struct TCP_Server_Info *server;	/* pointer to server info */
+-	atomic_t inUse; /* # of mounts (tree connections) on this ses */
++	int ses_count;		/* reference counter */
+ 	enum statusEnum status;
+ 	unsigned overrideSecFlg;  /* if non-zero override global sec flags */
+ 	__u16 ipc_tid;		/* special tid for connection to IPC share */
+@@ -214,6 +218,7 @@ struct cifsSesInfo {
+ 	char userName[MAX_USERNAME_SIZE + 1];
+ 	char *domainName;
+ 	char *password;
++	bool need_reconnect:1; /* connection reset, uid now invalid */
+ };
+ /* no more than one of the following three session flags may be set */
+ #define CIFS_SES_NT4 1
+@@ -228,16 +233,15 @@ struct cifsSesInfo {
+  * session
+  */
+ struct cifsTconInfo {
+-	struct list_head cifsConnectionList;
++	struct list_head tcon_list;
++	int tc_count;
+ 	struct list_head openFileList;
+-	struct semaphore tconSem;
+ 	struct cifsSesInfo *ses;	/* pointer to session associated with */
+ 	char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
+ 	char *nativeFileSystem;
+ 	__u16 tid;		/* The 2 byte tree id */
+ 	__u16 Flags;		/* optional support bits */
+ 	enum statusEnum tidStatus;
+-	atomic_t useCount;	/* how many explicit/implicit mounts to share */
+ #ifdef CONFIG_CIFS_STATS
+ 	atomic_t num_smbs_sent;
+ 	atomic_t num_writes;
+@@ -285,6 +289,7 @@ struct cifsTconInfo {
+ 	bool seal:1;      /* transport encryption for this mounted share */
+ 	bool unix_ext:1;  /* if false disable Linux extensions to CIFS protocol
+ 				for this mount even if server would support */
++	bool need_reconnect:1; /* connection reset, tid now invalid */
+ 	/* BB add field for back pointer to sb struct(s)? */
+ };
+ 
+@@ -584,21 +589,21 @@ require use of the stronger protocol */
+ #endif
+ 
+ /*
+- * The list of servers that did not respond with NT LM 0.12.
+- * This list helps improve performance and eliminate the messages indicating
+- * that we had a communications error talking to the server in this list.
++ * the list of TCP_Server_Info structures, ie each of the sockets
++ * connecting our client to a distinct server (ip address), is
++ * chained together by cifs_tcp_ses_list. The list of all our SMB
++ * sessions (and from that the tree connections) can be found
++ * by iterating over cifs_tcp_ses_list
+  */
+-/* Feature not supported */
+-/* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */
++GLOBAL_EXTERN struct list_head		cifs_tcp_ses_list;
+ 
+ /*
+- * The following is a hash table of all the users we know about.
++ * This lock protects the cifs_tcp_ses_list, the list of smb sessions per
++ * tcp session, and the list of tcon's per smb session. It also protects
++ * the reference counters for the server, smb session, and tcon. Finally,
++ * changes to the tcon->tidStatus should be done while holding this lock.
+  */
+-GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH];
+-
+-/* GLOBAL_EXTERN struct list_head GlobalServerList; BB not implemented yet */
+-GLOBAL_EXTERN struct list_head GlobalSMBSessionList;
+-GLOBAL_EXTERN struct list_head GlobalTreeConnectionList;
++GLOBAL_EXTERN rwlock_t		cifs_tcp_ses_lock;
+ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock;  /* protects list inserts on 3 above */
+ 
+ GLOBAL_EXTERN struct list_head GlobalOplock_Q;
+diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
+index a729d08..ca91f16 100644
+--- a/fs/cifs/cifsproto.h
++++ b/fs/cifs/cifsproto.h
+@@ -36,7 +36,7 @@ extern void cifs_buf_release(void *);
+ extern struct smb_hdr *cifs_small_buf_get(void);
+ extern void cifs_small_buf_release(void *);
+ extern int smb_send(struct socket *, struct smb_hdr *,
+-			unsigned int /* length */ , struct sockaddr *);
++			unsigned int /* length */ , struct sockaddr *, bool);
+ extern unsigned int _GetXid(void);
+ extern void _FreeXid(unsigned int);
+ #define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current->fsuid));
+diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
+index 77a0d1f..8f0f86d 100644
+--- a/fs/cifs/cifssmb.c
++++ b/fs/cifs/cifssmb.c
+@@ -190,10 +190,10 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
+ 		/* need to prevent multiple threads trying to
+ 		simultaneously reconnect the same SMB session */
+ 			down(&tcon->ses->sesSem);
+-			if (tcon->ses->status == CifsNeedReconnect)
++			if (tcon->ses->need_reconnect)
+ 				rc = cifs_setup_session(0, tcon->ses,
+ 							nls_codepage);
+-			if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
++			if (!rc && (tcon->need_reconnect)) {
+ 				mark_open_files_invalid(tcon);
+ 				rc = CIFSTCon(0, tcon->ses, tcon->treeName,
+ 					      tcon, nls_codepage);
+@@ -337,10 +337,10 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
+ 		/* need to prevent multiple threads trying to
+ 		simultaneously reconnect the same SMB session */
+ 			down(&tcon->ses->sesSem);
+-			if (tcon->ses->status == CifsNeedReconnect)
++			if (tcon->ses->need_reconnect)
+ 				rc = cifs_setup_session(0, tcon->ses,
+ 							nls_codepage);
+-			if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
++			if (!rc && (tcon->need_reconnect)) {
+ 				mark_open_files_invalid(tcon);
+ 				rc = CIFSTCon(0, tcon->ses, tcon->treeName,
+ 					      tcon, nls_codepage);
+@@ -664,8 +664,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
+ 			rc = -EIO;
+ 			goto neg_err_exit;
+ 		}
+-
+-		if (server->socketUseCount.counter > 1) {
++		read_lock(&cifs_tcp_ses_lock);
++		if (server->srv_count > 1) {
++			read_unlock(&cifs_tcp_ses_lock);
+ 			if (memcmp(server->server_GUID,
+ 				   pSMBr->u.extended_response.
+ 				   GUID, 16) != 0) {
+@@ -674,9 +675,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
+ 					pSMBr->u.extended_response.GUID,
+ 					16);
+ 			}
+-		} else
++		} else {
++			read_unlock(&cifs_tcp_ses_lock);
+ 			memcpy(server->server_GUID,
+ 			       pSMBr->u.extended_response.GUID, 16);
++		}
+ 
+ 		if (count == 16) {
+ 			server->secType = RawNTLMSSP;
+@@ -739,50 +742,31 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
+ 	int rc = 0;
+ 
+ 	cFYI(1, ("In tree disconnect"));
+-	/*
+-	 *  If last user of the connection and
+-	 *  connection alive - disconnect it
+-	 *  If this is the last connection on the server session disconnect it
+-	 *  (and inside session disconnect we should check if tcp socket needs
+-	 *  to be freed and kernel thread woken up).
+-	 */
+-	if (tcon)
+-		down(&tcon->tconSem);
+-	else
+-		return -EIO;
+ 
+-	atomic_dec(&tcon->useCount);
+-	if (atomic_read(&tcon->useCount) > 0) {
+-		up(&tcon->tconSem);
+-		return -EBUSY;
+-	}
++	/* BB: do we need to check this? These should never be NULL. */
++	if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
++		return -EIO;
+ 
+-	/* No need to return error on this operation if tid invalidated and
+-	closed on server already e.g. due to tcp session crashing */
+-	if (tcon->tidStatus == CifsNeedReconnect) {
+-		up(&tcon->tconSem);
++	/*
++	 * No need to return error on this operation if tid invalidated and
++	 * closed on server already e.g. due to tcp session crashing. Also,
++	 * the tcon is no longer on the list, so no need to take lock before
++	 * checking this.
++	 */
++	if (tcon->need_reconnect)
+ 		return 0;
+-	}
+ 
+-	if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
+-		up(&tcon->tconSem);
+-		return -EIO;
+-	}
+ 	rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
+ 			    (void **)&smb_buffer);
+-	if (rc) {
+-		up(&tcon->tconSem);
++	if (rc)
+ 		return rc;
+-	}
+ 
+ 	rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
+ 	if (rc)
+ 		cFYI(1, ("Tree disconnect failed %d", rc));
+ 
+-	up(&tcon->tconSem);
+-
+ 	/* No need to return error on this operation if tid invalidated and
+-	closed on server already e.g. due to tcp session crashing */
++	   closed on server already e.g. due to tcp session crashing */
+ 	if (rc == -EAGAIN)
+ 		rc = 0;
+ 
+@@ -796,43 +780,36 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
+ 	int rc = 0;
+ 
+ 	cFYI(1, ("In SMBLogoff for session disconnect"));
+-	if (ses)
+-		down(&ses->sesSem);
+-	else
++
++	/*
++	 * BB: do we need to check validity of ses and server? They should
++	 * always be valid since we have an active reference. If not, that
++	 * should probably be a BUG()
++	 */
++	if (!ses || !ses->server)
+ 		return -EIO;
+ 
+-	atomic_dec(&ses->inUse);
+-	if (atomic_read(&ses->inUse) > 0) {
+-		up(&ses->sesSem);
+-		return -EBUSY;
+-	}
++	down(&ses->sesSem);
++	if (ses->need_reconnect)
++		goto session_already_dead; /* no need to send SMBlogoff if uid
++					      already closed due to reconnect */
+ 	rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
+ 	if (rc) {
+ 		up(&ses->sesSem);
+ 		return rc;
+ 	}
+ 
+-	if (ses->server) {
+-		pSMB->hdr.Mid = GetNextMid(ses->server);
++	pSMB->hdr.Mid = GetNextMid(ses->server);
+ 
+-		if (ses->server->secMode &
++	if (ses->server->secMode &
+ 		   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ 			pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+-	}
+ 
+ 	pSMB->hdr.Uid = ses->Suid;
+ 
+ 	pSMB->AndXCommand = 0xFF;
+ 	rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
+-	if (ses->server) {
+-		atomic_dec(&ses->server->socketUseCount);
+-		if (atomic_read(&ses->server->socketUseCount) == 0) {
+-			spin_lock(&GlobalMid_Lock);
+-			ses->server->tcpStatus = CifsExiting;
+-			spin_unlock(&GlobalMid_Lock);
+-			rc = -ESHUTDOWN;
+-		}
+-	}
++session_already_dead:
+ 	up(&ses->sesSem);
+ 
+ 	/* if session dead then we do not need to do ulogoff,
+@@ -1534,7 +1511,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
+ 	__u32 bytes_sent;
+ 	__u16 byte_count;
+ 
+-	/* cFYI(1,("write at %lld %d bytes",offset,count));*/
++	/* cFYI(1, ("write at %lld %d bytes",offset,count));*/
+ 	if (tcon->ses == NULL)
+ 		return -ECONNABORTED;
+ 
+diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
+index 4c13bcd..6e2be4a 100644
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -90,6 +90,8 @@ struct smb_vol {
+ 	bool nocase:1;     /* request case insensitive filenames */
+ 	bool nobrl:1;      /* disable sending byte range locks to srv */
+ 	bool seal:1;       /* request transport encryption on share */
++	bool noblocksnd:1;
++	bool noautotune:1;
+ 	unsigned int rsize;
+ 	unsigned int wsize;
+ 	unsigned int sockopt;
+@@ -100,9 +102,11 @@ struct smb_vol {
+ static int ipv4_connect(struct sockaddr_in *psin_server,
+ 			struct socket **csocket,
+ 			char *netb_name,
+-			char *server_netb_name);
++			char *server_netb_name,
++			bool noblocksnd,
++			bool nosndbuf); /* ipv6 never set sndbuf size */
+ static int ipv6_connect(struct sockaddr_in6 *psin_server,
+-			struct socket **csocket);
++			struct socket **csocket, bool noblocksnd);
+ 
+ 
+ 	/*
+@@ -118,7 +122,7 @@ static int
+ cifs_reconnect(struct TCP_Server_Info *server)
+ {
+ 	int rc = 0;
+-	struct list_head *tmp;
++	struct list_head *tmp, *tmp2;
+ 	struct cifsSesInfo *ses;
+ 	struct cifsTconInfo *tcon;
+ 	struct mid_q_entry *mid_entry;
+@@ -138,23 +142,17 @@ cifs_reconnect(struct TCP_Server_Info *server)
+ 
+ 	/* before reconnecting the tcp session, mark the smb session (uid)
+ 		and the tid bad so they are not used until reconnected */
+-	read_lock(&GlobalSMBSeslock);
+-	list_for_each(tmp, &GlobalSMBSessionList) {
+-		ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
+-		if (ses->server) {
+-			if (ses->server == server) {
+-				ses->status = CifsNeedReconnect;
+-				ses->ipc_tid = 0;
+-			}
++	read_lock(&cifs_tcp_ses_lock);
++	list_for_each(tmp, &server->smb_ses_list) {
++		ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
++		ses->need_reconnect = true;
++		ses->ipc_tid = 0;
++		list_for_each(tmp2, &ses->tcon_list) {
++			tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list);
++			tcon->need_reconnect = true;
+ 		}
+-		/* else tcp and smb sessions need reconnection */
+-	}
+-	list_for_each(tmp, &GlobalTreeConnectionList) {
+-		tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
+-		if ((tcon->ses) && (tcon->ses->server == server))
+-			tcon->tidStatus = CifsNeedReconnect;
+ 	}
+-	read_unlock(&GlobalSMBSeslock);
++	read_unlock(&cifs_tcp_ses_lock);
+ 	/* do not want to be sending data on a socket we are freeing */
+ 	down(&server->tcpSem);
+ 	if (server->ssocket) {
+@@ -186,14 +184,15 @@ cifs_reconnect(struct TCP_Server_Info *server)
+ 
+ 	while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) {
+ 		try_to_freeze();
+-		if (server->protocolType == IPV6) {
++		if (server->addr.sockAddr6.sin6_family == AF_INET6) {
+ 			rc = ipv6_connect(&server->addr.sockAddr6,
+-					  &server->ssocket);
++					  &server->ssocket, server->noautotune);
+ 		} else {
+ 			rc = ipv4_connect(&server->addr.sockAddr,
+ 					&server->ssocket,
+ 					server->workstation_RFC1001_name,
+-					server->server_RFC1001_name);
++					server->server_RFC1001_name,
++					server->noblocksnd, server->noautotune);
+ 		}
+ 		if (rc) {
+ 			cFYI(1, ("reconnect error %d", rc));
+@@ -409,8 +408,14 @@ incomplete_rcv:
+ 			msleep(1); /* minimum sleep to prevent looping
+ 				allowing socket to clear and app threads to set
+ 				tcpStatus CifsNeedReconnect if server hung */
+-			if (pdu_length < 4)
++			if (pdu_length < 4) {
++				iov.iov_base = (4 - pdu_length) +
++						(char *)smb_buffer;
++				iov.iov_len = pdu_length;
++				smb_msg.msg_control = NULL;
++				smb_msg.msg_controllen = 0;
+ 				goto incomplete_rcv;
++			}
+ 			else
+ 				continue;
+ 		} else if (length <= 0) {
+@@ -646,6 +651,11 @@ multi_t2_fnd:
+ 		}
+ 	} /* end while !EXITING */
+ 
++	/* take it off the list, if it's not already */
++	write_lock(&cifs_tcp_ses_lock);
++	list_del_init(&server->tcp_ses_list);
++	write_unlock(&cifs_tcp_ses_lock);
++
+ 	spin_lock(&GlobalMid_Lock);
+ 	server->tcpStatus = CifsExiting;
+ 	spin_unlock(&GlobalMid_Lock);
+@@ -686,29 +696,29 @@ multi_t2_fnd:
+ 	if (smallbuf) /* no sense logging a debug message if NULL */
+ 		cifs_small_buf_release(smallbuf);
+ 
+-	read_lock(&GlobalSMBSeslock);
++	/*
++	 * BB: we shouldn't have to do any of this. It shouldn't be
++	 * possible to exit from the thread with active SMB sessions
++	 */
++	read_lock(&cifs_tcp_ses_lock);
+ 	if (list_empty(&server->pending_mid_q)) {
+ 		/* loop through server session structures attached to this and
+ 		    mark them dead */
+-		list_for_each(tmp, &GlobalSMBSessionList) {
+-			ses =
+-			    list_entry(tmp, struct cifsSesInfo,
+-				       cifsSessionList);
+-			if (ses->server == server) {
+-				ses->status = CifsExiting;
+-				ses->server = NULL;
+-			}
++		list_for_each(tmp, &server->smb_ses_list) {
++			ses = list_entry(tmp, struct cifsSesInfo,
++					 smb_ses_list);
++			ses->status = CifsExiting;
++			ses->server = NULL;
+ 		}
+-		read_unlock(&GlobalSMBSeslock);
++		read_unlock(&cifs_tcp_ses_lock);
+ 	} else {
+ 		/* although we can not zero the server struct pointer yet,
+ 		since there are active requests which may depnd on them,
+ 		mark the corresponding SMB sessions as exiting too */
+-		list_for_each(tmp, &GlobalSMBSessionList) {
++		list_for_each(tmp, &server->smb_ses_list) {
+ 			ses = list_entry(tmp, struct cifsSesInfo,
+-					 cifsSessionList);
+-			if (ses->server == server)
+-				ses->status = CifsExiting;
++					 smb_ses_list);
++			ses->status = CifsExiting;
+ 		}
+ 
+ 		spin_lock(&GlobalMid_Lock);
+@@ -723,7 +733,7 @@ multi_t2_fnd:
+ 			}
+ 		}
+ 		spin_unlock(&GlobalMid_Lock);
+-		read_unlock(&GlobalSMBSeslock);
++		read_unlock(&cifs_tcp_ses_lock);
+ 		/* 1/8th of sec is more than enough time for them to exit */
+ 		msleep(125);
+ 	}
+@@ -745,14 +755,13 @@ multi_t2_fnd:
+ 	if there are any pointing to this (e.g
+ 	if a crazy root user tried to kill cifsd
+ 	kernel thread explicitly this might happen) */
+-	write_lock(&GlobalSMBSeslock);
+-	list_for_each(tmp, &GlobalSMBSessionList) {
+-		ses = list_entry(tmp, struct cifsSesInfo,
+-				cifsSessionList);
+-		if (ses->server == server)
+-			ses->server = NULL;
++	/* BB: This shouldn't be necessary, see above */
++	read_lock(&cifs_tcp_ses_lock);
++	list_for_each(tmp, &server->smb_ses_list) {
++		ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
++		ses->server = NULL;
+ 	}
+-	write_unlock(&GlobalSMBSeslock);
++	read_unlock(&cifs_tcp_ses_lock);
+ 
+ 	kfree(server->hostname);
+ 	kfree(server);
+@@ -1186,6 +1195,10 @@ cifs_parse_mount_options(char *options, const char *devname,
+ 			/* ignore */
+ 		} else if (strnicmp(data, "rw", 2) == 0) {
+ 			vol->rw = true;
++		} else if (strnicmp(data, "noblocksnd", 11) == 0) {
++			vol->noblocksnd = true;
++		} else if (strnicmp(data, "noautotune", 10) == 0) {
++			vol->noautotune = true;
+ 		} else if ((strnicmp(data, "suid", 4) == 0) ||
+ 				   (strnicmp(data, "nosuid", 6) == 0) ||
+ 				   (strnicmp(data, "exec", 4) == 0) ||
+@@ -1331,94 +1344,158 @@ cifs_parse_mount_options(char *options, const char *devname,
+ 	return 0;
+ }
+ 
+-static struct cifsSesInfo *
+-cifs_find_tcp_session(struct in_addr *target_ip_addr,
+-		      struct in6_addr *target_ip6_addr,
+-		      char *userName, struct TCP_Server_Info **psrvTcp)
++static struct TCP_Server_Info *
++cifs_find_tcp_session(struct sockaddr *addr)
+ {
+ 	struct list_head *tmp;
+-	struct cifsSesInfo *ses;
+-
+-	*psrvTcp = NULL;
++	struct TCP_Server_Info *server;
++	struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
++	struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
++
++	write_lock(&cifs_tcp_ses_lock);
++	list_for_each(tmp, &cifs_tcp_ses_list) {
++		server = list_entry(tmp, struct TCP_Server_Info,
++				    tcp_ses_list);
++		/*
++		 * the demux thread can exit on its own while still in CifsNew
++		 * so don't accept any sockets in that state. Since the
++		 * tcpStatus never changes back to CifsNew it's safe to check
++		 * for this without a lock.
++		 */
++		if (server->tcpStatus == CifsNew)
++			continue;
+ 
+-	read_lock(&GlobalSMBSeslock);
+-	list_for_each(tmp, &GlobalSMBSessionList) {
+-		ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
+-		if (!ses->server)
++		if (addr->sa_family == AF_INET &&
++		    (addr4->sin_addr.s_addr !=
++		     server->addr.sockAddr.sin_addr.s_addr))
++			continue;
++		else if (addr->sa_family == AF_INET6 &&
++			 memcmp(&server->addr.sockAddr6.sin6_addr,
++				&addr6->sin6_addr, sizeof(addr6->sin6_addr)))
+ 			continue;
+ 
+-		if (target_ip_addr &&
+-		    ses->server->addr.sockAddr.sin_addr.s_addr != target_ip_addr->s_addr)
+-				continue;
+-		else if (target_ip6_addr &&
+-			 memcmp(&ses->server->addr.sockAddr6.sin6_addr,
+-				target_ip6_addr, sizeof(*target_ip6_addr)))
+-				continue;
+-		/* BB lock server and tcp session; increment use count here?? */
++		++server->srv_count;
++		write_unlock(&cifs_tcp_ses_lock);
++		cFYI(1, ("Existing tcp session with server found"));
++		return server;
++	}
++	write_unlock(&cifs_tcp_ses_lock);
++	return NULL;
++}
+ 
+-		/* found a match on the TCP session */
+-		*psrvTcp = ses->server;
++static void
++cifs_put_tcp_session(struct TCP_Server_Info *server)
++{
++	struct task_struct *task;
+ 
+-		/* BB check if reconnection needed */
+-		if (strncmp(ses->userName, userName, MAX_USERNAME_SIZE) == 0) {
+-			read_unlock(&GlobalSMBSeslock);
+-			/* Found exact match on both TCP and
+-			   SMB sessions */
+-			return ses;
+-		}
+-		/* else tcp and smb sessions need reconnection */
++	write_lock(&cifs_tcp_ses_lock);
++	if (--server->srv_count > 0) {
++		write_unlock(&cifs_tcp_ses_lock);
++		return;
+ 	}
+-	read_unlock(&GlobalSMBSeslock);
+ 
+-	return NULL;
++	list_del_init(&server->tcp_ses_list);
++	write_unlock(&cifs_tcp_ses_lock);
++
++	spin_lock(&GlobalMid_Lock);
++	server->tcpStatus = CifsExiting;
++	spin_unlock(&GlobalMid_Lock);
++
++	task = xchg(&server->tsk, NULL);
++	if (task)
++		force_sig(SIGKILL, task);
+ }
+ 
+-static struct cifsTconInfo *
+-find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
++static struct cifsSesInfo *
++cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
+ {
+ 	struct list_head *tmp;
+-	struct cifsTconInfo *tcon;
+-	__be32 old_ip;
+-
+-	read_lock(&GlobalSMBSeslock);
++	struct cifsSesInfo *ses;
+ 
+-	list_for_each(tmp, &GlobalTreeConnectionList) {
+-		cFYI(1, ("Next tcon"));
+-		tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
+-		if (!tcon->ses || !tcon->ses->server)
++	write_lock(&cifs_tcp_ses_lock);
++	list_for_each(tmp, &server->smb_ses_list) {
++		ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
++		if (strncmp(ses->userName, username, MAX_USERNAME_SIZE))
+ 			continue;
+ 
+-		old_ip = tcon->ses->server->addr.sockAddr.sin_addr.s_addr;
+-		cFYI(1, ("old ip addr: %x == new ip %x ?",
+-			old_ip, new_target_ip_addr));
++		++ses->ses_count;
++		write_unlock(&cifs_tcp_ses_lock);
++		return ses;
++	}
++	write_unlock(&cifs_tcp_ses_lock);
++	return NULL;
++}
+ 
+-		if (old_ip != new_target_ip_addr)
+-			continue;
++static void
++cifs_put_smb_ses(struct cifsSesInfo *ses)
++{
++	int xid;
++	struct TCP_Server_Info *server = ses->server;
+ 
+-		/* BB lock tcon, server, tcp session and increment use count? */
+-		/* found a match on the TCP session */
+-		/* BB check if reconnection needed */
+-		cFYI(1, ("IP match, old UNC: %s new: %s",
+-			tcon->treeName, uncName));
++	write_lock(&cifs_tcp_ses_lock);
++	if (--ses->ses_count > 0) {
++		write_unlock(&cifs_tcp_ses_lock);
++		return;
++	}
+ 
+-		if (strncmp(tcon->treeName, uncName, MAX_TREE_SIZE))
+-			continue;
++	list_del_init(&ses->smb_ses_list);
++	write_unlock(&cifs_tcp_ses_lock);
++
++	if (ses->status == CifsGood) {
++		xid = GetXid();
++		CIFSSMBLogoff(xid, ses);
++		_FreeXid(xid);
++	}
++	sesInfoFree(ses);
++	cifs_put_tcp_session(server);
++}
+ 
+-		cFYI(1, ("and old usr: %s new: %s",
+-			tcon->treeName, uncName));
++static struct cifsTconInfo *
++cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
++{
++	struct list_head *tmp;
++	struct cifsTconInfo *tcon;
+ 
+-		if (strncmp(tcon->ses->userName, userName, MAX_USERNAME_SIZE))
++	write_lock(&cifs_tcp_ses_lock);
++	list_for_each(tmp, &ses->tcon_list) {
++		tcon = list_entry(tmp, struct cifsTconInfo, tcon_list);
++		if (tcon->tidStatus == CifsExiting)
++			continue;
++		if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
+ 			continue;
+ 
+-		/* matched smb session (user name) */
+-		read_unlock(&GlobalSMBSeslock);
++		++tcon->tc_count;
++		write_unlock(&cifs_tcp_ses_lock);
+ 		return tcon;
+ 	}
+-
+-	read_unlock(&GlobalSMBSeslock);
++	write_unlock(&cifs_tcp_ses_lock);
+ 	return NULL;
+ }
+ 
++static void
++cifs_put_tcon(struct cifsTconInfo *tcon)
++{
++	int xid;
++	struct cifsSesInfo *ses = tcon->ses;
++
++	write_lock(&cifs_tcp_ses_lock);
++	if (--tcon->tc_count > 0) {
++		write_unlock(&cifs_tcp_ses_lock);
++		return;
++	}
++
++	list_del_init(&tcon->tcon_list);
++	write_unlock(&cifs_tcp_ses_lock);
++
++	xid = GetXid();
++	CIFSSMBTDis(xid, tcon);
++	_FreeXid(xid);
++
++	DeleteTconOplockQEntries(tcon);
++	tconInfoFree(tcon);
++	cifs_put_smb_ses(ses);
++}
++
+ int
+ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
+ 	     const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
+@@ -1506,7 +1583,8 @@ static void rfc1002mangle(char *target, char *source, unsigned int length)
+ 
+ static int
+ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
+-	     char *netbios_name, char *target_name)
++		char *netbios_name, char *target_name,
++		bool noblocksnd, bool noautotune)
+ {
+ 	int rc = 0;
+ 	int connected = 0;
+@@ -1578,11 +1656,15 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
+ 		 (*csocket)->sk->sk_sndbuf,
+ 		 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
+ 	(*csocket)->sk->sk_rcvtimeo = 7 * HZ;
++	if (!noblocksnd)
++		(*csocket)->sk->sk_sndtimeo = 3 * HZ;
+ 	/* make the bufsizes depend on wsize/rsize and max requests */
+-	if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
+-		(*csocket)->sk->sk_sndbuf = 200 * 1024;
+-	if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
+-		(*csocket)->sk->sk_rcvbuf = 140 * 1024;
++	if (noautotune) {
++		if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
++			(*csocket)->sk->sk_sndbuf = 200 * 1024;
++		if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
++			(*csocket)->sk->sk_rcvbuf = 140 * 1024;
++	}
+ 
+ 	/* send RFC1001 sessinit */
+ 	if (psin_server->sin_port == htons(RFC1001_PORT)) {
+@@ -1619,7 +1701,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
+ 			/* sizeof RFC1002_SESSION_REQUEST with no scope */
+ 			smb_buf->smb_buf_length = 0x81000044;
+ 			rc = smb_send(*csocket, smb_buf, 0x44,
+-				(struct sockaddr *)psin_server);
++				(struct sockaddr *)psin_server, noblocksnd);
+ 			kfree(ses_init_buf);
+ 			msleep(1); /* RFC1001 layer in at least one server
+ 				      requires very short break before negprot
+@@ -1639,7 +1721,8 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
+ }
+ 
+ static int
+-ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
++ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket,
++		bool noblocksnd)
+ {
+ 	int rc = 0;
+ 	int connected = 0;
+@@ -1708,6 +1791,8 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
+ 		the default. sock_setsockopt not used because it expects
+ 		user space buffer */
+ 	(*csocket)->sk->sk_rcvtimeo = 7 * HZ;
++	if (!noblocksnd)
++		(*csocket)->sk->sk_sndtimeo = 3 * HZ;
+ 
+ 	return rc;
+ }
+@@ -1845,19 +1930,104 @@ convert_delimiter(char *path, char delim)
+ 	}
+ }
+ 
++static void setup_cifs_sb(struct smb_vol *pvolume_info,
++			  struct cifs_sb_info *cifs_sb)
++{
++	if (pvolume_info->rsize > CIFSMaxBufSize) {
++		cERROR(1, ("rsize %d too large, using MaxBufSize",
++			pvolume_info->rsize));
++		cifs_sb->rsize = CIFSMaxBufSize;
++	} else if ((pvolume_info->rsize) &&
++			(pvolume_info->rsize <= CIFSMaxBufSize))
++		cifs_sb->rsize = pvolume_info->rsize;
++	else /* default */
++		cifs_sb->rsize = CIFSMaxBufSize;
++
++	if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
++		cERROR(1, ("wsize %d too large, using 4096 instead",
++			  pvolume_info->wsize));
++		cifs_sb->wsize = 4096;
++	} else if (pvolume_info->wsize)
++		cifs_sb->wsize = pvolume_info->wsize;
++	else
++		cifs_sb->wsize = min_t(const int,
++					PAGEVEC_SIZE * PAGE_CACHE_SIZE,
++					127*1024);
++		/* old default of CIFSMaxBufSize was too small now
++		   that SMB Write2 can send multiple pages in kvec.
++		   RFC1001 does not describe what happens when frame
++		   bigger than 128K is sent so use that as max in
++		   conjunction with 52K kvec constraint on arch with 4K
++		   page size  */
++
++	if (cifs_sb->rsize < 2048) {
++		cifs_sb->rsize = 2048;
++		/* Windows ME may prefer this */
++		cFYI(1, ("readsize set to minimum: 2048"));
++	}
++	/* calculate prepath */
++	cifs_sb->prepath = pvolume_info->prepath;
++	if (cifs_sb->prepath) {
++		cifs_sb->prepathlen = strlen(cifs_sb->prepath);
++		/* we can not convert the / to \ in the path
++		separators in the prefixpath yet because we do not
++		know (until reset_cifs_unix_caps is called later)
++		whether POSIX PATH CAP is available. We normalize
++		the / to \ after reset_cifs_unix_caps is called */
++		pvolume_info->prepath = NULL;
++	} else
++		cifs_sb->prepathlen = 0;
++	cifs_sb->mnt_uid = pvolume_info->linux_uid;
++	cifs_sb->mnt_gid = pvolume_info->linux_gid;
++	cifs_sb->mnt_file_mode = pvolume_info->file_mode;
++	cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
++	cFYI(1, ("file mode: 0x%x  dir mode: 0x%x",
++		cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
++
++	if (pvolume_info->noperm)
++		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
++	if (pvolume_info->setuids)
++		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
++	if (pvolume_info->server_ino)
++		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
++	if (pvolume_info->remap)
++		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
++	if (pvolume_info->no_xattr)
++		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
++	if (pvolume_info->sfu_emul)
++		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
++	if (pvolume_info->nobrl)
++		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
++	if (pvolume_info->cifs_acl)
++		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
++	if (pvolume_info->override_uid)
++		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
++	if (pvolume_info->override_gid)
++		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
++	if (pvolume_info->dynperm)
++		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
++	if (pvolume_info->direct_io) {
++		cFYI(1, ("mounting share using direct i/o"));
++		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
++	}
++
++	if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
++		cERROR(1, ("mount option dynperm ignored if cifsacl "
++			   "mount option supported"));
++}
++
+ int
+ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
+ 	   char *mount_data, const char *devname)
+ {
+ 	int rc = 0;
+ 	int xid;
+-	int address_type = AF_INET;
+ 	struct socket *csocket = NULL;
+-	struct sockaddr_in sin_server;
+-	struct sockaddr_in6 sin_server6;
++	struct sockaddr addr;
++	struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
++	struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
+ 	struct smb_vol volume_info;
+ 	struct cifsSesInfo *pSesInfo = NULL;
+-	struct cifsSesInfo *existingCifsSes = NULL;
+ 	struct cifsTconInfo *tcon = NULL;
+ 	struct TCP_Server_Info *srvTcp = NULL;
+ 
+@@ -1865,6 +2035,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
+ 
+ /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
+ 
++	memset(&addr, 0, sizeof(struct sockaddr));
+ 	memset(&volume_info, 0, sizeof(struct smb_vol));
+ 	if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
+ 		rc = -EINVAL;
+@@ -1887,16 +2058,16 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
+ 
+ 	if (volume_info.UNCip && volume_info.UNC) {
+ 		rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
+-				    &sin_server.sin_addr.s_addr);
++				    &sin_server->sin_addr.s_addr);
+ 
+ 		if (rc <= 0) {
+ 			/* not ipv4 address, try ipv6 */
+ 			rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
+-					    &sin_server6.sin6_addr.in6_u);
++					    &sin_server6->sin6_addr.in6_u);
+ 			if (rc > 0)
+-				address_type = AF_INET6;
++				addr.sa_family = AF_INET6;
+ 		} else {
+-			address_type = AF_INET;
++			addr.sa_family = AF_INET;
+ 		}
+ 
+ 		if (rc <= 0) {
+@@ -1936,38 +2107,25 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
+ 		}
+ 	}
+ 
+-	if (address_type == AF_INET)
+-		existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
+-			NULL /* no ipv6 addr */,
+-			volume_info.username, &srvTcp);
+-	else if (address_type == AF_INET6) {
+-		cFYI(1, ("looking for ipv6 address"));
+-		existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
+-			&sin_server6.sin6_addr,
+-			volume_info.username, &srvTcp);
+-	} else {
+-		rc = -EINVAL;
+-		goto out;
+-	}
+-
+-	if (srvTcp) {
+-		cFYI(1, ("Existing tcp session with server found"));
+-	} else {	/* create socket */
+-		if (volume_info.port)
+-			sin_server.sin_port = htons(volume_info.port);
+-		else
+-			sin_server.sin_port = 0;
+-		if (address_type == AF_INET6) {
++	srvTcp = cifs_find_tcp_session(&addr);
++	if (!srvTcp) { /* create socket */
++		if (addr.sa_family == AF_INET6) {
+ 			cFYI(1, ("attempting ipv6 connect"));
+ 			/* BB should we allow ipv6 on port 139? */
+ 			/* other OS never observed in Wild doing 139 with v6 */
+-			rc = ipv6_connect(&sin_server6, &csocket);
+-		} else
+-			rc = ipv4_connect(&sin_server, &csocket,
+-				  volume_info.source_rfc1001_name,
+-				  volume_info.target_rfc1001_name);
++			sin_server6->sin6_port = htons(volume_info.port);
++			rc = ipv6_connect(sin_server6, &csocket,
++					volume_info.noblocksnd);
++		} else {
++			sin_server->sin_port = htons(volume_info.port);
++			rc = ipv4_connect(sin_server, &csocket,
++					volume_info.source_rfc1001_name,
++					volume_info.target_rfc1001_name,
++					volume_info.noblocksnd,
++					volume_info.noautotune);
++		}
+ 		if (rc < 0) {
+-			cERROR(1, ("Error connecting to IPv4 socket. "
++			cERROR(1, ("Error connecting to socket. "
+ 				   "Aborting operation"));
+ 			if (csocket != NULL)
+ 				sock_release(csocket);
+@@ -1980,12 +2138,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
+ 			sock_release(csocket);
+ 			goto out;
+ 		} else {
+-			memcpy(&srvTcp->addr.sockAddr, &sin_server,
+-				sizeof(struct sockaddr_in));
++			srvTcp->noblocksnd = volume_info.noblocksnd;
++			srvTcp->noautotune = volume_info.noautotune;
++			if (addr.sa_family == AF_INET6)
++				memcpy(&srvTcp->addr.sockAddr6, sin_server6,
++					sizeof(struct sockaddr_in6));
++			else
++				memcpy(&srvTcp->addr.sockAddr, sin_server,
++					sizeof(struct sockaddr_in));
+ 			atomic_set(&srvTcp->inFlight, 0);
+ 			/* BB Add code for ipv6 case too */
+ 			srvTcp->ssocket = csocket;
+-			srvTcp->protocolType = IPV4;
+ 			srvTcp->hostname = extract_hostname(volume_info.UNC);
+ 			if (IS_ERR(srvTcp->hostname)) {
+ 				rc = PTR_ERR(srvTcp->hostname);
+@@ -2015,15 +2178,28 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
+ 			memcpy(srvTcp->server_RFC1001_name,
+ 				volume_info.target_rfc1001_name, 16);
+ 			srvTcp->sequence_number = 0;
++			INIT_LIST_HEAD(&srvTcp->tcp_ses_list);
++			INIT_LIST_HEAD(&srvTcp->smb_ses_list);
++			++srvTcp->srv_count;
++			write_lock(&cifs_tcp_ses_lock);
++			list_add(&srvTcp->tcp_ses_list,
++				 &cifs_tcp_ses_list);
++			write_unlock(&cifs_tcp_ses_lock);
+ 		}
+ 	}
+ 
+-	if (existingCifsSes) {
+-		pSesInfo = existingCifsSes;
++	pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username);
++	if (pSesInfo) {
+ 		cFYI(1, ("Existing smb sess found (status=%d)",
+ 			pSesInfo->status));
++		/*
++		 * The existing SMB session already has a reference to srvTcp,
++		 * so we can put back the extra one we got before
++		 */
++		cifs_put_tcp_session(srvTcp);
++
+ 		down(&pSesInfo->sesSem);
+-		if (pSesInfo->status == CifsNeedReconnect) {
++		if (pSesInfo->need_reconnect) {
+ 			cFYI(1, ("Session needs reconnect"));
+ 			rc = cifs_setup_session(xid, pSesInfo,
+ 						cifs_sb->local_nls);
+@@ -2032,180 +2208,94 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
+ 	} else if (!rc) {
+ 		cFYI(1, ("Existing smb sess not found"));
+ 		pSesInfo = sesInfoAlloc();
+-		if (pSesInfo == NULL)
++		if (pSesInfo == NULL) {
+ 			rc = -ENOMEM;
+-		else {
+-			pSesInfo->server = srvTcp;
+-			sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
+-				NIPQUAD(sin_server.sin_addr.s_addr));
+-		}
++			goto mount_fail_check;
++		}
++
++		/* new SMB session uses our srvTcp ref */
++		pSesInfo->server = srvTcp;
++		sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
++			NIPQUAD(sin_server->sin_addr.s_addr));
++
++		write_lock(&cifs_tcp_ses_lock);
++		list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
++		write_unlock(&cifs_tcp_ses_lock);
++
++		/* volume_info.password freed at unmount */
++		if (volume_info.password) {
++			pSesInfo->password = volume_info.password;
++			/* set to NULL to prevent freeing on exit */
++			volume_info.password = NULL;
++		}
++		if (volume_info.username)
++			strncpy(pSesInfo->userName, volume_info.username,
++				MAX_USERNAME_SIZE);
++		if (volume_info.domainname) {
++			int len = strlen(volume_info.domainname);
++			pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
++			if (pSesInfo->domainName)
++				strcpy(pSesInfo->domainName,
++					volume_info.domainname);
++		}
++		pSesInfo->linux_uid = volume_info.linux_uid;
++		pSesInfo->overrideSecFlg = volume_info.secFlg;
++		down(&pSesInfo->sesSem);
+ 
+-		if (!rc) {
+-			/* volume_info.password freed at unmount */
+-			if (volume_info.password) {
+-				pSesInfo->password = volume_info.password;
+-				/* set to NULL to prevent freeing on exit */
+-				volume_info.password = NULL;
+-			}
+-			if (volume_info.username)
+-				strncpy(pSesInfo->userName,
+-					volume_info.username,
+-					MAX_USERNAME_SIZE);
+-			if (volume_info.domainname) {
+-				int len = strlen(volume_info.domainname);
+-				pSesInfo->domainName =
+-					kmalloc(len + 1, GFP_KERNEL);
+-				if (pSesInfo->domainName)
+-					strcpy(pSesInfo->domainName,
+-						volume_info.domainname);
+-			}
+-			pSesInfo->linux_uid = volume_info.linux_uid;
+-			pSesInfo->overrideSecFlg = volume_info.secFlg;
+-			down(&pSesInfo->sesSem);
+-			/* BB FIXME need to pass vol->secFlgs BB */
+-			rc = cifs_setup_session(xid, pSesInfo,
+-						cifs_sb->local_nls);
+-			up(&pSesInfo->sesSem);
+-			if (!rc)
+-				atomic_inc(&srvTcp->socketUseCount);
+-		}
++		/* BB FIXME need to pass vol->secFlgs BB */
++		rc = cifs_setup_session(xid, pSesInfo,
++					cifs_sb->local_nls);
++		up(&pSesInfo->sesSem);
+ 	}
+ 
+ 	/* search for existing tcon to this server share */
+ 	if (!rc) {
+-		if (volume_info.rsize > CIFSMaxBufSize) {
+-			cERROR(1, ("rsize %d too large, using MaxBufSize",
+-				volume_info.rsize));
+-			cifs_sb->rsize = CIFSMaxBufSize;
+-		} else if ((volume_info.rsize) &&
+-				(volume_info.rsize <= CIFSMaxBufSize))
+-			cifs_sb->rsize = volume_info.rsize;
+-		else /* default */
+-			cifs_sb->rsize = CIFSMaxBufSize;
+-
+-		if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
+-			cERROR(1, ("wsize %d too large, using 4096 instead",
+-				  volume_info.wsize));
+-			cifs_sb->wsize = 4096;
+-		} else if (volume_info.wsize)
+-			cifs_sb->wsize = volume_info.wsize;
+-		else
+-			cifs_sb->wsize =
+-				min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
+-					127*1024);
+-			/* old default of CIFSMaxBufSize was too small now
+-			   that SMB Write2 can send multiple pages in kvec.
+-			   RFC1001 does not describe what happens when frame
+-			   bigger than 128K is sent so use that as max in
+-			   conjunction with 52K kvec constraint on arch with 4K
+-			   page size  */
+-
+-		if (cifs_sb->rsize < 2048) {
+-			cifs_sb->rsize = 2048;
+-			/* Windows ME may prefer this */
+-			cFYI(1, ("readsize set to minimum: 2048"));
+-		}
+-		/* calculate prepath */
+-		cifs_sb->prepath = volume_info.prepath;
+-		if (cifs_sb->prepath) {
+-			cifs_sb->prepathlen = strlen(cifs_sb->prepath);
+-			/* we can not convert the / to \ in the path
+-			separators in the prefixpath yet because we do not
+-			know (until reset_cifs_unix_caps is called later)
+-			whether POSIX PATH CAP is available. We normalize
+-			the / to \ after reset_cifs_unix_caps is called */
+-			volume_info.prepath = NULL;
+-		} else
+-			cifs_sb->prepathlen = 0;
+-		cifs_sb->mnt_uid = volume_info.linux_uid;
+-		cifs_sb->mnt_gid = volume_info.linux_gid;
+-		cifs_sb->mnt_file_mode = volume_info.file_mode;
+-		cifs_sb->mnt_dir_mode = volume_info.dir_mode;
+-		cFYI(1, ("file mode: 0x%x  dir mode: 0x%x",
+-			cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
+-
+-		if (volume_info.noperm)
+-			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
+-		if (volume_info.setuids)
+-			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
+-		if (volume_info.server_ino)
+-			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
+-		if (volume_info.remap)
+-			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
+-		if (volume_info.no_xattr)
+-			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
+-		if (volume_info.sfu_emul)
+-			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
+-		if (volume_info.nobrl)
+-			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
+-		if (volume_info.cifs_acl)
+-			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
+-		if (volume_info.override_uid)
+-			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
+-		if (volume_info.override_gid)
+-			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
+-		if (volume_info.dynperm)
+-			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
+-		if (volume_info.direct_io) {
+-			cFYI(1, ("mounting share using direct i/o"));
+-			cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
+-		}
+-
+-		if ((volume_info.cifs_acl) && (volume_info.dynperm))
+-			cERROR(1, ("mount option dynperm ignored if cifsacl "
+-				   "mount option supported"));
+-
+-		tcon =
+-		    find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
+-			     volume_info.username);
++		setup_cifs_sb(&volume_info, cifs_sb);
++		tcon = cifs_find_tcon(pSesInfo, volume_info.UNC);
+ 		if (tcon) {
+ 			cFYI(1, ("Found match on UNC path"));
+-			/* we can have only one retry value for a connection
+-			   to a share so for resources mounted more than once
+-			   to the same server share the last value passed in
+-			   for the retry flag is used */
+-			tcon->retry = volume_info.retry;
+-			tcon->nocase = volume_info.nocase;
++			/* existing tcon already has a reference */
++			cifs_put_smb_ses(pSesInfo);
+ 			if (tcon->seal != volume_info.seal)
+ 				cERROR(1, ("transport encryption setting "
+ 					   "conflicts with existing tid"));
+ 		} else {
+ 			tcon = tconInfoAlloc();
+-			if (tcon == NULL)
++			if (tcon == NULL) {
+ 				rc = -ENOMEM;
+-			else {
+-				/* check for null share name ie connecting to
+-				 * dfs root */
+-
+-				/* BB check if this works for exactly length
+-				 * three strings */
+-				if ((strchr(volume_info.UNC + 3, '\\') == NULL)
+-				    && (strchr(volume_info.UNC + 3, '/') ==
+-					NULL)) {
+-/*					rc = connect_to_dfs_path(xid, pSesInfo,
+-						"", cifs_sb->local_nls,
+-						cifs_sb->mnt_cifs_flags &
+-						  CIFS_MOUNT_MAP_SPECIAL_CHR);*/
+-					cFYI(1, ("DFS root not supported"));
+-					rc = -ENODEV;
+-					goto out;
+-				} else {
+-					/* BB Do we need to wrap sesSem around
+-					 * this TCon call and Unix SetFS as
+-					 * we do on SessSetup and reconnect? */
+-					rc = CIFSTCon(xid, pSesInfo,
+-						volume_info.UNC,
+-						tcon, cifs_sb->local_nls);
+-					cFYI(1, ("CIFS Tcon rc = %d", rc));
+-				}
+-				if (!rc) {
+-					atomic_inc(&pSesInfo->inUse);
+-					tcon->retry = volume_info.retry;
+-					tcon->nocase = volume_info.nocase;
+-					tcon->seal = volume_info.seal;
+-				}
++				goto mount_fail_check;
++			}
++			tcon->ses = pSesInfo;
++
++			/* check for null share name ie connect to dfs root */
++			if ((strchr(volume_info.UNC + 3, '\\') == NULL)
++			    && (strchr(volume_info.UNC + 3, '/') == NULL)) {
++				/* rc = connect_to_dfs_path(...) */
++				cFYI(1, ("DFS root not supported"));
++				rc = -ENODEV;
++				goto mount_fail_check;
++			} else {
++				/* BB Do we need to wrap sesSem around
++				 * this TCon call and Unix SetFS as
++				 * we do on SessSetup and reconnect? */
++				rc = CIFSTCon(xid, pSesInfo, volume_info.UNC,
++					      tcon, cifs_sb->local_nls);
++				cFYI(1, ("CIFS Tcon rc = %d", rc));
+ 			}
++			if (rc)
++				goto mount_fail_check;
++			tcon->seal = volume_info.seal;
++			write_lock(&cifs_tcp_ses_lock);
++			list_add(&tcon->tcon_list, &pSesInfo->tcon_list);
++			write_unlock(&cifs_tcp_ses_lock);
+ 		}
++
++		/* we can have only one retry value for a connection
++		   to a share so for resources mounted more than once
++		   to the same server share the last value passed in
++		   for the retry flag is used */
++		tcon->retry = volume_info.retry;
++		tcon->nocase = volume_info.nocase;
+ 	}
+ 	if (pSesInfo) {
+ 		if (pSesInfo->capabilities & CAP_LARGE_FILES) {
+@@ -2217,91 +2307,49 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
+ 	/* BB FIXME fix time_gran to be larger for LANMAN sessions */
+ 	sb->s_time_gran = 100;
+ 
+-/* on error free sesinfo and tcon struct if needed */
++	/* on error free sesinfo and tcon struct if needed */
++mount_fail_check:
+ 	if (rc) {
+-		/* if session setup failed, use count is zero but
+-		we still need to free cifsd thread */
+-		if (atomic_read(&srvTcp->socketUseCount) == 0) {
+-			spin_lock(&GlobalMid_Lock);
+-			srvTcp->tcpStatus = CifsExiting;
+-			spin_unlock(&GlobalMid_Lock);
+-			if (srvTcp->tsk) {
+-				/* If we could verify that kthread_stop would
+-				   always wake up processes blocked in
+-				   tcp in recv_mesg then we could remove the
+-				   send_sig call */
+-				force_sig(SIGKILL, srvTcp->tsk);
+-				kthread_stop(srvTcp->tsk);
+-			}
+-		}
+ 		 /* If find_unc succeeded then rc == 0 so we can not end */
+-		if (tcon)  /* up accidently freeing someone elses tcon struct */
+-			tconInfoFree(tcon);
+-		if (existingCifsSes == NULL) {
+-			if (pSesInfo) {
+-				if ((pSesInfo->server) &&
+-				    (pSesInfo->status == CifsGood)) {
+-					int temp_rc;
+-					temp_rc = CIFSSMBLogoff(xid, pSesInfo);
+-					/* if the socketUseCount is now zero */
+-					if ((temp_rc == -ESHUTDOWN) &&
+-					    (pSesInfo->server) &&
+-					    (pSesInfo->server->tsk)) {
+-						force_sig(SIGKILL,
+-							pSesInfo->server->tsk);
+-						kthread_stop(pSesInfo->server->tsk);
+-					}
+-				} else {
+-					cFYI(1, ("No session or bad tcon"));
+-					if ((pSesInfo->server) &&
+-					    (pSesInfo->server->tsk)) {
+-						force_sig(SIGKILL,
+-							pSesInfo->server->tsk);
+-						kthread_stop(pSesInfo->server->tsk);
+-					}
+-				}
+-				sesInfoFree(pSesInfo);
+-				/* pSesInfo = NULL; */
+-			}
+-		}
+-	} else {
+-		atomic_inc(&tcon->useCount);
+-		cifs_sb->tcon = tcon;
+-		tcon->ses = pSesInfo;
+-
+-		/* do not care if following two calls succeed - informational */
+-		if (!tcon->ipc) {
+-			CIFSSMBQFSDeviceInfo(xid, tcon);
+-			CIFSSMBQFSAttributeInfo(xid, tcon);
+-		}
+-
+-		/* tell server which Unix caps we support */
+-		if (tcon->ses->capabilities & CAP_UNIX)
+-			/* reset of caps checks mount to see if unix extensions
+-			   disabled for just this mount */
+-			reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
++		/* up accidently freeing someone elses tcon struct */
++		if (tcon)
++			cifs_put_tcon(tcon);
++		else if (pSesInfo)
++			cifs_put_smb_ses(pSesInfo);
+ 		else
+-			tcon->unix_ext = 0; /* server does not support them */
++			cifs_put_tcp_session(srvTcp);
++		goto out;
++	}
++	cifs_sb->tcon = tcon;
+ 
+-		/* convert forward to back slashes in prepath here if needed */
+-		if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
+-			convert_delimiter(cifs_sb->prepath,
+-					  CIFS_DIR_SEP(cifs_sb));
++	/* do not care if following two calls succeed - informational */
++	if (!tcon->ipc) {
++		CIFSSMBQFSDeviceInfo(xid, tcon);
++		CIFSSMBQFSAttributeInfo(xid, tcon);
++	}
+ 
+-		if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
+-			cifs_sb->rsize = 1024 * 127;
+-			cFYI(DBG2,
+-				("no very large read support, rsize now 127K"));
+-		}
+-		if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
+-			cifs_sb->wsize = min(cifs_sb->wsize,
+-					     (tcon->ses->server->maxBuf -
+-					      MAX_CIFS_HDR_SIZE));
+-		if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
+-			cifs_sb->rsize = min(cifs_sb->rsize,
+-					     (tcon->ses->server->maxBuf -
+-					      MAX_CIFS_HDR_SIZE));
++	/* tell server which Unix caps we support */
++	if (tcon->ses->capabilities & CAP_UNIX)
++		/* reset of caps checks mount to see if unix extensions
++		   disabled for just this mount */
++		reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
++	else
++		tcon->unix_ext = 0; /* server does not support them */
++
++	/* convert forward to back slashes in prepath here if needed */
++	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
++		convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
++
++	if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
++		cifs_sb->rsize = 1024 * 127;
++		cFYI(DBG2, ("no very large read support, rsize now 127K"));
+ 	}
++	if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
++		cifs_sb->wsize = min(cifs_sb->wsize,
++			       (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
++	if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
++		cifs_sb->rsize = min(cifs_sb->rsize,
++			       (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
+ 
+ 	/* volume_info.password is freed above when existing session found
+ 	(in which case it is not needed anymore) but when new sesion is created
+@@ -3471,6 +3519,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
+ 	/* above now done in SendReceive */
+ 	if ((rc == 0) && (tcon != NULL)) {
+ 		tcon->tidStatus = CifsGood;
++		tcon->need_reconnect = false;
+ 		tcon->tid = smb_buffer_response->Tid;
+ 		bcc_ptr = pByteArea(smb_buffer_response);
+ 		length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
+@@ -3542,52 +3591,17 @@ int
+ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
+ {
+ 	int rc = 0;
+-	int xid;
+-	struct cifsSesInfo *ses = NULL;
+-	struct task_struct *cifsd_task;
+ 	char *tmp;
+ 
+-	xid = GetXid();
+-
+-	if (cifs_sb->tcon) {
+-		ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
+-		rc = CIFSSMBTDis(xid, cifs_sb->tcon);
+-		if (rc == -EBUSY) {
+-			FreeXid(xid);
+-			return 0;
+-		}
+-		DeleteTconOplockQEntries(cifs_sb->tcon);
+-		tconInfoFree(cifs_sb->tcon);
+-		if ((ses) && (ses->server)) {
+-			/* save off task so we do not refer to ses later */
+-			cifsd_task = ses->server->tsk;
+-			cFYI(1, ("About to do SMBLogoff "));
+-			rc = CIFSSMBLogoff(xid, ses);
+-			if (rc == -EBUSY) {
+-				FreeXid(xid);
+-				return 0;
+-			} else if (rc == -ESHUTDOWN) {
+-				cFYI(1, ("Waking up socket by sending signal"));
+-				if (cifsd_task) {
+-					force_sig(SIGKILL, cifsd_task);
+-					kthread_stop(cifsd_task);
+-				}
+-				rc = 0;
+-			} /* else - we have an smb session
+-				left on this socket do not kill cifsd */
+-		} else
+-			cFYI(1, ("No session or bad tcon"));
+-	}
++	if (cifs_sb->tcon)
++		cifs_put_tcon(cifs_sb->tcon);
+ 
+ 	cifs_sb->tcon = NULL;
+ 	tmp = cifs_sb->prepath;
+ 	cifs_sb->prepathlen = 0;
+ 	cifs_sb->prepath = NULL;
+ 	kfree(tmp);
+-	if (ses)
+-		sesInfoFree(ses);
+ 
+-	FreeXid(xid);
+ 	return rc;
+ }
+ 
+@@ -3702,6 +3716,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
+ 	} else {
+ 		cFYI(1, ("CIFS Session Established successfully"));
+ 			pSesInfo->status = CifsGood;
++			pSesInfo->need_reconnect = false;
+ 	}
+ 
+ ss_err_exit:
+diff --git a/fs/cifs/file.c b/fs/cifs/file.c
+index cbefe1f..042b122 100644
+--- a/fs/cifs/file.c
++++ b/fs/cifs/file.c
+@@ -493,7 +493,7 @@ int cifs_close(struct inode *inode, struct file *file)
+ 		if (pTcon) {
+ 			/* no sense reconnecting to close a file that is
+ 			   already closed */
+-			if (pTcon->tidStatus != CifsNeedReconnect) {
++			if (!pTcon->need_reconnect) {
+ 				timeout = 2;
+ 				while ((atomic_read(&pSMBFile->wrtPending) != 0)
+ 					&& (timeout <= 2048)) {
+@@ -1396,7 +1396,10 @@ retry:
+ 			if ((wbc->nr_to_write -= n_iov) <= 0)
+ 				done = 1;
+ 			index = next;
+-		}
++		} else
++			/* Need to re-find the pages we skipped */
++			index = pvec.pages[0]->index + 1;
++
+ 		pagevec_release(&pvec);
+ 	}
+ 	if (!scanned && !done) {
+@@ -1813,7 +1816,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
+ 	pTcon = cifs_sb->tcon;
+ 
+ 	pagevec_init(&lru_pvec, 0);
+-		cFYI(DBG2, ("rpages: num pages %d", num_pages));
++	cFYI(DBG2, ("rpages: num pages %d", num_pages));
+ 	for (i = 0; i < num_pages; ) {
+ 		unsigned contig_pages;
+ 		struct page *tmp_page;
+diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
+index 4b17f8f..b891553 100644
+--- a/fs/cifs/misc.c
++++ b/fs/cifs/misc.c
+@@ -75,12 +75,12 @@ sesInfoAlloc(void)
+ 
+ 	ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL);
+ 	if (ret_buf) {
+-		write_lock(&GlobalSMBSeslock);
+ 		atomic_inc(&sesInfoAllocCount);
+ 		ret_buf->status = CifsNew;
+-		list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList);
++		++ret_buf->ses_count;
++		INIT_LIST_HEAD(&ret_buf->smb_ses_list);
++		INIT_LIST_HEAD(&ret_buf->tcon_list);
+ 		init_MUTEX(&ret_buf->sesSem);
+-		write_unlock(&GlobalSMBSeslock);
+ 	}
+ 	return ret_buf;
+ }
+@@ -93,10 +93,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
+ 		return;
+ 	}
+ 
+-	write_lock(&GlobalSMBSeslock);
+ 	atomic_dec(&sesInfoAllocCount);
+-	list_del(&buf_to_free->cifsSessionList);
+-	write_unlock(&GlobalSMBSeslock);
+ 	kfree(buf_to_free->serverOS);
+ 	kfree(buf_to_free->serverDomain);
+ 	kfree(buf_to_free->serverNOS);
+@@ -111,17 +108,14 @@ tconInfoAlloc(void)
+ 	struct cifsTconInfo *ret_buf;
+ 	ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL);
+ 	if (ret_buf) {
+-		write_lock(&GlobalSMBSeslock);
+ 		atomic_inc(&tconInfoAllocCount);
+-		list_add(&ret_buf->cifsConnectionList,
+-			 &GlobalTreeConnectionList);
+ 		ret_buf->tidStatus = CifsNew;
++		++ret_buf->tc_count;
+ 		INIT_LIST_HEAD(&ret_buf->openFileList);
+-		init_MUTEX(&ret_buf->tconSem);
++		INIT_LIST_HEAD(&ret_buf->tcon_list);
+ #ifdef CONFIG_CIFS_STATS
+ 		spin_lock_init(&ret_buf->stat_lock);
+ #endif
+-		write_unlock(&GlobalSMBSeslock);
+ 	}
+ 	return ret_buf;
+ }
+@@ -133,10 +127,7 @@ tconInfoFree(struct cifsTconInfo *buf_to_free)
+ 		cFYI(1, ("Null buffer passed to tconInfoFree"));
+ 		return;
+ 	}
+-	write_lock(&GlobalSMBSeslock);
+ 	atomic_dec(&tconInfoAllocCount);
+-	list_del(&buf_to_free->cifsConnectionList);
+-	write_unlock(&GlobalSMBSeslock);
+ 	kfree(buf_to_free->nativeFileSystem);
+ 	kfree(buf_to_free);
+ }
+@@ -354,9 +345,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
+ 				if (current->fsuid != treeCon->ses->linux_uid) {
+ 					cFYI(1, ("Multiuser mode and UID "
+ 						 "did not match tcon uid"));
+-					read_lock(&GlobalSMBSeslock);
+-					list_for_each(temp_item, &GlobalSMBSessionList) {
+-						ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList);
++					read_lock(&cifs_tcp_ses_lock);
++					list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) {
++						ses = list_entry(temp_item, struct cifsSesInfo, smb_ses_list);
+ 						if (ses->linux_uid == current->fsuid) {
+ 							if (ses->server == treeCon->ses->server) {
+ 								cFYI(1, ("found matching uid substitute right smb_uid"));
+@@ -368,7 +359,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
+ 							}
+ 						}
+ 					}
+-					read_unlock(&GlobalSMBSeslock);
++					read_unlock(&cifs_tcp_ses_lock);
+ 				}
+ 			}
+ 		}
+@@ -501,9 +492,10 @@ bool
+ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
+ {
+ 	struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
+-	struct list_head *tmp;
+-	struct list_head *tmp1;
++	struct list_head *tmp, *tmp1, *tmp2;
++	struct cifsSesInfo *ses;
+ 	struct cifsTconInfo *tcon;
++	struct cifsInodeInfo *pCifsInode;
+ 	struct cifsFileInfo *netfile;
+ 
+ 	cFYI(1, ("Checking for oplock break or dnotify response"));
+@@ -558,42 +550,42 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
+ 		return false;
+ 
+ 	/* look up tcon based on tid & uid */
+-	read_lock(&GlobalSMBSeslock);
+-	list_for_each(tmp, &GlobalTreeConnectionList) {
+-		tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
+-		if ((tcon->tid == buf->Tid) && (srv == tcon->ses->server)) {
++	read_lock(&cifs_tcp_ses_lock);
++	list_for_each(tmp, &srv->smb_ses_list) {
++		ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
++		list_for_each(tmp1, &ses->tcon_list) {
++			tcon = list_entry(tmp1, struct cifsTconInfo, tcon_list);
++			if (tcon->tid != buf->Tid)
++				continue;
++
+ 			cifs_stats_inc(&tcon->num_oplock_brks);
+-			list_for_each(tmp1, &tcon->openFileList) {
+-				netfile = list_entry(tmp1, struct cifsFileInfo,
++			list_for_each(tmp2, &tcon->openFileList) {
++				netfile = list_entry(tmp2, struct cifsFileInfo,
+ 						     tlist);
+-				if (pSMB->Fid == netfile->netfid) {
+-					struct cifsInodeInfo *pCifsInode;
+-					read_unlock(&GlobalSMBSeslock);
+-					cFYI(1,
+-					    ("file id match, oplock break"));
+-					pCifsInode =
+-						CIFS_I(netfile->pInode);
+-					pCifsInode->clientCanCacheAll = false;
+-					if (pSMB->OplockLevel == 0)
+-						pCifsInode->clientCanCacheRead
+-							= false;
+-					pCifsInode->oplockPending = true;
+-					AllocOplockQEntry(netfile->pInode,
+-							  netfile->netfid,
+-							  tcon);
+-					cFYI(1,
+-					    ("about to wake up oplock thread"));
+-					if (oplockThread)
+-					    wake_up_process(oplockThread);
+-					return true;
+-				}
++				if (pSMB->Fid != netfile->netfid)
++					continue;
++
++				read_unlock(&cifs_tcp_ses_lock);
++				cFYI(1, ("file id match, oplock break"));
++				pCifsInode = CIFS_I(netfile->pInode);
++				pCifsInode->clientCanCacheAll = false;
++				if (pSMB->OplockLevel == 0)
++					pCifsInode->clientCanCacheRead = false;
++				pCifsInode->oplockPending = true;
++				AllocOplockQEntry(netfile->pInode,
++						  netfile->netfid, tcon);
++				cFYI(1, ("about to wake up oplock thread"));
++				if (oplockThread)
++					wake_up_process(oplockThread);
++
++				return true;
+ 			}
+-			read_unlock(&GlobalSMBSeslock);
++			read_unlock(&cifs_tcp_ses_lock);
+ 			cFYI(1, ("No matching file for oplock break"));
+ 			return true;
+ 		}
+ 	}
+-	read_unlock(&GlobalSMBSeslock);
++	read_unlock(&cifs_tcp_ses_lock);
+ 	cFYI(1, ("Can not process oplock break for non-existent connection"));
+ 	return true;
+ }
+diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
+index e286db9..bb0f329 100644
+--- a/fs/cifs/transport.c
++++ b/fs/cifs/transport.c
+@@ -162,7 +162,7 @@ void DeleteTconOplockQEntries(struct cifsTconInfo *tcon)
+ 
+ int
+ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
+-	 unsigned int smb_buf_length, struct sockaddr *sin)
++	 unsigned int smb_buf_length, struct sockaddr *sin, bool noblocksnd)
+ {
+ 	int rc = 0;
+ 	int i = 0;
+@@ -179,7 +179,10 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
+ 	smb_msg.msg_namelen = sizeof(struct sockaddr);
+ 	smb_msg.msg_control = NULL;
+ 	smb_msg.msg_controllen = 0;
+-	smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
++	if (noblocksnd)
++		smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
++	else
++		smb_msg.msg_flags = MSG_NOSIGNAL;
+ 
+ 	/* smb header is converted in header_assemble. bcc and rest of SMB word
+ 	   area, and byte area if necessary, is converted to littleendian in
+@@ -230,8 +233,8 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
+ }
+ 
+ static int
+-smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
+-	  struct sockaddr *sin)
++smb_send2(struct TCP_Server_Info *server, struct kvec *iov, int n_vec,
++	  struct sockaddr *sin, bool noblocksnd)
+ {
+ 	int rc = 0;
+ 	int i = 0;
+@@ -241,6 +244,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
+ 	unsigned int total_len;
+ 	int first_vec = 0;
+ 	unsigned int smb_buf_length = smb_buffer->smb_buf_length;
++	struct socket *ssocket = server->ssocket;
+ 
+ 	if (ssocket == NULL)
+ 		return -ENOTSOCK; /* BB eventually add reconnect code here */
+@@ -249,7 +253,10 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
+ 	smb_msg.msg_namelen = sizeof(struct sockaddr);
+ 	smb_msg.msg_control = NULL;
+ 	smb_msg.msg_controllen = 0;
+-	smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
++	if (noblocksnd)
++		smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
++	else
++		smb_msg.msg_flags = MSG_NOSIGNAL;
+ 
+ 	/* smb header is converted in header_assemble. bcc and rest of SMB word
+ 	   area, and byte area if necessary, is converted to littleendian in
+@@ -284,8 +291,11 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
+ 		if (rc < 0)
+ 			break;
+ 
+-		if (rc >= total_len) {
+-			WARN_ON(rc > total_len);
++		if (rc == total_len) {
++			total_len = 0;
++			break;
++		} else if (rc > total_len) {
++			cERROR(1, ("sent %d requested %d", rc, total_len));
+ 			break;
+ 		}
+ 		if (rc == 0) {
+@@ -313,6 +323,16 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
+ 		i = 0; /* in case we get ENOSPC on the next send */
+ 	}
+ 
++	if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
++		cFYI(1, ("partial send (%d remaining), terminating session",
++				total_len));
++		/* If we have only sent part of an SMB then the next SMB
++		   could be taken as the remainder of this one.  We need
++		   to kill the socket so the server throws away the partial
++		   SMB */
++		server->tcpStatus = CifsNeedReconnect;
++	}
++
+ 	if (rc < 0) {
+ 		cERROR(1, ("Error %d sending data on socket to server", rc));
+ 	} else
+@@ -519,8 +539,9 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
+ #ifdef CONFIG_CIFS_STATS2
+ 	atomic_inc(&ses->server->inSend);
+ #endif
+-	rc = smb_send2(ses->server->ssocket, iov, n_vec,
+-		      (struct sockaddr *) &(ses->server->addr.sockAddr));
++	rc = smb_send2(ses->server, iov, n_vec,
++			(struct sockaddr *) &(ses->server->addr.sockAddr),
++			ses->server->noblocksnd);
+ #ifdef CONFIG_CIFS_STATS2
+ 	atomic_dec(&ses->server->inSend);
+ 	midQ->when_sent = jiffies;
+@@ -712,7 +733,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
+ 	atomic_inc(&ses->server->inSend);
+ #endif
+ 	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
+-		      (struct sockaddr *) &(ses->server->addr.sockAddr));
++			(struct sockaddr *) &(ses->server->addr.sockAddr),
++			ses->server->noblocksnd);
+ #ifdef CONFIG_CIFS_STATS2
+ 	atomic_dec(&ses->server->inSend);
+ 	midQ->when_sent = jiffies;
+@@ -852,7 +874,8 @@ send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
+ 		return rc;
+ 	}
+ 	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
+-	      (struct sockaddr *) &(ses->server->addr.sockAddr));
++		(struct sockaddr *) &(ses->server->addr.sockAddr),
++		ses->server->noblocksnd);
+ 	up(&ses->server->tcpSem);
+ 	return rc;
+ }
+@@ -942,7 +965,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
+ 	atomic_inc(&ses->server->inSend);
+ #endif
+ 	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
+-		      (struct sockaddr *) &(ses->server->addr.sockAddr));
++			(struct sockaddr *) &(ses->server->addr.sockAddr),
++			ses->server->noblocksnd);
+ #ifdef CONFIG_CIFS_STATS2
+ 	atomic_dec(&ses->server->inSend);
+ 	midQ->when_sent = jiffies;
+diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
+index f5b76a3..59b9833 100644
+--- a/fs/ecryptfs/keystore.c
++++ b/fs/ecryptfs/keystore.c
+@@ -1037,17 +1037,14 @@ static int
+ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
+ 					 struct ecryptfs_crypt_stat *crypt_stat)
+ {
+-	struct scatterlist dst_sg;
+-	struct scatterlist src_sg;
++	struct scatterlist dst_sg[2];
++	struct scatterlist src_sg[2];
+ 	struct mutex *tfm_mutex;
+ 	struct blkcipher_desc desc = {
+ 		.flags = CRYPTO_TFM_REQ_MAY_SLEEP
+ 	};
+ 	int rc = 0;
+ 
+-	sg_init_table(&dst_sg, 1);
+-	sg_init_table(&src_sg, 1);
+-
+ 	if (unlikely(ecryptfs_verbosity > 0)) {
+ 		ecryptfs_printk(
+ 			KERN_DEBUG, "Session key encryption key (size [%d]):\n",
+@@ -1066,8 +1063,8 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
+ 	}
+ 	rc = virt_to_scatterlist(auth_tok->session_key.encrypted_key,
+ 				 auth_tok->session_key.encrypted_key_size,
+-				 &src_sg, 1);
+-	if (rc != 1) {
++				 src_sg, 2);
++	if (rc < 1 || rc > 2) {
+ 		printk(KERN_ERR "Internal error whilst attempting to convert "
+ 			"auth_tok->session_key.encrypted_key to scatterlist; "
+ 			"expected rc = 1; got rc = [%d]. "
+@@ -1079,8 +1076,8 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
+ 		auth_tok->session_key.encrypted_key_size;
+ 	rc = virt_to_scatterlist(auth_tok->session_key.decrypted_key,
+ 				 auth_tok->session_key.decrypted_key_size,
+-				 &dst_sg, 1);
+-	if (rc != 1) {
++				 dst_sg, 2);
++	if (rc < 1 || rc > 2) {
+ 		printk(KERN_ERR "Internal error whilst attempting to convert "
+ 			"auth_tok->session_key.decrypted_key to scatterlist; "
+ 			"expected rc = 1; got rc = [%d]\n", rc);
+@@ -1096,7 +1093,7 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
+ 		rc = -EINVAL;
+ 		goto out;
+ 	}
+-	rc = crypto_blkcipher_decrypt(&desc, &dst_sg, &src_sg,
++	rc = crypto_blkcipher_decrypt(&desc, dst_sg, src_sg,
+ 				      auth_tok->session_key.encrypted_key_size);
+ 	mutex_unlock(tfm_mutex);
+ 	if (unlikely(rc)) {
+@@ -1541,8 +1538,8 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
+ 	size_t i;
+ 	size_t encrypted_session_key_valid = 0;
+ 	char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
+-	struct scatterlist dst_sg;
+-	struct scatterlist src_sg;
++	struct scatterlist dst_sg[2];
++	struct scatterlist src_sg[2];
+ 	struct mutex *tfm_mutex = NULL;
+ 	u8 cipher_code;
+ 	size_t packet_size_length;
+@@ -1621,8 +1618,8 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
+ 		ecryptfs_dump_hex(session_key_encryption_key, 16);
+ 	}
+ 	rc = virt_to_scatterlist(crypt_stat->key, key_rec->enc_key_size,
+-				 &src_sg, 1);
+-	if (rc != 1) {
++				 src_sg, 2);
++	if (rc < 1 || rc > 2) {
+ 		ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
+ 				"for crypt_stat session key; expected rc = 1; "
+ 				"got rc = [%d]. key_rec->enc_key_size = [%d]\n",
+@@ -1631,8 +1628,8 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
+ 		goto out;
+ 	}
+ 	rc = virt_to_scatterlist(key_rec->enc_key, key_rec->enc_key_size,
+-				 &dst_sg, 1);
+-	if (rc != 1) {
++				 dst_sg, 2);
++	if (rc < 1 || rc > 2) {
+ 		ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
+ 				"for crypt_stat encrypted session key; "
+ 				"expected rc = 1; got rc = [%d]. "
+@@ -1653,7 +1650,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
+ 	rc = 0;
+ 	ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes of the key\n",
+ 			crypt_stat->key_size);
+-	rc = crypto_blkcipher_encrypt(&desc, &dst_sg, &src_sg,
++	rc = crypto_blkcipher_encrypt(&desc, dst_sg, src_sg,
+ 				      (*key_rec).enc_key_size);
+ 	mutex_unlock(tfm_mutex);
+ 	if (rc) {
+diff --git a/fs/eventpoll.c b/fs/eventpoll.c
+index 7cc0eb7..c8cec49 100644
+--- a/fs/eventpoll.c
++++ b/fs/eventpoll.c
+@@ -102,6 +102,8 @@
+ 
+ #define EP_UNACTIVE_PTR ((void *) -1L)
+ 
++#define EP_ITEM_COST (sizeof(struct epitem) + sizeof(struct eppoll_entry))
++
+ struct epoll_filefd {
+ 	struct file *file;
+ 	int fd;
+@@ -200,6 +202,9 @@ struct eventpoll {
+ 	 * holding ->lock.
+ 	 */
+ 	struct epitem *ovflist;
++
++	/* The user that created the eventpoll descriptor */
++	struct user_struct *user;
+ };
+ 
+ /* Wait structure used by the poll hooks */
+@@ -227,9 +232,17 @@ struct ep_pqueue {
+ };
+ 
+ /*
++ * Configuration options available inside /proc/sys/fs/epoll/
++ */
++/* Maximum number of epoll devices, per user */
++static int max_user_instances __read_mostly;
++/* Maximum number of epoll watched descriptors, per user */
++static int max_user_watches __read_mostly;
++
++/*
+  * This mutex is used to serialize ep_free() and eventpoll_release_file().
+  */
+-static struct mutex epmutex;
++static DEFINE_MUTEX(epmutex);
+ 
+ /* Safe wake up implementation */
+ static struct poll_safewake psw;
+@@ -240,6 +253,33 @@ static struct kmem_cache *epi_cache __read_mostly;
+ /* Slab cache used to allocate "struct eppoll_entry" */
+ static struct kmem_cache *pwq_cache __read_mostly;
+ 
++#ifdef CONFIG_SYSCTL
++
++#include <linux/sysctl.h>
++
++static int zero;
++
++ctl_table epoll_table[] = {
++	{
++		.procname	= "max_user_instances",
++		.data		= &max_user_instances,
++		.maxlen		= sizeof(int),
++		.mode		= 0644,
++		.proc_handler	= &proc_dointvec_minmax,
++		.extra1		= &zero,
++	},
++	{
++		.procname	= "max_user_watches",
++		.data		= &max_user_watches,
++		.maxlen		= sizeof(int),
++		.mode		= 0644,
++		.proc_handler	= &proc_dointvec_minmax,
++		.extra1		= &zero,
++	},
++	{ .ctl_name = 0 }
++};
++#endif /* CONFIG_SYSCTL */
++
+ 
+ /* Setup the structure that is used as key for the RB tree */
+ static inline void ep_set_ffd(struct epoll_filefd *ffd,
+@@ -402,6 +442,8 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi)
+ 	/* At this point it is safe to free the eventpoll item */
+ 	kmem_cache_free(epi_cache, epi);
+ 
++	atomic_dec(&ep->user->epoll_watches);
++
+ 	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %p)\n",
+ 		     current, ep, file));
+ 
+@@ -449,6 +491,8 @@ static void ep_free(struct eventpoll *ep)
+ 
+ 	mutex_unlock(&epmutex);
+ 	mutex_destroy(&ep->mtx);
++	atomic_dec(&ep->user->epoll_devs);
++	free_uid(ep->user);
+ 	kfree(ep);
+ }
+ 
+@@ -532,10 +576,19 @@ void eventpoll_release_file(struct file *file)
+ 
+ static int ep_alloc(struct eventpoll **pep)
+ {
+-	struct eventpoll *ep = kzalloc(sizeof(*ep), GFP_KERNEL);
++	int error;
++	struct user_struct *user;
++	struct eventpoll *ep;
+ 
+-	if (!ep)
+-		return -ENOMEM;
++	user = get_current_user();
++	error = -EMFILE;
++	if (unlikely(atomic_read(&user->epoll_devs) >=
++			max_user_instances))
++		goto free_uid;
++	error = -ENOMEM;
++	ep = kzalloc(sizeof(*ep), GFP_KERNEL);
++	if (unlikely(!ep))
++		goto free_uid;
+ 
+ 	spin_lock_init(&ep->lock);
+ 	mutex_init(&ep->mtx);
+@@ -544,12 +597,17 @@ static int ep_alloc(struct eventpoll **pep)
+ 	INIT_LIST_HEAD(&ep->rdllist);
+ 	ep->rbr = RB_ROOT;
+ 	ep->ovflist = EP_UNACTIVE_PTR;
++	ep->user = user;
+ 
+ 	*pep = ep;
+ 
+ 	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_alloc() ep=%p\n",
+ 		     current, ep));
+ 	return 0;
++
++free_uid:
++	free_uid(user);
++	return error;
+ }
+ 
+ /*
+@@ -703,9 +761,11 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
+ 	struct epitem *epi;
+ 	struct ep_pqueue epq;
+ 
+-	error = -ENOMEM;
++	if (unlikely(atomic_read(&ep->user->epoll_watches) >=
++		     max_user_watches))
++		return -ENOSPC;
+ 	if (!(epi = kmem_cache_alloc(epi_cache, GFP_KERNEL)))
+-		goto error_return;
++		return -ENOMEM;
+ 
+ 	/* Item initialization follow here ... */
+ 	INIT_LIST_HEAD(&epi->rdllink);
+@@ -735,6 +795,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
+ 	 * install process. Namely an allocation for a wait queue failed due
+ 	 * high memory pressure.
+ 	 */
++	error = -ENOMEM;
+ 	if (epi->nwait < 0)
+ 		goto error_unregister;
+ 
+@@ -765,6 +826,8 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
+ 
+ 	spin_unlock_irqrestore(&ep->lock, flags);
+ 
++	atomic_inc(&ep->user->epoll_watches);
++
+ 	/* We have to call this outside the lock */
+ 	if (pwake)
+ 		ep_poll_safewake(&psw, &ep->poll_wait);
+@@ -789,7 +852,7 @@ error_unregister:
+ 	spin_unlock_irqrestore(&ep->lock, flags);
+ 
+ 	kmem_cache_free(epi_cache, epi);
+-error_return:
++
+ 	return error;
+ }
+ 
+@@ -1074,6 +1137,7 @@ asmlinkage long sys_epoll_create1(int flags)
+ 			      flags & O_CLOEXEC);
+ 	if (fd < 0)
+ 		ep_free(ep);
++	atomic_inc(&ep->user->epoll_devs);
+ 
+ error_return:
+ 	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
+@@ -1295,7 +1359,12 @@ asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
+ 
+ static int __init eventpoll_init(void)
+ {
+-	mutex_init(&epmutex);
++	struct sysinfo si;
++
++	si_meminfo(&si);
++	max_user_instances = 128;
++	max_user_watches = (((si.totalram - si.totalhigh) / 32) << PAGE_SHIFT) /
++		EP_ITEM_COST;
+ 
+ 	/* Initialize the structure used to perform safe poll wait head wake ups */
+ 	ep_poll_safewake_init(&psw);
+diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
+index 10bb02c..6dac7ba 100644
+--- a/fs/ext2/balloc.c
++++ b/fs/ext2/balloc.c
+@@ -1295,6 +1295,7 @@ retry_alloc:
+ 	 * turn off reservation for this allocation
+ 	 */
+ 	if (my_rsv && (free_blocks < windowsz)
++		&& (free_blocks > 0)
+ 		&& (rsv_is_empty(&my_rsv->rsv_window)))
+ 		my_rsv = NULL;
+ 
+@@ -1332,7 +1333,7 @@ retry_alloc:
+ 		 * free blocks is less than half of the reservation
+ 		 * window size.
+ 		 */
+-		if (free_blocks <= (windowsz/2))
++		if (my_rsv && (free_blocks <= (windowsz/2)))
+ 			continue;
+ 
+ 		brelse(bitmap_bh);
+diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
+index 92fd033..f5b57a2 100644
+--- a/fs/ext3/balloc.c
++++ b/fs/ext3/balloc.c
+@@ -1547,6 +1547,7 @@ retry_alloc:
+ 	 * turn off reservation for this allocation
+ 	 */
+ 	if (my_rsv && (free_blocks < windowsz)
++		&& (free_blocks > 0)
+ 		&& (rsv_is_empty(&my_rsv->rsv_window)))
+ 		my_rsv = NULL;
+ 
+@@ -1585,7 +1586,7 @@ retry_alloc:
+ 		 * free blocks is less than half of the reservation
+ 		 * window size.
+ 		 */
+-		if (free_blocks <= (windowsz/2))
++		if (my_rsv && (free_blocks <= (windowsz/2)))
+ 			continue;
+ 
+ 		brelse(bitmap_bh);
+diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
+index 1b80f1c..5853f44 100644
+--- a/fs/ext3/dir.c
++++ b/fs/ext3/dir.c
+@@ -414,7 +414,7 @@ static int call_filldir(struct file * filp, void * dirent,
+ 				get_dtype(sb, fname->file_type));
+ 		if (error) {
+ 			filp->f_pos = curr_pos;
+-			info->extra_fname = fname->next;
++			info->extra_fname = fname;
+ 			return error;
+ 		}
+ 		fname = fname->next;
+@@ -453,11 +453,12 @@ static int ext3_dx_readdir(struct file * filp,
+ 	 * If there are any leftover names on the hash collision
+ 	 * chain, return them first.
+ 	 */
+-	if (info->extra_fname &&
+-	    call_filldir(filp, dirent, filldir, info->extra_fname))
+-		goto finished;
+-
+-	if (!info->curr_node)
++	if (info->extra_fname) {
++		if (call_filldir(filp, dirent, filldir, info->extra_fname))
++			goto finished;
++		info->extra_fname = NULL;
++		goto next_node;
++	} else if (!info->curr_node)
+ 		info->curr_node = rb_first(&info->root);
+ 
+ 	while (1) {
+@@ -488,9 +489,14 @@ static int ext3_dx_readdir(struct file * filp,
+ 		info->curr_minor_hash = fname->minor_hash;
+ 		if (call_filldir(filp, dirent, filldir, fname))
+ 			break;
+-
++	next_node:
+ 		info->curr_node = rb_next(info->curr_node);
+-		if (!info->curr_node) {
++		if (info->curr_node) {
++			fname = rb_entry(info->curr_node, struct fname,
++					 rb_hash);
++			info->curr_hash = fname->hash;
++			info->curr_minor_hash = fname->minor_hash;
++		} else {
+ 			if (info->next_hash == ~0) {
+ 				filp->f_pos = EXT3_HTREE_EOF;
+ 				break;
+diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c
+index 77278e9..78fdf38 100644
+--- a/fs/ext3/resize.c
++++ b/fs/ext3/resize.c
+@@ -790,7 +790,8 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
+ 
+ 	if (reserved_gdb || gdb_off == 0) {
+ 		if (!EXT3_HAS_COMPAT_FEATURE(sb,
+-					     EXT3_FEATURE_COMPAT_RESIZE_INODE)){
++					     EXT3_FEATURE_COMPAT_RESIZE_INODE)
++		    || !le16_to_cpu(es->s_reserved_gdt_blocks)) {
+ 			ext3_warning(sb, __func__,
+ 				     "No reserved GDT blocks, can't resize");
+ 			return -EPERM;
+diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
+index d1d6487..e45d086 100644
+--- a/fs/ext4/dir.c
++++ b/fs/ext4/dir.c
+@@ -458,17 +458,8 @@ static int ext4_dx_readdir(struct file * filp,
+ 	if (info->extra_fname) {
+ 		if (call_filldir(filp, dirent, filldir, info->extra_fname))
+ 			goto finished;
+-
+ 		info->extra_fname = NULL;
+-		info->curr_node = rb_next(info->curr_node);
+-		if (!info->curr_node) {
+-			if (info->next_hash == ~0) {
+-				filp->f_pos = EXT4_HTREE_EOF;
+-				goto finished;
+-			}
+-			info->curr_hash = info->next_hash;
+-			info->curr_minor_hash = 0;
+-		}
++		goto next_node;
+ 	} else if (!info->curr_node)
+ 		info->curr_node = rb_first(&info->root);
+ 
+@@ -500,9 +491,14 @@ static int ext4_dx_readdir(struct file * filp,
+ 		info->curr_minor_hash = fname->minor_hash;
+ 		if (call_filldir(filp, dirent, filldir, fname))
+ 			break;
+-
++	next_node:
+ 		info->curr_node = rb_next(info->curr_node);
+-		if (!info->curr_node) {
++		if (info->curr_node) {
++			fname = rb_entry(info->curr_node, struct fname,
++					 rb_hash);
++			info->curr_hash = fname->hash;
++			info->curr_minor_hash = fname->minor_hash;
++		} else {
+ 			if (info->next_hash == ~0) {
+ 				filp->f_pos = EXT4_HTREE_EOF;
+ 				break;
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index 2950032..4829dac 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -291,8 +291,6 @@ struct ext4_new_group_data {
+ #define	EXT4_IOC_SETFLAGS		FS_IOC_SETFLAGS
+ #define	EXT4_IOC_GETVERSION		_IOR('f', 3, long)
+ #define	EXT4_IOC_SETVERSION		_IOW('f', 4, long)
+-#define EXT4_IOC_GROUP_EXTEND		_IOW('f', 7, unsigned long)
+-#define EXT4_IOC_GROUP_ADD		_IOW('f', 8,struct ext4_new_group_input)
+ #define	EXT4_IOC_GETVERSION_OLD		FS_IOC_GETVERSION
+ #define	EXT4_IOC_SETVERSION_OLD		FS_IOC_SETVERSION
+ #ifdef CONFIG_JBD2_DEBUG
+@@ -300,7 +298,10 @@ struct ext4_new_group_data {
+ #endif
+ #define EXT4_IOC_GETRSVSZ		_IOR('f', 5, long)
+ #define EXT4_IOC_SETRSVSZ		_IOW('f', 6, long)
+-#define EXT4_IOC_MIGRATE		_IO('f', 7)
++#define EXT4_IOC_GROUP_EXTEND		_IOW('f', 7, unsigned long)
++#define EXT4_IOC_GROUP_ADD		_IOW('f', 8, struct ext4_new_group_input)
++#define EXT4_IOC_MIGRATE		_IO('f', 9)
++ /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */
+ 
+ /*
+  * ioctl commands in 32 bit emulation
+@@ -1083,8 +1084,7 @@ extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
+ extern long ext4_compat_ioctl (struct file *, unsigned int, unsigned long);
+ 
+ /* migrate.c */
+-extern int ext4_ext_migrate(struct inode *, struct file *, unsigned int,
+-		       unsigned long);
++extern int ext4_ext_migrate(struct inode *);
+ /* namei.c */
+ extern int ext4_orphan_add(handle_t *, struct inode *);
+ extern int ext4_orphan_del(handle_t *, struct inode *);
+diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
+index f344834..9805924 100644
+--- a/fs/ext4/ialloc.c
++++ b/fs/ext4/ialloc.c
+@@ -715,6 +715,8 @@ got:
+ 			gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
+ 			free = ext4_free_blocks_after_init(sb, group, gdp);
+ 			gdp->bg_free_blocks_count = cpu_to_le16(free);
++			gdp->bg_checksum = ext4_group_desc_csum(sbi, group,
++								gdp);
+ 		}
+ 		spin_unlock(sb_bgl_lock(sbi, group));
+ 
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index 7e91913..846a790 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -2242,6 +2242,8 @@ static int ext4_da_writepage(struct page *page,
+ 			unlock_page(page);
+ 			return 0;
+ 		}
++		/* now mark the buffer_heads as dirty and uptodate */
++		block_commit_write(page, 0, PAGE_CACHE_SIZE);
+ 	}
+ 
+ 	if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
+@@ -4444,9 +4446,10 @@ static int ext4_indirect_trans_blocks(struct inode *inode, int nrblocks,
+ static int ext4_index_trans_blocks(struct inode *inode, int nrblocks, int chunk)
+ {
+ 	if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+-		return ext4_indirect_trans_blocks(inode, nrblocks, 0);
+-	return ext4_ext_index_trans_blocks(inode, nrblocks, 0);
++		return ext4_indirect_trans_blocks(inode, nrblocks, chunk);
++	return ext4_ext_index_trans_blocks(inode, nrblocks, chunk);
+ }
++
+ /*
+  * Account for index blocks, block groups bitmaps and block group
+  * descriptor blocks if modify datablocks and index blocks
+diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
+index 7a6c2f1..306bfd4 100644
+--- a/fs/ext4/ioctl.c
++++ b/fs/ext4/ioctl.c
+@@ -267,7 +267,26 @@ setversion_out:
+ 	}
+ 
+ 	case EXT4_IOC_MIGRATE:
+-		return ext4_ext_migrate(inode, filp, cmd, arg);
++	{
++		int err;
++		if (!is_owner_or_cap(inode))
++			return -EACCES;
++
++		err = mnt_want_write(filp->f_path.mnt);
++		if (err)
++			return err;
++		/*
++		 * inode_mutex prevent write and truncate on the file.
++		 * Read still goes through. We take i_data_sem in
++		 * ext4_ext_swap_inode_data before we switch the
++		 * inode format to prevent read.
++		 */
++		mutex_lock(&(inode->i_mutex));
++		err = ext4_ext_migrate(inode);
++		mutex_unlock(&(inode->i_mutex));
++		mnt_drop_write(filp->f_path.mnt);
++		return err;
++	}
+ 
+ 	default:
+ 		return -ENOTTY;
+diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
+index e0e3a5e..ba86b56 100644
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -2575,7 +2575,7 @@ static void ext4_mb_cleanup_pa(struct ext4_group_info *grp)
+ 		pa = list_entry(cur, struct ext4_prealloc_space, pa_group_list);
+ 		list_del(&pa->pa_group_list);
+ 		count++;
+-		kfree(pa);
++		kmem_cache_free(ext4_pspace_cachep, pa);
+ 	}
+ 	if (count)
+ 		mb_debug("mballoc: %u PAs left\n", count);
+@@ -2785,14 +2785,20 @@ static int ext4_mb_init_per_dev_proc(struct super_block *sb)
+ 	mode_t mode = S_IFREG | S_IRUGO | S_IWUSR;
+ 	struct ext4_sb_info *sbi = EXT4_SB(sb);
+ 	struct proc_dir_entry *proc;
+-	char devname[64];
++	char devname[BDEVNAME_SIZE], *p;
+ 
+ 	if (proc_root_ext4 == NULL) {
+ 		sbi->s_mb_proc = NULL;
+ 		return -EINVAL;
+ 	}
+ 	bdevname(sb->s_bdev, devname);
++	p = devname;
++	while ((p = strchr(p, '/')))
++		*p = '!';
++
+ 	sbi->s_mb_proc = proc_mkdir(devname, proc_root_ext4);
++	if (!sbi->s_mb_proc)
++		goto err_create_dir;
+ 
+ 	MB_PROC_HANDLER(EXT4_MB_STATS_NAME, stats);
+ 	MB_PROC_HANDLER(EXT4_MB_MAX_TO_SCAN_NAME, max_to_scan);
+@@ -2804,7 +2810,6 @@ static int ext4_mb_init_per_dev_proc(struct super_block *sb)
+ 	return 0;
+ 
+ err_out:
+-	printk(KERN_ERR "EXT4-fs: Unable to create %s\n", devname);
+ 	remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_mb_proc);
+ 	remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_mb_proc);
+ 	remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_mb_proc);
+@@ -2813,6 +2818,8 @@ err_out:
+ 	remove_proc_entry(EXT4_MB_STATS_NAME, sbi->s_mb_proc);
+ 	remove_proc_entry(devname, proc_root_ext4);
+ 	sbi->s_mb_proc = NULL;
++err_create_dir:
++	printk(KERN_ERR "EXT4-fs: Unable to create %s\n", devname);
+ 
+ 	return -ENOMEM;
+ }
+@@ -2820,12 +2827,15 @@ err_out:
+ static int ext4_mb_destroy_per_dev_proc(struct super_block *sb)
+ {
+ 	struct ext4_sb_info *sbi = EXT4_SB(sb);
+-	char devname[64];
++	char devname[BDEVNAME_SIZE], *p;
+ 
+ 	if (sbi->s_mb_proc == NULL)
+ 		return -EINVAL;
+ 
+ 	bdevname(sb->s_bdev, devname);
++	p = devname;
++	while ((p = strchr(p, '/')))
++		*p = '!';
+ 	remove_proc_entry(EXT4_MB_GROUP_PREALLOC, sbi->s_mb_proc);
+ 	remove_proc_entry(EXT4_MB_STREAM_REQ, sbi->s_mb_proc);
+ 	remove_proc_entry(EXT4_MB_ORDER2_REQ, sbi->s_mb_proc);
+diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
+index 46fc0b5..f2a9cf4 100644
+--- a/fs/ext4/migrate.c
++++ b/fs/ext4/migrate.c
+@@ -447,8 +447,7 @@ static int free_ext_block(handle_t *handle, struct inode *inode)
+ 
+ }
+ 
+-int ext4_ext_migrate(struct inode *inode, struct file *filp,
+-				unsigned int cmd, unsigned long arg)
++int ext4_ext_migrate(struct inode *inode)
+ {
+ 	handle_t *handle;
+ 	int retval = 0, i;
+@@ -516,12 +515,6 @@ int ext4_ext_migrate(struct inode *inode, struct file *filp,
+ 	 * when we add extents we extent the journal
+ 	 */
+ 	/*
+-	 * inode_mutex prevent write and truncate on the file. Read still goes
+-	 * through. We take i_data_sem in ext4_ext_swap_inode_data before we
+-	 * switch the inode format to prevent read.
+-	 */
+-	mutex_lock(&(inode->i_mutex));
+-	/*
+ 	 * Even though we take i_mutex we can still cause block allocation
+ 	 * via mmap write to holes. If we have allocated new blocks we fail
+ 	 * migrate.  New block allocation will clear EXT4_EXT_MIGRATE flag.
+@@ -623,7 +616,6 @@ err_out:
+ 	tmp_inode->i_nlink = 0;
+ 
+ 	ext4_journal_stop(handle);
+-	mutex_unlock(&(inode->i_mutex));
+ 
+ 	if (tmp_inode)
+ 		iput(tmp_inode);
+diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
+index b3d3560..3922a8b 100644
+--- a/fs/ext4/resize.c
++++ b/fs/ext4/resize.c
+@@ -929,6 +929,15 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
+ 	percpu_counter_add(&sbi->s_freeinodes_counter,
+ 			   EXT4_INODES_PER_GROUP(sb));
+ 
++	if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
++		ext4_group_t flex_group;
++		flex_group = ext4_flex_group(sbi, input->group);
++		sbi->s_flex_groups[flex_group].free_blocks +=
++			input->free_blocks_count;
++		sbi->s_flex_groups[flex_group].free_inodes +=
++			EXT4_INODES_PER_GROUP(sb);
++	}
++
+ 	ext4_journal_dirty_metadata(handle, sbi->s_sbh);
+ 	sb->s_dirt = 1;
+ 
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index 566344b..7726e8e 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -1504,8 +1504,10 @@ static int ext4_fill_flex_info(struct super_block *sb)
+ 	sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex;
+ 	groups_per_flex = 1 << sbi->s_log_groups_per_flex;
+ 
+-	flex_group_count = (sbi->s_groups_count + groups_per_flex - 1) /
+-		groups_per_flex;
++	/* We allocate both existing and potentially added groups */
++	flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) +
++			((le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) + 1) <<
++			      EXT4_DESC_PER_BLOCK_BITS(sb))) / groups_per_flex;
+ 	sbi->s_flex_groups = kzalloc(flex_group_count *
+ 				     sizeof(struct flex_groups), GFP_KERNEL);
+ 	if (sbi->s_flex_groups == NULL) {
+@@ -1623,8 +1625,10 @@ static int ext4_check_descriptors(struct super_block *sb)
+ 			       "Checksum for group %lu failed (%u!=%u)\n",
+ 			       i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
+ 			       gdp)), le16_to_cpu(gdp->bg_checksum));
+-			if (!(sb->s_flags & MS_RDONLY))
++			if (!(sb->s_flags & MS_RDONLY)) {
++				spin_unlock(sb_bgl_lock(sbi, i));
+ 				return 0;
++			}
+ 		}
+ 		spin_unlock(sb_bgl_lock(sbi, i));
+ 		if (!flexbg_flag)
+@@ -2444,6 +2448,21 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
+ 			"available.\n");
+ 	}
+ 
++	if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
++		printk(KERN_WARNING "EXT4-fs: Ignoring delalloc option - "
++				"requested data journaling mode\n");
++		clear_opt(sbi->s_mount_opt, DELALLOC);
++	} else if (test_opt(sb, DELALLOC))
++		printk(KERN_INFO "EXT4-fs: delayed allocation enabled\n");
++
++	ext4_ext_init(sb);
++	err = ext4_mb_init(sb, needs_recovery);
++	if (err) {
++		printk(KERN_ERR "EXT4-fs: failed to initalize mballoc (%d)\n",
++		       err);
++		goto failed_mount4;
++	}
++
+ 	/*
+ 	 * akpm: core read_super() calls in here with the superblock locked.
+ 	 * That deadlocks, because orphan cleanup needs to lock the superblock
+@@ -2463,16 +2482,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
+ 	       test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA ? "ordered":
+ 	       "writeback");
+ 
+-	if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
+-		printk(KERN_WARNING "EXT4-fs: Ignoring delalloc option - "
+-				"requested data journaling mode\n");
+-		clear_opt(sbi->s_mount_opt, DELALLOC);
+-	} else if (test_opt(sb, DELALLOC))
+-		printk(KERN_INFO "EXT4-fs: delayed allocation enabled\n");
+-
+-	ext4_ext_init(sb);
+-	ext4_mb_init(sb, needs_recovery);
+-
+ 	lock_kernel();
+ 	return 0;
+ 
+@@ -2799,13 +2808,34 @@ static void ext4_commit_super(struct super_block *sb,
+ 
+ 	if (!sbh)
+ 		return;
++	if (buffer_write_io_error(sbh)) {
++		/*
++		 * Oh, dear.  A previous attempt to write the
++		 * superblock failed.  This could happen because the
++		 * USB device was yanked out.  Or it could happen to
++		 * be a transient write error and maybe the block will
++		 * be remapped.  Nothing we can do but to retry the
++		 * write and hope for the best.
++		 */
++		printk(KERN_ERR "ext4: previous I/O error to "
++		       "superblock detected for %s.\n", sb->s_id);
++		clear_buffer_write_io_error(sbh);
++		set_buffer_uptodate(sbh);
++	}
+ 	es->s_wtime = cpu_to_le32(get_seconds());
+ 	ext4_free_blocks_count_set(es, ext4_count_free_blocks(sb));
+ 	es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb));
+ 	BUFFER_TRACE(sbh, "marking dirty");
+ 	mark_buffer_dirty(sbh);
+-	if (sync)
++	if (sync) {
+ 		sync_dirty_buffer(sbh);
++		if (buffer_write_io_error(sbh)) {
++			printk(KERN_ERR "ext4: I/O error while writing "
++			       "superblock for %s.\n", sb->s_id);
++			clear_buffer_write_io_error(sbh);
++			set_buffer_uptodate(sbh);
++		}
++	}
+ }
+ 
+ 
+@@ -2890,12 +2920,9 @@ int ext4_force_commit(struct super_block *sb)
+ /*
+  * Ext4 always journals updates to the superblock itself, so we don't
+  * have to propagate any other updates to the superblock on disk at this
+- * point.  Just start an async writeback to get the buffers on their way
+- * to the disk.
+- *
+- * This implicitly triggers the writebehind on sync().
++ * point.  (We can probably nuke this function altogether, and remove
++ * any mention to sb->s_dirt in all of fs/ext4; eventual cleanup...)
+  */
+-
+ static void ext4_write_super(struct super_block *sb)
+ {
+ 	if (mutex_trylock(&sb->s_lock) != 0)
+@@ -2905,14 +2932,14 @@ static void ext4_write_super(struct super_block *sb)
+ 
+ static int ext4_sync_fs(struct super_block *sb, int wait)
+ {
+-	tid_t target;
++	int ret = 0;
+ 
+ 	sb->s_dirt = 0;
+-	if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, &target)) {
+-		if (wait)
+-			jbd2_log_wait_commit(EXT4_SB(sb)->s_journal, target);
+-	}
+-	return 0;
++	if (wait)
++		ret = ext4_force_commit(sb);
++	else
++		jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, NULL);
++	return ret;
+ }
+ 
+ /*
+diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
+index 8954208..362b0ed 100644
+--- a/fs/ext4/xattr.c
++++ b/fs/ext4/xattr.c
+@@ -959,6 +959,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
+ 	struct ext4_xattr_block_find bs = {
+ 		.s = { .not_found = -ENODATA, },
+ 	};
++	unsigned long no_expand;
+ 	int error;
+ 
+ 	if (!name)
+@@ -966,6 +967,9 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
+ 	if (strlen(name) > 255)
+ 		return -ERANGE;
+ 	down_write(&EXT4_I(inode)->xattr_sem);
++	no_expand = EXT4_I(inode)->i_state & EXT4_STATE_NO_EXPAND;
++	EXT4_I(inode)->i_state |= EXT4_STATE_NO_EXPAND;
++
+ 	error = ext4_get_inode_loc(inode, &is.iloc);
+ 	if (error)
+ 		goto cleanup;
+@@ -1042,6 +1046,8 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
+ cleanup:
+ 	brelse(is.iloc.bh);
+ 	brelse(bs.bh);
++	if (no_expand == 0)
++		EXT4_I(inode)->i_state &= ~EXT4_STATE_NO_EXPAND;
+ 	up_write(&EXT4_I(inode)->xattr_sem);
+ 	return error;
+ }
+diff --git a/fs/inotify.c b/fs/inotify.c
+index 690e725..7bbed1b 100644
+--- a/fs/inotify.c
++++ b/fs/inotify.c
+@@ -106,6 +106,20 @@ void get_inotify_watch(struct inotify_watch *watch)
+ }
+ EXPORT_SYMBOL_GPL(get_inotify_watch);
+ 
++int pin_inotify_watch(struct inotify_watch *watch)
++{
++	struct super_block *sb = watch->inode->i_sb;
++	spin_lock(&sb_lock);
++	if (sb->s_count >= S_BIAS) {
++		atomic_inc(&sb->s_active);
++		spin_unlock(&sb_lock);
++		atomic_inc(&watch->count);
++		return 1;
++	}
++	spin_unlock(&sb_lock);
++	return 0;
++}
++
+ /**
+  * put_inotify_watch - decrements the ref count on a given watch.  cleans up
+  * watch references if the count reaches zero.  inotify_watch is freed by
+@@ -124,6 +138,13 @@ void put_inotify_watch(struct inotify_watch *watch)
+ }
+ EXPORT_SYMBOL_GPL(put_inotify_watch);
+ 
++void unpin_inotify_watch(struct inotify_watch *watch)
++{
++	struct super_block *sb = watch->inode->i_sb;
++	put_inotify_watch(watch);
++	deactivate_super(sb);
++}
++
+ /*
+  * inotify_handle_get_wd - returns the next WD for use by the given handle
+  *
+@@ -479,6 +500,112 @@ void inotify_init_watch(struct inotify_watch *watch)
+ }
+ EXPORT_SYMBOL_GPL(inotify_init_watch);
+ 
++/*
++ * Watch removals suck violently.  To kick the watch out we need (in this
++ * order) inode->inotify_mutex and ih->mutex.  That's fine if we have
++ * a hold on inode; however, for all other cases we need to make damn sure
++ * we don't race with umount.  We can *NOT* just grab a reference to a
++ * watch - inotify_unmount_inodes() will happily sail past it and we'll end
++ * with reference to inode potentially outliving its superblock.  Ideally
++ * we just want to grab an active reference to superblock if we can; that
++ * will make sure we won't go into inotify_umount_inodes() until we are
++ * done.  Cleanup is just deactivate_super().  However, that leaves a messy
++ * case - what if we *are* racing with umount() and active references to
++ * superblock can't be acquired anymore?  We can bump ->s_count, grab
++ * ->s_umount, which will almost certainly wait until the superblock is shut
++ * down and the watch in question is pining for fjords.  That's fine, but
++ * there is a problem - we might have hit the window between ->s_active
++ * getting to 0 / ->s_count - below S_BIAS (i.e. the moment when superblock
++ * is past the point of no return and is heading for shutdown) and the
++ * moment when deactivate_super() acquires ->s_umount.  We could just do
++ * drop_super() yield() and retry, but that's rather antisocial and this
++ * stuff is luser-triggerable.  OTOH, having grabbed ->s_umount and having
++ * found that we'd got there first (i.e. that ->s_root is non-NULL) we know
++ * that we won't race with inotify_umount_inodes().  So we could grab a
++ * reference to watch and do the rest as above, just with drop_super() instead
++ * of deactivate_super(), right?  Wrong.  We had to drop ih->mutex before we
++ * could grab ->s_umount.  So the watch could've been gone already.
++ *
++ * That still can be dealt with - we need to save watch->wd, do idr_find()
++ * and compare its result with our pointer.  If they match, we either have
++ * the damn thing still alive or we'd lost not one but two races at once,
++ * the watch had been killed and a new one got created with the same ->wd
++ * at the same address.  That couldn't have happened in inotify_destroy(),
++ * but inotify_rm_wd() could run into that.  Still, "new one got created"
++ * is not a problem - we have every right to kill it or leave it alone,
++ * whatever's more convenient.
++ *
++ * So we can use idr_find(...) == watch && watch->inode->i_sb == sb as
++ * "grab it and kill it" check.  If it's been our original watch, we are
++ * fine, if it's a newcomer - nevermind, just pretend that we'd won the
++ * race and kill the fscker anyway; we are safe since we know that its
++ * superblock won't be going away.
++ *
++ * And yes, this is far beyond mere "not very pretty"; so's the entire
++ * concept of inotify to start with.
++ */
++
++/**
++ * pin_to_kill - pin the watch down for removal
++ * @ih: inotify handle
++ * @watch: watch to kill
++ *
++ * Called with ih->mutex held, drops it.  Possible return values:
++ * 0 - nothing to do, it has died
++ * 1 - remove it, drop the reference and deactivate_super()
++ * 2 - remove it, drop the reference and drop_super(); we tried hard to avoid
++ * that variant, since it involved a lot of PITA, but that's the best that
++ * could've been done.
++ */
++static int pin_to_kill(struct inotify_handle *ih, struct inotify_watch *watch)
++{
++	struct super_block *sb = watch->inode->i_sb;
++	s32 wd = watch->wd;
++
++	spin_lock(&sb_lock);
++	if (sb->s_count >= S_BIAS) {
++		atomic_inc(&sb->s_active);
++		spin_unlock(&sb_lock);
++		get_inotify_watch(watch);
++		mutex_unlock(&ih->mutex);
++		return 1;	/* the best outcome */
++	}
++	sb->s_count++;
++	spin_unlock(&sb_lock);
++	mutex_unlock(&ih->mutex); /* can't grab ->s_umount under it */
++	down_read(&sb->s_umount);
++	if (likely(!sb->s_root)) {
++		/* fs is already shut down; the watch is dead */
++		drop_super(sb);
++		return 0;
++	}
++	/* raced with the final deactivate_super() */
++	mutex_lock(&ih->mutex);
++	if (idr_find(&ih->idr, wd) != watch || watch->inode->i_sb != sb) {
++		/* the watch is dead */
++		mutex_unlock(&ih->mutex);
++		drop_super(sb);
++		return 0;
++	}
++	/* still alive or freed and reused with the same sb and wd; kill */
++	get_inotify_watch(watch);
++	mutex_unlock(&ih->mutex);
++	return 2;
++}
++
++static void unpin_and_kill(struct inotify_watch *watch, int how)
++{
++	struct super_block *sb = watch->inode->i_sb;
++	put_inotify_watch(watch);
++	switch (how) {
++	case 1:
++		deactivate_super(sb);
++		break;
++	case 2:
++		drop_super(sb);
++	}
++}
++
+ /**
+  * inotify_destroy - clean up and destroy an inotify instance
+  * @ih: inotify handle
+@@ -490,11 +617,15 @@ void inotify_destroy(struct inotify_handle *ih)
+ 	 * pretty.  We cannot do a simple iteration over the list, because we
+ 	 * do not know the inode until we iterate to the watch.  But we need to
+ 	 * hold inode->inotify_mutex before ih->mutex.  The following works.
++	 *
++	 * AV: it had to become even uglier to start working ;-/
+ 	 */
+ 	while (1) {
+ 		struct inotify_watch *watch;
+ 		struct list_head *watches;
++		struct super_block *sb;
+ 		struct inode *inode;
++		int how;
+ 
+ 		mutex_lock(&ih->mutex);
+ 		watches = &ih->watches;
+@@ -503,8 +634,10 @@ void inotify_destroy(struct inotify_handle *ih)
+ 			break;
+ 		}
+ 		watch = list_first_entry(watches, struct inotify_watch, h_list);
+-		get_inotify_watch(watch);
+-		mutex_unlock(&ih->mutex);
++		sb = watch->inode->i_sb;
++		how = pin_to_kill(ih, watch);
++		if (!how)
++			continue;
+ 
+ 		inode = watch->inode;
+ 		mutex_lock(&inode->inotify_mutex);
+@@ -518,7 +651,7 @@ void inotify_destroy(struct inotify_handle *ih)
+ 
+ 		mutex_unlock(&ih->mutex);
+ 		mutex_unlock(&inode->inotify_mutex);
+-		put_inotify_watch(watch);
++		unpin_and_kill(watch, how);
+ 	}
+ 
+ 	/* free this handle: the put matching the get in inotify_init() */
+@@ -719,7 +852,9 @@ void inotify_evict_watch(struct inotify_watch *watch)
+ int inotify_rm_wd(struct inotify_handle *ih, u32 wd)
+ {
+ 	struct inotify_watch *watch;
++	struct super_block *sb;
+ 	struct inode *inode;
++	int how;
+ 
+ 	mutex_lock(&ih->mutex);
+ 	watch = idr_find(&ih->idr, wd);
+@@ -727,9 +862,12 @@ int inotify_rm_wd(struct inotify_handle *ih, u32 wd)
+ 		mutex_unlock(&ih->mutex);
+ 		return -EINVAL;
+ 	}
+-	get_inotify_watch(watch);
++	sb = watch->inode->i_sb;
++	how = pin_to_kill(ih, watch);
++	if (!how)
++		return 0;
++
+ 	inode = watch->inode;
+-	mutex_unlock(&ih->mutex);
+ 
+ 	mutex_lock(&inode->inotify_mutex);
+ 	mutex_lock(&ih->mutex);
+@@ -740,7 +878,7 @@ int inotify_rm_wd(struct inotify_handle *ih, u32 wd)
+ 
+ 	mutex_unlock(&ih->mutex);
+ 	mutex_unlock(&inode->inotify_mutex);
+-	put_inotify_watch(watch);
++	unpin_and_kill(watch, how);
+ 
+ 	return 0;
+ }
+diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
+index 0540ca2..d15cd6e 100644
+--- a/fs/jbd/transaction.c
++++ b/fs/jbd/transaction.c
+@@ -954,9 +954,10 @@ int journal_dirty_data(handle_t *handle, struct buffer_head *bh)
+ 	journal_t *journal = handle->h_transaction->t_journal;
+ 	int need_brelse = 0;
+ 	struct journal_head *jh;
++	int ret = 0;
+ 
+ 	if (is_handle_aborted(handle))
+-		return 0;
++		return ret;
+ 
+ 	jh = journal_add_journal_head(bh);
+ 	JBUFFER_TRACE(jh, "entry");
+@@ -1067,7 +1068,16 @@ int journal_dirty_data(handle_t *handle, struct buffer_head *bh)
+ 				   time if it is redirtied */
+ 			}
+ 
+-			/* journal_clean_data_list() may have got there first */
++			/*
++			 * We cannot remove the buffer with io error from the
++			 * committing transaction, because otherwise it would
++			 * miss the error and the commit would not abort.
++			 */
++			if (unlikely(!buffer_uptodate(bh))) {
++				ret = -EIO;
++				goto no_journal;
++			}
++
+ 			if (jh->b_transaction != NULL) {
+ 				JBUFFER_TRACE(jh, "unfile from commit");
+ 				__journal_temp_unlink_buffer(jh);
+@@ -1108,7 +1118,7 @@ no_journal:
+ 	}
+ 	JBUFFER_TRACE(jh, "exit");
+ 	journal_put_journal_head(jh);
+-	return 0;
++	return ret;
+ }
+ 
+ /**
+diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
+index 91389c8..77255a3 100644
+--- a/fs/jbd2/checkpoint.c
++++ b/fs/jbd2/checkpoint.c
+@@ -114,7 +114,7 @@ static int __try_to_free_cp_buf(struct journal_head *jh)
+  */
+ void __jbd2_log_wait_for_space(journal_t *journal)
+ {
+-	int nblocks;
++	int nblocks, space_left;
+ 	assert_spin_locked(&journal->j_state_lock);
+ 
+ 	nblocks = jbd_space_needed(journal);
+@@ -126,14 +126,47 @@ void __jbd2_log_wait_for_space(journal_t *journal)
+ 
+ 		/*
+ 		 * Test again, another process may have checkpointed while we
+-		 * were waiting for the checkpoint lock
++		 * were waiting for the checkpoint lock. If there are no
++		 * transactions ready to be checkpointed, try to recover
++		 * journal space by calling cleanup_journal_tail(), and if
++		 * that doesn't work, by waiting for the currently committing
++		 * transaction to complete.  If there is absolutely no way
++		 * to make progress, this is either a BUG or corrupted
++		 * filesystem, so abort the journal and leave a stack
++		 * trace for forensic evidence.
+ 		 */
+ 		spin_lock(&journal->j_state_lock);
++		spin_lock(&journal->j_list_lock);
+ 		nblocks = jbd_space_needed(journal);
+-		if (__jbd2_log_space_left(journal) < nblocks) {
++		space_left = __jbd2_log_space_left(journal);
++		if (space_left < nblocks) {
++			int chkpt = journal->j_checkpoint_transactions != NULL;
++			tid_t tid = 0;
++
++			if (journal->j_committing_transaction)
++				tid = journal->j_committing_transaction->t_tid;
++			spin_unlock(&journal->j_list_lock);
+ 			spin_unlock(&journal->j_state_lock);
+-			jbd2_log_do_checkpoint(journal);
++			if (chkpt) {
++				jbd2_log_do_checkpoint(journal);
++			} else if (jbd2_cleanup_journal_tail(journal) == 0) {
++				/* We were able to recover space; yay! */
++				;
++			} else if (tid) {
++				jbd2_log_wait_commit(journal, tid);
++			} else {
++				printk(KERN_ERR "%s: needed %d blocks and "
++				       "only had %d space available\n",
++				       __func__, nblocks, space_left);
++				printk(KERN_ERR "%s: no way to get more "
++				       "journal space in %s\n", __func__,
++				       journal->j_devname);
++				WARN_ON(1);
++				jbd2_journal_abort(journal, 0);
++			}
+ 			spin_lock(&journal->j_state_lock);
++		} else {
++			spin_unlock(&journal->j_list_lock);
+ 		}
+ 		mutex_unlock(&journal->j_checkpoint_mutex);
+ 	}
+diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
+index f2ad061..6caf22d 100644
+--- a/fs/jbd2/commit.c
++++ b/fs/jbd2/commit.c
+@@ -126,8 +126,7 @@ static int journal_submit_commit_record(journal_t *journal,
+ 
+ 	JBUFFER_TRACE(descriptor, "submit commit block");
+ 	lock_buffer(bh);
+-	get_bh(bh);
+-	set_buffer_dirty(bh);
++	clear_buffer_dirty(bh);
+ 	set_buffer_uptodate(bh);
+ 	bh->b_end_io = journal_end_buffer_io_sync;
+ 
+@@ -160,7 +159,7 @@ static int journal_submit_commit_record(journal_t *journal,
+ 		/* And try again, without the barrier */
+ 		lock_buffer(bh);
+ 		set_buffer_uptodate(bh);
+-		set_buffer_dirty(bh);
++		clear_buffer_dirty(bh);
+ 		ret = submit_bh(WRITE, bh);
+ 	}
+ 	*cbh = bh;
+diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
+index 8207a01..52d2bee 100644
+--- a/fs/jbd2/journal.c
++++ b/fs/jbd2/journal.c
+@@ -901,10 +901,7 @@ static struct proc_dir_entry *proc_jbd2_stats;
+ 
+ static void jbd2_stats_proc_init(journal_t *journal)
+ {
+-	char name[BDEVNAME_SIZE];
+-
+-	bdevname(journal->j_dev, name);
+-	journal->j_proc_entry = proc_mkdir(name, proc_jbd2_stats);
++	journal->j_proc_entry = proc_mkdir(journal->j_devname, proc_jbd2_stats);
+ 	if (journal->j_proc_entry) {
+ 		proc_create_data("history", S_IRUGO, journal->j_proc_entry,
+ 				 &jbd2_seq_history_fops, journal);
+@@ -915,12 +912,9 @@ static void jbd2_stats_proc_init(journal_t *journal)
+ 
+ static void jbd2_stats_proc_exit(journal_t *journal)
+ {
+-	char name[BDEVNAME_SIZE];
+-
+-	bdevname(journal->j_dev, name);
+ 	remove_proc_entry("info", journal->j_proc_entry);
+ 	remove_proc_entry("history", journal->j_proc_entry);
+-	remove_proc_entry(name, proc_jbd2_stats);
++	remove_proc_entry(journal->j_devname, proc_jbd2_stats);
+ }
+ 
+ static void journal_init_stats(journal_t *journal)
+@@ -1018,6 +1012,7 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev,
+ {
+ 	journal_t *journal = journal_init_common();
+ 	struct buffer_head *bh;
++	char *p;
+ 	int n;
+ 
+ 	if (!journal)
+@@ -1039,6 +1034,10 @@ journal_t * jbd2_journal_init_dev(struct block_device *bdev,
+ 	journal->j_fs_dev = fs_dev;
+ 	journal->j_blk_offset = start;
+ 	journal->j_maxlen = len;
++	bdevname(journal->j_dev, journal->j_devname);
++	p = journal->j_devname;
++	while ((p = strchr(p, '/')))
++		*p = '!';
+ 	jbd2_stats_proc_init(journal);
+ 
+ 	bh = __getblk(journal->j_dev, start, journal->j_blocksize);
+@@ -1061,6 +1060,7 @@ journal_t * jbd2_journal_init_inode (struct inode *inode)
+ {
+ 	struct buffer_head *bh;
+ 	journal_t *journal = journal_init_common();
++	char *p;
+ 	int err;
+ 	int n;
+ 	unsigned long long blocknr;
+@@ -1070,6 +1070,12 @@ journal_t * jbd2_journal_init_inode (struct inode *inode)
+ 
+ 	journal->j_dev = journal->j_fs_dev = inode->i_sb->s_bdev;
+ 	journal->j_inode = inode;
++	bdevname(journal->j_dev, journal->j_devname);
++	p = journal->j_devname;
++	while ((p = strchr(p, '/')))
++		*p = '!';
++	p = journal->j_devname + strlen(journal->j_devname);
++	sprintf(p, ":%lu", journal->j_inode->i_ino);
+ 	jbd_debug(1,
+ 		  "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n",
+ 		  journal, inode->i_sb->s_id, inode->i_ino,
+@@ -1253,6 +1259,22 @@ void jbd2_journal_update_superblock(journal_t *journal, int wait)
+ 		goto out;
+ 	}
+ 
++	if (buffer_write_io_error(bh)) {
++		/*
++		 * Oh, dear.  A previous attempt to write the journal
++		 * superblock failed.  This could happen because the
++		 * USB device was yanked out.  Or it could happen to
++		 * be a transient write error and maybe the block will
++		 * be remapped.  Nothing we can do but to retry the
++		 * write and hope for the best.
++		 */
++		printk(KERN_ERR "JBD2: previous I/O error detected "
++		       "for journal superblock update for %s.\n",
++		       journal->j_devname);
++		clear_buffer_write_io_error(bh);
++		set_buffer_uptodate(bh);
++	}
++
+ 	spin_lock(&journal->j_state_lock);
+ 	jbd_debug(1,"JBD: updating superblock (start %ld, seq %d, errno %d)\n",
+ 		  journal->j_tail, journal->j_tail_sequence, journal->j_errno);
+@@ -1264,9 +1286,16 @@ void jbd2_journal_update_superblock(journal_t *journal, int wait)
+ 
+ 	BUFFER_TRACE(bh, "marking dirty");
+ 	mark_buffer_dirty(bh);
+-	if (wait)
++	if (wait) {
+ 		sync_dirty_buffer(bh);
+-	else
++		if (buffer_write_io_error(bh)) {
++			printk(KERN_ERR "JBD2: I/O error detected "
++			       "when updating journal superblock for %s.\n",
++			       journal->j_devname);
++			clear_buffer_write_io_error(bh);
++			set_buffer_uptodate(bh);
++		}
++	} else
+ 		ll_rw_block(SWRITE, 1, &bh);
+ 
+ out:
+diff --git a/include/asm-x86/mmzone_32.h b/include/asm-x86/mmzone_32.h
+index 5862e64..eb77583 100644
+--- a/include/asm-x86/mmzone_32.h
++++ b/include/asm-x86/mmzone_32.h
+@@ -34,10 +34,14 @@ static inline void get_memcfg_numa(void)
+ 
+ extern int early_pfn_to_nid(unsigned long pfn);
+ 
++extern void resume_map_numa_kva(pgd_t *pgd);
++
+ #else /* !CONFIG_NUMA */
+ 
+ #define get_memcfg_numa get_memcfg_numa_flat
+ 
++static inline void resume_map_numa_kva(pgd_t *pgd) {}
++
+ #endif /* CONFIG_NUMA */
+ 
+ #ifdef CONFIG_DISCONTIGMEM
+diff --git a/include/asm-x86/pci_64.h b/include/asm-x86/pci_64.h
+index f330234..50d3df5 100644
+--- a/include/asm-x86/pci_64.h
++++ b/include/asm-x86/pci_64.h
+@@ -34,8 +34,6 @@ extern void pci_iommu_alloc(void);
+  */
+ #define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys)
+ 
+-#if defined(CONFIG_GART_IOMMU) || defined(CONFIG_CALGARY_IOMMU)
+-
+ #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+ 	dma_addr_t ADDR_NAME;
+ #define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+@@ -49,18 +47,6 @@ extern void pci_iommu_alloc(void);
+ #define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+ 	(((PTR)->LEN_NAME) = (VAL))
+ 
+-#else
+-/* No IOMMU */
+-
+-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+-#define pci_unmap_addr(PTR, ADDR_NAME)		(0)
+-#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do { } while (0)
+-#define pci_unmap_len(PTR, LEN_NAME)		(0)
+-#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
+-
+-#endif
+-
+ #endif /* __KERNEL__ */
+ 
+ #endif /* __x8664_PCI_H */
+diff --git a/include/linux/idr.h b/include/linux/idr.h
+index fa035f9..dd846df 100644
+--- a/include/linux/idr.h
++++ b/include/linux/idr.h
+@@ -52,13 +52,14 @@ struct idr_layer {
+ 	unsigned long		 bitmap; /* A zero bit means "space here" */
+ 	struct idr_layer	*ary[1<<IDR_BITS];
+ 	int			 count;	 /* When zero, we can release it */
++	int			 layer;	 /* distance from leaf */
+ 	struct rcu_head		 rcu_head;
+ };
+ 
+ struct idr {
+ 	struct idr_layer *top;
+ 	struct idr_layer *id_free;
+-	int		  layers;
++	int		  layers; /* only valid without concurrent changes */
+ 	int		  id_free_cnt;
+ 	spinlock_t	  lock;
+ };
+diff --git a/include/linux/inotify.h b/include/linux/inotify.h
+index bd57857..37ea289 100644
+--- a/include/linux/inotify.h
++++ b/include/linux/inotify.h
+@@ -134,6 +134,8 @@ extern void inotify_remove_watch_locked(struct inotify_handle *,
+ 					struct inotify_watch *);
+ extern void get_inotify_watch(struct inotify_watch *);
+ extern void put_inotify_watch(struct inotify_watch *);
++extern int pin_inotify_watch(struct inotify_watch *);
++extern void unpin_inotify_watch(struct inotify_watch *);
+ 
+ #else
+ 
+@@ -228,6 +230,15 @@ static inline void put_inotify_watch(struct inotify_watch *watch)
+ {
+ }
+ 
++extern inline int pin_inotify_watch(struct inotify_watch *watch)
++{
++	return 0;
++}
++
++extern inline void unpin_inotify_watch(struct inotify_watch *watch)
++{
++}
++
+ #endif	/* CONFIG_INOTIFY */
+ 
+ #endif	/* __KERNEL __ */
+diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
+index 3dd2090..66c3499 100644
+--- a/include/linux/jbd2.h
++++ b/include/linux/jbd2.h
+@@ -850,7 +850,8 @@ struct journal_s
+ 	 */
+ 	struct block_device	*j_dev;
+ 	int			j_blocksize;
+-	unsigned long long		j_blk_offset;
++	unsigned long long	j_blk_offset;
++	char			j_devname[BDEVNAME_SIZE+24];
+ 
+ 	/*
+ 	 * Device which holds the client fs.  For internal journal this will be
+diff --git a/include/linux/libata.h b/include/linux/libata.h
+index 225bfc5..25062ac 100644
+--- a/include/linux/libata.h
++++ b/include/linux/libata.h
+@@ -364,6 +364,7 @@ enum {
+ 	ATA_HORKAGE_IPM		= (1 << 7),	/* Link PM problems */
+ 	ATA_HORKAGE_IVB		= (1 << 8),	/* cbl det validity bit bugs */
+ 	ATA_HORKAGE_STUCK_ERR	= (1 << 9),	/* stuck ERR on next PACKET */
++	ATA_HORKAGE_FIRMWARE_WARN = (1 << 12),	/* firwmare update warning */
+ 
+ 	 /* DMA mask for user DMA control: User visible values; DO NOT
+ 	    renumber */
+diff --git a/include/linux/pci.h b/include/linux/pci.h
+index 98dc624..426e029 100644
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -64,6 +64,11 @@ struct pci_slot {
+ 	struct kobject kobj;
+ };
+ 
++static inline const char *pci_slot_name(const struct pci_slot *slot)
++{
++	return kobject_name(&slot->kobj);
++}
++
+ /* File state for mmap()s on /proc/bus/pci/X/Y */
+ enum pci_mmap_state {
+ 	pci_mmap_io,
+@@ -509,7 +514,8 @@ struct pci_bus *pci_create_bus(struct device *parent, int bus,
+ struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev,
+ 				int busnr);
+ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
+-				 const char *name);
++				 const char *name,
++				 struct hotplug_slot *hotplug);
+ void pci_destroy_slot(struct pci_slot *slot);
+ void pci_update_slot_number(struct pci_slot *slot, int slot_nr);
+ int pci_scan_slot(struct pci_bus *bus, int devfn);
+diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h
+index a08cd06..a00bd1a 100644
+--- a/include/linux/pci_hotplug.h
++++ b/include/linux/pci_hotplug.h
+@@ -142,8 +142,6 @@ struct hotplug_slot_info {
+ 
+ /**
+  * struct hotplug_slot - used to register a physical slot with the hotplug pci core
+- * @name: the name of the slot being registered.  This string must
+- * be unique amoung slots registered on this system.
+  * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot
+  * @info: pointer to the &struct hotplug_slot_info for the initial values for
+  * this slot.
+@@ -153,7 +151,6 @@ struct hotplug_slot_info {
+  * needs.
+  */
+ struct hotplug_slot {
+-	char				*name;
+ 	struct hotplug_slot_ops		*ops;
+ 	struct hotplug_slot_info	*info;
+ 	void (*release) (struct hotplug_slot *slot);
+@@ -165,7 +162,13 @@ struct hotplug_slot {
+ };
+ #define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj)
+ 
+-extern int pci_hp_register(struct hotplug_slot *, struct pci_bus *, int nr);
++static inline const char *hotplug_slot_name(const struct hotplug_slot *slot)
++{
++	return pci_slot_name(slot->pci_slot);
++}
++
++extern int pci_hp_register(struct hotplug_slot *, struct pci_bus *, int nr,
++			   const char *name);
+ extern int pci_hp_deregister(struct hotplug_slot *slot);
+ extern int __must_check pci_hp_change_slot_info	(struct hotplug_slot *slot,
+ 						 struct hotplug_slot_info *info);
+diff --git a/include/linux/sched.h b/include/linux/sched.h
+index 6bfb849..086f5e1 100644
+--- a/include/linux/sched.h
++++ b/include/linux/sched.h
+@@ -587,6 +587,10 @@ struct user_struct {
+ 	atomic_t inotify_watches; /* How many inotify watches does this user have? */
+ 	atomic_t inotify_devs;	/* How many inotify devs does this user have opened? */
+ #endif
++#ifdef CONFIG_EPOLL
++	atomic_t epoll_devs;	/* The number of epoll descriptors currently open */
++	atomic_t epoll_watches;	/* The number of file descriptors currently watched */
++#endif
+ #ifdef CONFIG_POSIX_MQUEUE
+ 	/* protected by mq_lock	*/
+ 	unsigned long mq_bytes;	/* How many bytes can be allocated to mqueue? */
+diff --git a/include/net/af_unix.h b/include/net/af_unix.h
+index c29ff1d..1614d78 100644
+--- a/include/net/af_unix.h
++++ b/include/net/af_unix.h
+@@ -9,6 +9,7 @@
+ extern void unix_inflight(struct file *fp);
+ extern void unix_notinflight(struct file *fp);
+ extern void unix_gc(void);
++extern void wait_for_unix_gc(void);
+ 
+ #define UNIX_HASH_SIZE	256
+ 
+diff --git a/ipc/util.c b/ipc/util.c
+index 49b3ea6..361fd1c 100644
+--- a/ipc/util.c
++++ b/ipc/util.c
+@@ -266,9 +266,17 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
+ 	if (ids->in_use >= size)
+ 		return -ENOSPC;
+ 
++	spin_lock_init(&new->lock);
++	new->deleted = 0;
++	rcu_read_lock();
++	spin_lock(&new->lock);
++
+ 	err = idr_get_new(&ids->ipcs_idr, new, &id);
+-	if (err)
++	if (err) {
++		spin_unlock(&new->lock);
++		rcu_read_unlock();
+ 		return err;
++	}
+ 
+ 	ids->in_use++;
+ 
+@@ -280,10 +288,6 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
+ 		ids->seq = 0;
+ 
+ 	new->id = ipc_buildid(id, new->seq);
+-	spin_lock_init(&new->lock);
+-	new->deleted = 0;
+-	rcu_read_lock();
+-	spin_lock(&new->lock);
+ 	return id;
+ }
+ 
+diff --git a/kernel/Makefile b/kernel/Makefile
+index 4e1d7df..143e8b6 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -11,8 +11,6 @@ obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
+ 	    hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
+ 	    notifier.o ksysfs.o pm_qos_params.o sched_clock.o
+ 
+-CFLAGS_REMOVE_sched.o = -mno-spe
+-
+ ifdef CONFIG_FTRACE
+ # Do not trace debug files and internal ftrace files
+ CFLAGS_REMOVE_lockdep.o = -pg
+@@ -21,7 +19,7 @@ CFLAGS_REMOVE_mutex-debug.o = -pg
+ CFLAGS_REMOVE_rtmutex-debug.o = -pg
+ CFLAGS_REMOVE_cgroup-debug.o = -pg
+ CFLAGS_REMOVE_sched_clock.o = -pg
+-CFLAGS_REMOVE_sched.o = -mno-spe -pg
++CFLAGS_REMOVE_sched.o = -pg
+ endif
+ 
+ obj-$(CONFIG_PROFILING) += profile.o
+diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
+index f7921a2..894b599 100644
+--- a/kernel/audit_tree.c
++++ b/kernel/audit_tree.c
+@@ -24,6 +24,7 @@ struct audit_chunk {
+ 	struct list_head trees;		/* with root here */
+ 	int dead;
+ 	int count;
++	atomic_long_t refs;
+ 	struct rcu_head head;
+ 	struct node {
+ 		struct list_head list;
+@@ -56,7 +57,8 @@ static LIST_HEAD(prune_list);
+  * tree is refcounted; one reference for "some rules on rules_list refer to
+  * it", one for each chunk with pointer to it.
+  *
+- * chunk is refcounted by embedded inotify_watch.
++ * chunk is refcounted by embedded inotify_watch + .refs (non-zero refcount
++ * of watch contributes 1 to .refs).
+  *
+  * node.index allows to get from node.list to containing chunk.
+  * MSB of that sucker is stolen to mark taggings that we might have to
+@@ -121,6 +123,7 @@ static struct audit_chunk *alloc_chunk(int count)
+ 	INIT_LIST_HEAD(&chunk->hash);
+ 	INIT_LIST_HEAD(&chunk->trees);
+ 	chunk->count = count;
++	atomic_long_set(&chunk->refs, 1);
+ 	for (i = 0; i < count; i++) {
+ 		INIT_LIST_HEAD(&chunk->owners[i].list);
+ 		chunk->owners[i].index = i;
+@@ -129,9 +132,8 @@ static struct audit_chunk *alloc_chunk(int count)
+ 	return chunk;
+ }
+ 
+-static void __free_chunk(struct rcu_head *rcu)
++static void free_chunk(struct audit_chunk *chunk)
+ {
+-	struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head);
+ 	int i;
+ 
+ 	for (i = 0; i < chunk->count; i++) {
+@@ -141,14 +143,16 @@ static void __free_chunk(struct rcu_head *rcu)
+ 	kfree(chunk);
+ }
+ 
+-static inline void free_chunk(struct audit_chunk *chunk)
++void audit_put_chunk(struct audit_chunk *chunk)
+ {
+-	call_rcu(&chunk->head, __free_chunk);
++	if (atomic_long_dec_and_test(&chunk->refs))
++		free_chunk(chunk);
+ }
+ 
+-void audit_put_chunk(struct audit_chunk *chunk)
++static void __put_chunk(struct rcu_head *rcu)
+ {
+-	put_inotify_watch(&chunk->watch);
++	struct audit_chunk *chunk = container_of(rcu, struct audit_chunk, head);
++	audit_put_chunk(chunk);
+ }
+ 
+ enum {HASH_SIZE = 128};
+@@ -176,7 +180,7 @@ struct audit_chunk *audit_tree_lookup(const struct inode *inode)
+ 
+ 	list_for_each_entry_rcu(p, list, hash) {
+ 		if (p->watch.inode == inode) {
+-			get_inotify_watch(&p->watch);
++			atomic_long_inc(&p->refs);
+ 			return p;
+ 		}
+ 	}
+@@ -194,17 +198,49 @@ int audit_tree_match(struct audit_chunk *chunk, struct audit_tree *tree)
+ 
+ /* tagging and untagging inodes with trees */
+ 
+-static void untag_chunk(struct audit_chunk *chunk, struct node *p)
++static struct audit_chunk *find_chunk(struct node *p)
++{
++	int index = p->index & ~(1U<<31);
++	p -= index;
++	return container_of(p, struct audit_chunk, owners[0]);
++}
++
++static void untag_chunk(struct node *p)
+ {
++	struct audit_chunk *chunk = find_chunk(p);
+ 	struct audit_chunk *new;
+ 	struct audit_tree *owner;
+ 	int size = chunk->count - 1;
+ 	int i, j;
+ 
++	if (!pin_inotify_watch(&chunk->watch)) {
++		/*
++		 * Filesystem is shutting down; all watches are getting
++		 * evicted, just take it off the node list for this
++		 * tree and let the eviction logics take care of the
++		 * rest.
++		 */
++		owner = p->owner;
++		if (owner->root == chunk) {
++			list_del_init(&owner->same_root);
++			owner->root = NULL;
++		}
++		list_del_init(&p->list);
++		p->owner = NULL;
++		put_tree(owner);
++		return;
++	}
++
++	spin_unlock(&hash_lock);
++
++	/*
++	 * pin_inotify_watch() succeeded, so the watch won't go away
++	 * from under us.
++	 */
+ 	mutex_lock(&chunk->watch.inode->inotify_mutex);
+ 	if (chunk->dead) {
+ 		mutex_unlock(&chunk->watch.inode->inotify_mutex);
+-		return;
++		goto out;
+ 	}
+ 
+ 	owner = p->owner;
+@@ -221,7 +257,7 @@ static void untag_chunk(struct audit_chunk *chunk, struct node *p)
+ 		inotify_evict_watch(&chunk->watch);
+ 		mutex_unlock(&chunk->watch.inode->inotify_mutex);
+ 		put_inotify_watch(&chunk->watch);
+-		return;
++		goto out;
+ 	}
+ 
+ 	new = alloc_chunk(size);
+@@ -263,7 +299,7 @@ static void untag_chunk(struct audit_chunk *chunk, struct node *p)
+ 	inotify_evict_watch(&chunk->watch);
+ 	mutex_unlock(&chunk->watch.inode->inotify_mutex);
+ 	put_inotify_watch(&chunk->watch);
+-	return;
++	goto out;
+ 
+ Fallback:
+ 	// do the best we can
+@@ -277,6 +313,9 @@ Fallback:
+ 	put_tree(owner);
+ 	spin_unlock(&hash_lock);
+ 	mutex_unlock(&chunk->watch.inode->inotify_mutex);
++out:
++	unpin_inotify_watch(&chunk->watch);
++	spin_lock(&hash_lock);
+ }
+ 
+ static int create_chunk(struct inode *inode, struct audit_tree *tree)
+@@ -387,13 +426,6 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
+ 	return 0;
+ }
+ 
+-static struct audit_chunk *find_chunk(struct node *p)
+-{
+-	int index = p->index & ~(1U<<31);
+-	p -= index;
+-	return container_of(p, struct audit_chunk, owners[0]);
+-}
+-
+ static void kill_rules(struct audit_tree *tree)
+ {
+ 	struct audit_krule *rule, *next;
+@@ -431,17 +463,10 @@ static void prune_one(struct audit_tree *victim)
+ 	spin_lock(&hash_lock);
+ 	while (!list_empty(&victim->chunks)) {
+ 		struct node *p;
+-		struct audit_chunk *chunk;
+ 
+ 		p = list_entry(victim->chunks.next, struct node, list);
+-		chunk = find_chunk(p);
+-		get_inotify_watch(&chunk->watch);
+-		spin_unlock(&hash_lock);
+-
+-		untag_chunk(chunk, p);
+ 
+-		put_inotify_watch(&chunk->watch);
+-		spin_lock(&hash_lock);
++		untag_chunk(p);
+ 	}
+ 	spin_unlock(&hash_lock);
+ 	put_tree(victim);
+@@ -469,7 +494,6 @@ static void trim_marked(struct audit_tree *tree)
+ 
+ 	while (!list_empty(&tree->chunks)) {
+ 		struct node *node;
+-		struct audit_chunk *chunk;
+ 
+ 		node = list_entry(tree->chunks.next, struct node, list);
+ 
+@@ -477,14 +501,7 @@ static void trim_marked(struct audit_tree *tree)
+ 		if (!(node->index & (1U<<31)))
+ 			break;
+ 
+-		chunk = find_chunk(node);
+-		get_inotify_watch(&chunk->watch);
+-		spin_unlock(&hash_lock);
+-
+-		untag_chunk(chunk, node);
+-
+-		put_inotify_watch(&chunk->watch);
+-		spin_lock(&hash_lock);
++		untag_chunk(node);
+ 	}
+ 	if (!tree->root && !tree->goner) {
+ 		tree->goner = 1;
+@@ -878,7 +895,7 @@ static void handle_event(struct inotify_watch *watch, u32 wd, u32 mask,
+ static void destroy_watch(struct inotify_watch *watch)
+ {
+ 	struct audit_chunk *chunk = container_of(watch, struct audit_chunk, watch);
+-	free_chunk(chunk);
++	call_rcu(&chunk->head, __put_chunk);
+ }
+ 
+ static const struct inotify_operations rtree_inotify_ops = {
+diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
+index b7d354e..9fd85a4 100644
+--- a/kernel/auditfilter.c
++++ b/kernel/auditfilter.c
+@@ -1094,8 +1094,8 @@ static void audit_inotify_unregister(struct list_head *in_list)
+ 	list_for_each_entry_safe(p, n, in_list, ilist) {
+ 		list_del(&p->ilist);
+ 		inotify_rm_watch(audit_ih, &p->wdata);
+-		/* the put matching the get in audit_do_del_rule() */
+-		put_inotify_watch(&p->wdata);
++		/* the unpin matching the pin in audit_do_del_rule() */
++		unpin_inotify_watch(&p->wdata);
+ 	}
+ }
+ 
+@@ -1389,9 +1389,13 @@ static inline int audit_del_rule(struct audit_entry *entry,
+ 				/* Put parent on the inotify un-registration
+ 				 * list.  Grab a reference before releasing
+ 				 * audit_filter_mutex, to be released in
+-				 * audit_inotify_unregister(). */
+-				list_add(&parent->ilist, &inotify_list);
+-				get_inotify_watch(&parent->wdata);
++				 * audit_inotify_unregister().
++				 * If filesystem is going away, just leave
++				 * the sucker alone, eviction will take
++				 * care of it.
++				 */
++				if (pin_inotify_watch(&parent->wdata))
++					list_add(&parent->ilist, &inotify_list);
+ 			}
+ 		}
+ 	}
+diff --git a/kernel/cgroup.c b/kernel/cgroup.c
+index d68bf2b..0ba3a5a 100644
+--- a/kernel/cgroup.c
++++ b/kernel/cgroup.c
+@@ -2045,10 +2045,13 @@ int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry)
+ 	struct cgroup *cgrp;
+ 	struct cgroup_iter it;
+ 	struct task_struct *tsk;
++
+ 	/*
+-	 * Validate dentry by checking the superblock operations
++	 * Validate dentry by checking the superblock operations,
++	 * and make sure it's a directory.
+ 	 */
+-	if (dentry->d_sb->s_op != &cgroup_ops)
++	if (dentry->d_sb->s_op != &cgroup_ops ||
++	    !S_ISDIR(dentry->d_inode->i_mode))
+ 		 goto err;
+ 
+ 	ret = 0;
+diff --git a/kernel/cpuset.c b/kernel/cpuset.c
+index 827cd9a..fbda85d 100644
+--- a/kernel/cpuset.c
++++ b/kernel/cpuset.c
+@@ -587,7 +587,6 @@ static int generate_sched_domains(cpumask_t **domains,
+ 	int ndoms;		/* number of sched domains in result */
+ 	int nslot;		/* next empty doms[] cpumask_t slot */
+ 
+-	ndoms = 0;
+ 	doms = NULL;
+ 	dattr = NULL;
+ 	csa = NULL;
+@@ -674,10 +673,8 @@ restart:
+ 	 * Convert <csn, csa> to <ndoms, doms> and populate cpu masks.
+ 	 */
+ 	doms = kmalloc(ndoms * sizeof(cpumask_t), GFP_KERNEL);
+-	if (!doms) {
+-		ndoms = 0;
++	if (!doms)
+ 		goto done;
+-	}
+ 
+ 	/*
+ 	 * The rest of the code, including the scheduler, can deal with
+@@ -732,6 +729,13 @@ restart:
+ done:
+ 	kfree(csa);
+ 
++	/*
++	 * Fallback to the default domain if kmalloc() failed.
++	 * See comments in partition_sched_domains().
++	 */
++	if (doms == NULL)
++		ndoms = 1;
++
+ 	*domains    = doms;
+ 	*attributes = dattr;
+ 	return ndoms;
+diff --git a/kernel/sched.c b/kernel/sched.c
+index ad1962d..a992cbe 100644
+--- a/kernel/sched.c
++++ b/kernel/sched.c
+@@ -7692,13 +7692,14 @@ static int dattrs_equal(struct sched_domain_attr *cur, int idx_cur,
+  *
+  * The passed in 'doms_new' should be kmalloc'd. This routine takes
+  * ownership of it and will kfree it when done with it. If the caller
+- * failed the kmalloc call, then it can pass in doms_new == NULL,
+- * and partition_sched_domains() will fallback to the single partition
+- * 'fallback_doms', it also forces the domains to be rebuilt.
++ * failed the kmalloc call, then it can pass in doms_new == NULL &&
++ * ndoms_new == 1, and partition_sched_domains() will fallback to
++ * the single partition 'fallback_doms', it also forces the domains
++ * to be rebuilt.
+  *
+- * If doms_new==NULL it will be replaced with cpu_online_map.
+- * ndoms_new==0 is a special case for destroying existing domains.
+- * It will not create the default domain.
++ * If doms_new == NULL it will be replaced with cpu_online_map.
++ * ndoms_new == 0 is a special case for destroying existing domains,
++ * and it will not create the default domain.
+  *
+  * Call with hotplug lock held
+  */
+diff --git a/kernel/sysctl.c b/kernel/sysctl.c
+index 50ec088..6ffbed2 100644
+--- a/kernel/sysctl.c
++++ b/kernel/sysctl.c
+@@ -179,6 +179,9 @@ extern struct ctl_table random_table[];
+ #ifdef CONFIG_INOTIFY_USER
+ extern struct ctl_table inotify_table[];
+ #endif
++#ifdef CONFIG_EPOLL
++extern struct ctl_table epoll_table[];
++#endif
+ 
+ #ifdef HAVE_ARCH_PICK_MMAP_LAYOUT
+ int sysctl_legacy_va_layout;
+@@ -1313,6 +1316,13 @@ static struct ctl_table fs_table[] = {
+ 		.child		= inotify_table,
+ 	},
+ #endif	
++#ifdef CONFIG_EPOLL
++	{
++		.procname	= "epoll",
++		.mode		= 0555,
++		.child		= epoll_table,
++	},
++#endif
+ #endif
+ 	{
+ 		.ctl_name	= KERN_SETUID_DUMPABLE,
+diff --git a/lib/idr.c b/lib/idr.c
+index e728c7f..7a785a0 100644
+--- a/lib/idr.c
++++ b/lib/idr.c
+@@ -185,6 +185,7 @@ static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa)
+ 			new = get_from_free_list(idp);
+ 			if (!new)
+ 				return -1;
++			new->layer = l-1;
+ 			rcu_assign_pointer(p->ary[m], new);
+ 			p->count++;
+ 		}
+@@ -210,6 +211,7 @@ build_up:
+ 	if (unlikely(!p)) {
+ 		if (!(p = get_from_free_list(idp)))
+ 			return -1;
++		p->layer = 0;
+ 		layers = 1;
+ 	}
+ 	/*
+@@ -237,6 +239,7 @@ build_up:
+ 		}
+ 		new->ary[0] = p;
+ 		new->count = 1;
++		new->layer = layers-1;
+ 		if (p->bitmap == IDR_FULL)
+ 			__set_bit(0, &new->bitmap);
+ 		p = new;
+@@ -493,17 +496,21 @@ void *idr_find(struct idr *idp, int id)
+ 	int n;
+ 	struct idr_layer *p;
+ 
+-	n = idp->layers * IDR_BITS;
+ 	p = rcu_dereference(idp->top);
++	if (!p)
++		return NULL;
++	n = (p->layer+1) * IDR_BITS;
+ 
+ 	/* Mask off upper bits we don't use for the search. */
+ 	id &= MAX_ID_MASK;
+ 
+ 	if (id >= (1 << n))
+ 		return NULL;
++	BUG_ON(n == 0);
+ 
+ 	while (n > 0 && p) {
+ 		n -= IDR_BITS;
++		BUG_ON(n != p->layer*IDR_BITS);
+ 		p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]);
+ 	}
+ 	return((void *)p);
+@@ -582,8 +589,11 @@ void *idr_replace(struct idr *idp, void *ptr, int id)
+ 	int n;
+ 	struct idr_layer *p, *old_p;
+ 
+-	n = idp->layers * IDR_BITS;
+ 	p = idp->top;
++	if (!p)
++		return ERR_PTR(-EINVAL);
++
++	n = (p->layer+1) * IDR_BITS;
+ 
+ 	id &= MAX_ID_MASK;
+ 
+diff --git a/lib/scatterlist.c b/lib/scatterlist.c
+index 8d2688f..b7b449d 100644
+--- a/lib/scatterlist.c
++++ b/lib/scatterlist.c
+@@ -395,7 +395,7 @@ void sg_miter_stop(struct sg_mapping_iter *miter)
+ 			WARN_ON(!irqs_disabled());
+ 			kunmap_atomic(miter->addr, KM_BIO_SRC_IRQ);
+ 		} else
+-			kunmap(miter->addr);
++			kunmap(miter->page);
+ 
+ 		miter->page = NULL;
+ 		miter->addr = NULL;
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index 8bde9bf..b0785ef 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -1341,6 +1341,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
+ 
+ 	if (NULL == siocb->scm)
+ 		siocb->scm = &tmp_scm;
++	wait_for_unix_gc();
+ 	err = scm_send(sock, msg, siocb->scm);
+ 	if (err < 0)
+ 		return err;
+@@ -1491,6 +1492,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
+ 
+ 	if (NULL == siocb->scm)
+ 		siocb->scm = &tmp_scm;
++	wait_for_unix_gc();
+ 	err = scm_send(sock, msg, siocb->scm);
+ 	if (err < 0)
+ 		return err;
+diff --git a/net/unix/garbage.c b/net/unix/garbage.c
+index 6d4a9a8..abb3ab3 100644
+--- a/net/unix/garbage.c
++++ b/net/unix/garbage.c
+@@ -80,6 +80,7 @@
+ #include <linux/file.h>
+ #include <linux/proc_fs.h>
+ #include <linux/mutex.h>
++#include <linux/wait.h>
+ 
+ #include <net/sock.h>
+ #include <net/af_unix.h>
+@@ -91,6 +92,7 @@
+ static LIST_HEAD(gc_inflight_list);
+ static LIST_HEAD(gc_candidates);
+ static DEFINE_SPINLOCK(unix_gc_lock);
++static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait);
+ 
+ unsigned int unix_tot_inflight;
+ 
+@@ -266,12 +268,16 @@ static void inc_inflight_move_tail(struct unix_sock *u)
+ 		list_move_tail(&u->link, &gc_candidates);
+ }
+ 
+-/* The external entry point: unix_gc() */
++static bool gc_in_progress = false;
+ 
+-void unix_gc(void)
++void wait_for_unix_gc(void)
+ {
+-	static bool gc_in_progress = false;
++	wait_event(unix_gc_wait, gc_in_progress == false);
++}
+ 
++/* The external entry point: unix_gc() */
++void unix_gc(void)
++{
+ 	struct unix_sock *u;
+ 	struct unix_sock *next;
+ 	struct sk_buff_head hitlist;
+@@ -376,6 +382,7 @@ void unix_gc(void)
+ 	/* All candidates should have been detached by now. */
+ 	BUG_ON(!list_empty(&gc_candidates));
+ 	gc_in_progress = false;
++	wake_up(&unix_gc_wait);
+ 
+  out:
+ 	spin_unlock(&unix_gc_lock);

Modified: dists/trunk/linux-2.6/debian/patches/series/1~experimental.1
==============================================================================
--- dists/trunk/linux-2.6/debian/patches/series/1~experimental.1	(original)
+++ dists/trunk/linux-2.6/debian/patches/series/1~experimental.1	Tue Dec  9 17:09:14 2008
@@ -32,3 +32,4 @@
 + bugfix/all/stable/patch-2.6.27.5
 + bugfix/all/stable/patch-2.6.27.6
 + bugfix/all/stable/patch-2.6.27.7
++ bugfix/all/stable/patch-2.6.27.8



More information about the Kernel-svn-changes mailing list