## Automatically generated incremental diff
## From:   linux-2.6.15-rc7
## To:     linux-2.6.15
## Robot:  $Id: make-incremental-diff,v 1.12 2004/01/06 07:19:36 hpa Exp $

diff -urN linux-2.6.15-rc7/Makefile linux-2.6.15/Makefile
--- linux-2.6.15-rc7/Makefile	2006-01-02 21:11:56.246045622 -0800
+++ linux-2.6.15/Makefile	2006-01-02 21:12:05.371449136 -0800
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 15
-EXTRAVERSION =-rc7
+EXTRAVERSION =
 NAME=Sliding Snow Leopard
 
 # *DOCUMENTATION*
diff -urN linux-2.6.15-rc7/arch/i386/kernel/process.c linux-2.6.15/arch/i386/kernel/process.c
--- linux-2.6.15-rc7/arch/i386/kernel/process.c	2006-01-02 21:11:56.416053140 -0800
+++ linux-2.6.15/arch/i386/kernel/process.c	2006-01-02 21:12:05.543456743 -0800
@@ -554,7 +554,9 @@
 	struct pt_regs ptregs;
 	
 	ptregs = *(struct pt_regs *)
-		((unsigned long)tsk->thread_info+THREAD_SIZE - sizeof(ptregs));
+		((unsigned long)tsk->thread_info +
+		/* see comments in copy_thread() about -8 */
+		THREAD_SIZE - sizeof(ptregs) - 8);
 	ptregs.xcs &= 0xffff;
 	ptregs.xds &= 0xffff;
 	ptregs.xes &= 0xffff;
diff -urN linux-2.6.15-rc7/arch/powerpc/mm/hash_utils_64.c linux-2.6.15/arch/powerpc/mm/hash_utils_64.c
--- linux-2.6.15-rc7/arch/powerpc/mm/hash_utils_64.c	2006-01-02 21:11:56.829071403 -0800
+++ linux-2.6.15/arch/powerpc/mm/hash_utils_64.c	2006-01-02 21:12:05.953474873 -0800
@@ -514,7 +514,7 @@
 #undef KB
 #undef MB
 
-void __init htab_initialize_secondary(void)
+void htab_initialize_secondary(void)
 {
 	if (!platform_is_lpar())
 		mtspr(SPRN_SDR1, _SDR1);
diff -urN linux-2.6.15-rc7/arch/sparc/kernel/vmlinux.lds.S linux-2.6.15/arch/sparc/kernel/vmlinux.lds.S
--- linux-2.6.15-rc7/arch/sparc/kernel/vmlinux.lds.S	2005-10-27 17:02:08.000000000 -0700
+++ linux-2.6.15/arch/sparc/kernel/vmlinux.lds.S	2006-01-02 21:12:06.658506049 -0800
@@ -85,19 +85,9 @@
   }
   _end = . ;
   PROVIDE (end = .);
-  /* Stabs debugging sections.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  .stab.excl 0 : { *(.stab.excl) }
-  .stab.exclstr 0 : { *(.stab.exclstr) }
-  .stab.index 0 : { *(.stab.index) }
-  .stab.indexstr 0 : { *(.stab.indexstr) }
-  .comment 0 : { *(.comment) }
-  .debug          0 : { *(.debug) }
-  .debug_srcinfo  0 : { *(.debug_srcinfo) }
-  .debug_aranges  0 : { *(.debug_aranges) }
-  .debug_pubnames 0 : { *(.debug_pubnames) }
-  .debug_sfnames  0 : { *(.debug_sfnames) }
-  .line           0 : { *(.line) }
   /DISCARD/ : { *(.exit.text) *(.exit.data) *(.exitcall.exit) }
+
+  STABS_DEBUG
+
+  DWARF_DEBUG
 }
diff -urN linux-2.6.15-rc7/arch/sparc64/kernel/vmlinux.lds.S linux-2.6.15/arch/sparc64/kernel/vmlinux.lds.S
--- linux-2.6.15-rc7/arch/sparc64/kernel/vmlinux.lds.S	2005-10-27 17:02:08.000000000 -0700
+++ linux-2.6.15/arch/sparc64/kernel/vmlinux.lds.S	2006-01-02 21:12:06.670506580 -0800
@@ -90,19 +90,9 @@
   }
   _end = . ;
   PROVIDE (end = .);
-  /* Stabs debugging sections.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  .stab.excl 0 : { *(.stab.excl) }
-  .stab.exclstr 0 : { *(.stab.exclstr) }
-  .stab.index 0 : { *(.stab.index) }
-  .stab.indexstr 0 : { *(.stab.indexstr) }
-  .comment 0 : { *(.comment) }
-  .debug          0 : { *(.debug) }
-  .debug_srcinfo  0 : { *(.debug_srcinfo) }
-  .debug_aranges  0 : { *(.debug_aranges) }
-  .debug_pubnames 0 : { *(.debug_pubnames) }
-  .debug_sfnames  0 : { *(.debug_sfnames) }
-  .line           0 : { *(.line) }
   /DISCARD/ : { *(.exit.text) *(.exit.data) *(.exitcall.exit) }
+
+  STABS_DEBUG
+
+  DWARF_DEBUG
 }
diff -urN linux-2.6.15-rc7/arch/um/os-Linux/start_up.c linux-2.6.15/arch/um/os-Linux/start_up.c
--- linux-2.6.15-rc7/arch/um/os-Linux/start_up.c	2006-01-02 21:11:57.585104833 -0800
+++ linux-2.6.15/arch/um/os-Linux/start_up.c	2006-01-02 21:12:06.699507862 -0800
@@ -116,16 +116,16 @@
 	if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
 		int exit_with = WEXITSTATUS(status);
 		if (exit_with == 2)
-			printk("check_ptrace : child exited with status 2. "
+			printf("check_ptrace : child exited with status 2. "
 			       "Serious trouble happening! Try updating your "
 			       "host skas patch!\nDisabling SYSEMU support.");
-		printk("check_ptrace : child exited with exitcode %d, while "
+		printf("check_ptrace : child exited with exitcode %d, while "
 		      "expecting %d; status 0x%x", exit_with,
 		      exitcode, status);
 		if (mustpanic)
 			panic("\n");
 		else
-			printk("\n");
+			printf("\n");
 		ret = -1;
 	}
 
@@ -183,7 +183,7 @@
 	void *stack;
  	int pid, n, status, count=0;
 
-	printk("Checking syscall emulation patch for ptrace...");
+	printf("Checking syscall emulation patch for ptrace...");
 	sysemu_supported = 0;
 	pid = start_ptraced_child(&stack);
 
@@ -207,10 +207,10 @@
 		goto fail_stopped;
 
 	sysemu_supported = 1;
-	printk("OK\n");
+	printf("OK\n");
 	set_using_sysemu(!force_sysemu_disabled);
 
-	printk("Checking advanced syscall emulation patch for ptrace...");
+	printf("Checking advanced syscall emulation patch for ptrace...");
 	pid = start_ptraced_child(&stack);
 
 	if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
@@ -246,7 +246,7 @@
 		goto fail_stopped;
 
 	sysemu_supported = 2;
-	printk("OK\n");
+	printf("OK\n");
 
 	if ( !force_sysemu_disabled )
 		set_using_sysemu(sysemu_supported);
@@ -255,7 +255,7 @@
 fail:
 	stop_ptraced_child(pid, stack, 1, 0);
 fail_stopped:
-	printk("missing\n");
+	printf("missing\n");
 }
 
 static void __init check_ptrace(void)
@@ -263,7 +263,7 @@
 	void *stack;
 	int pid, syscall, n, status;
 
-	printk("Checking that ptrace can change system call numbers...");
+	printf("Checking that ptrace can change system call numbers...");
 	pid = start_ptraced_child(&stack);
 
 	if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
@@ -292,7 +292,7 @@
 		}
 	}
 	stop_ptraced_child(pid, stack, 0, 1);
-	printk("OK\n");
+	printf("OK\n");
 	check_sysemu();
 }
 
@@ -472,6 +472,8 @@
 
 int have_devanon = 0;
 
+/* Runs on boot kernel stack - already safe to use printk. */
+
 void check_devanon(void)
 {
 	int fd;
diff -urN linux-2.6.15-rc7/arch/um/os-Linux/user_syms.c linux-2.6.15/arch/um/os-Linux/user_syms.c
--- linux-2.6.15-rc7/arch/um/os-Linux/user_syms.c	2005-10-27 17:02:08.000000000 -0700
+++ linux-2.6.15/arch/um/os-Linux/user_syms.c	2006-01-02 21:12:06.699507862 -0800
@@ -34,6 +34,11 @@
        int sym(void);                  \
        EXPORT_SYMBOL(sym);
 
+extern void readdir64(void) __attribute__((weak));
+EXPORT_SYMBOL(readdir64);
+extern void truncate64(void) __attribute__((weak));
+EXPORT_SYMBOL(truncate64);
+
 #ifdef SUBARCH_i386
 EXPORT_SYMBOL(vsyscall_ehdr);
 EXPORT_SYMBOL(vsyscall_end);
diff -urN linux-2.6.15-rc7/arch/um/sys-i386/Makefile linux-2.6.15/arch/um/sys-i386/Makefile
--- linux-2.6.15-rc7/arch/um/sys-i386/Makefile	2006-01-02 21:11:57.585104833 -0800
+++ linux-2.6.15/arch/um/sys-i386/Makefile	2006-01-02 21:12:06.700507906 -0800
@@ -1,6 +1,8 @@
-obj-y = bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
-	ptrace_user.o semaphore.o signal.o sigcontext.o stub.o stub_segv.o \
-	syscalls.o sysrq.o sys_call_table.o
+obj-y := bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
+	ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o \
+	sys_call_table.o
+
+obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
 
 obj-$(CONFIG_HIGHMEM) += highmem.o
 obj-$(CONFIG_MODULES) += module.o
diff -urN linux-2.6.15-rc7/arch/um/sys-x86_64/Makefile linux-2.6.15/arch/um/sys-x86_64/Makefile
--- linux-2.6.15-rc7/arch/um/sys-x86_64/Makefile	2006-01-02 21:11:57.587104922 -0800
+++ linux-2.6.15/arch/um/sys-x86_64/Makefile	2006-01-02 21:12:06.701507951 -0800
@@ -6,8 +6,9 @@
 
 #XXX: why into lib-y?
 lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o ldt.o mem.o memcpy.o \
-	ptrace.o ptrace_user.o sigcontext.o signal.o stub.o \
-	stub_segv.o syscalls.o syscall_table.o sysrq.o thunk.o
+	ptrace.o ptrace_user.o sigcontext.o signal.o syscalls.o \
+	syscall_table.o sysrq.o thunk.o
+lib-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o
 
 obj-y := ksyms.o
 obj-$(CONFIG_MODULES) += module.o um_module.o
diff -urN linux-2.6.15-rc7/arch/x86_64/mm/init.c linux-2.6.15/arch/x86_64/mm/init.c
--- linux-2.6.15-rc7/arch/x86_64/mm/init.c	2006-01-02 21:11:57.611105983 -0800
+++ linux-2.6.15/arch/x86_64/mm/init.c	2006-01-02 21:12:06.725509012 -0800
@@ -348,7 +348,7 @@
 	}
 
 	/* Compute holes */
-	w = 0;
+	w = start_pfn;
 	for (i = 0; i < MAX_NR_ZONES; i++) {
 		unsigned long s = w;
 		w += z[i];
diff -urN linux-2.6.15-rc7/drivers/char/drm/radeon_cp.c linux-2.6.15/drivers/char/drm/radeon_cp.c
--- linux-2.6.15-rc7/drivers/char/drm/radeon_cp.c	2006-01-02 21:11:57.836115933 -0800
+++ linux-2.6.15/drivers/char/drm/radeon_cp.c	2006-01-02 21:12:06.950518962 -0800
@@ -1312,8 +1312,6 @@
 static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
-	unsigned int mem_size;
-
 	DRM_DEBUG("\n");
 
 	dev_priv->is_pci = init->is_pci;
@@ -1523,11 +1521,8 @@
 					  + dev_priv->fb_location) >> 10));
 
 	dev_priv->gart_size = init->gart_size;
-
-	mem_size = RADEON_READ(RADEON_CONFIG_MEMSIZE);
-	if (mem_size == 0)
-		mem_size = 0x800000;
-	dev_priv->gart_vm_start = dev_priv->fb_location + mem_size;
+	dev_priv->gart_vm_start = dev_priv->fb_location
+	    + RADEON_READ(RADEON_CONFIG_APER_SIZE);
 
 #if __OS_HAS_AGP
 	if (!dev_priv->is_pci)
diff -urN linux-2.6.15-rc7/drivers/char/vc_screen.c linux-2.6.15/drivers/char/vc_screen.c
--- linux-2.6.15-rc7/drivers/char/vc_screen.c	2006-01-02 21:11:57.927119957 -0800
+++ linux-2.6.15/drivers/char/vc_screen.c	2006-01-02 21:12:07.041522986 -0800
@@ -419,7 +419,7 @@
 			while (this_round > 1) {
 				unsigned short w;
 
-				w = get_unaligned(((const unsigned short *)con_buf0));
+				w = get_unaligned(((unsigned short *)con_buf0));
 				vcs_scr_writew(vc, w, org++);
 				con_buf0 += 2;
 				this_round -= 2;
diff -urN linux-2.6.15-rc7/drivers/input/joystick/warrior.c linux-2.6.15/drivers/input/joystick/warrior.c
--- linux-2.6.15-rc7/drivers/input/joystick/warrior.c	2006-01-02 21:11:58.084126900 -0800
+++ linux-2.6.15/drivers/input/joystick/warrior.c	2006-01-02 21:12:07.199529973 -0800
@@ -172,7 +172,7 @@
 	input_set_abs_params(input_dev, ABS_Y, -64, 64, 0, 8);
 	input_set_abs_params(input_dev, ABS_THROTTLE, -112, 112, 0, 0);
 	input_set_abs_params(input_dev, ABS_HAT0X, -1, 1, 0, 0);
-	input_set_abs_params(input_dev, ABS_HAT0X, -1, 1, 0, 0);
+	input_set_abs_params(input_dev, ABS_HAT0Y, -1, 1, 0, 0);
 
 	serio_set_drvdata(serio, warrior);
 
diff -urN linux-2.6.15-rc7/drivers/input/mouse/sermouse.c linux-2.6.15/drivers/input/mouse/sermouse.c
--- linux-2.6.15-rc7/drivers/input/mouse/sermouse.c	2006-01-02 21:11:58.101127651 -0800
+++ linux-2.6.15/drivers/input/mouse/sermouse.c	2006-01-02 21:12:07.216530725 -0800
@@ -95,7 +95,7 @@
 
 	input_sync(dev);
 
-	if (++sermouse->count == (5 - ((sermouse->type == SERIO_SUN) << 1)))
+	if (++sermouse->count == 5)
 		sermouse->count = 0;
 }
 
diff -urN linux-2.6.15-rc7/drivers/macintosh/therm_pm72.c linux-2.6.15/drivers/macintosh/therm_pm72.c
--- linux-2.6.15-rc7/drivers/macintosh/therm_pm72.c	2006-01-02 21:11:58.142129464 -0800
+++ linux-2.6.15/drivers/macintosh/therm_pm72.c	2006-01-02 21:12:07.256532493 -0800
@@ -923,7 +923,7 @@
 	if (temp_combi >= ((state0->mpu.tmax + 8) << 16)) {
 		printk(KERN_WARNING "Warning ! Temperature way above maximum (%d) !\n",
 		       temp_combi >> 16);
-		state0->overtemp = CPU_MAX_OVERTEMP;
+		state0->overtemp += CPU_MAX_OVERTEMP / 4;
 	} else if (temp_combi > (state0->mpu.tmax << 16))
 		state0->overtemp++;
 	else
@@ -998,7 +998,7 @@
 		printk(KERN_WARNING "Warning ! CPU %d temperature way above maximum"
 		       " (%d) !\n",
 		       state->index, temp >> 16);
-		state->overtemp = CPU_MAX_OVERTEMP;
+		state->overtemp += CPU_MAX_OVERTEMP / 4;
 	} else if (temp > (state->mpu.tmax << 16))
 		state->overtemp++;
 	else
@@ -1060,7 +1060,7 @@
 		printk(KERN_WARNING "Warning ! CPU %d temperature way above maximum"
 		       " (%d) !\n",
 		       state->index, temp >> 16);
-		state->overtemp = CPU_MAX_OVERTEMP;
+		state->overtemp = CPU_MAX_OVERTEMP / 4;
 	} else if (temp > (state->mpu.tmax << 16))
 		state->overtemp++;
 	else
diff -urN linux-2.6.15-rc7/drivers/media/video/saa7134/Kconfig linux-2.6.15/drivers/media/video/saa7134/Kconfig
--- linux-2.6.15-rc7/drivers/media/video/saa7134/Kconfig	2006-01-02 21:11:58.288135920 -0800
+++ linux-2.6.15/drivers/media/video/saa7134/Kconfig	2006-01-02 21:12:07.400538861 -0800
@@ -14,7 +14,7 @@
 
 config VIDEO_SAA7134_ALSA
 	tristate "Philips SAA7134 DMA audio support"
-	depends on VIDEO_SAA7134 && SOUND && SND && (!VIDEO_SAA7134_OSS || VIDEO_SAA7134_OSS = m)
+	depends on VIDEO_SAA7134 && SND
 	select SND_PCM_OSS
 	---help---
 	  This is a video4linux driver for direct (DMA) audio in
@@ -25,7 +25,7 @@
 
 config VIDEO_SAA7134_OSS
 	tristate "Philips SAA7134 DMA audio support (OSS, DEPRECATED)"
-	depends on VIDEO_SAA7134 && SOUND_PRIME && (!VIDEO_SAA7134_ALSA || VIDEO_SAA7134_ALSA = m)
+	depends on VIDEO_SAA7134 && SOUND_PRIME && !VIDEO_SAA7134_ALSA
 	---help---
 	  This is a video4linux driver for direct (DMA) audio in
 	  Philips SAA713x based TV cards using OSS
diff -urN linux-2.6.15-rc7/drivers/mmc/mmc_block.c linux-2.6.15/drivers/mmc/mmc_block.c
--- linux-2.6.15-rc7/drivers/mmc/mmc_block.c	2006-01-02 21:11:58.349138618 -0800
+++ linux-2.6.15/drivers/mmc/mmc_block.c	2006-01-02 21:12:07.462541603 -0800
@@ -359,7 +359,12 @@
 		md->block_bits = card->csd.read_blkbits;
 
 		blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
-		set_capacity(md->disk, card->csd.capacity);
+
+		/*
+		 * The CSD capacity field is in units of read_blkbits.
+		 * set_capacity takes units of 512 bytes.
+		 */
+		set_capacity(md->disk, card->csd.capacity << (card->csd.read_blkbits - 9));
 	}
  out:
 	return md;
@@ -373,7 +378,7 @@
 
 	mmc_card_claim_host(card);
 	cmd.opcode = MMC_SET_BLOCKLEN;
-	cmd.arg = 1 << card->csd.read_blkbits;
+	cmd.arg = 1 << md->block_bits;
 	cmd.flags = MMC_RSP_R1;
 	err = mmc_wait_for_cmd(card->host, &cmd, 5);
 	mmc_card_release_host(card);
@@ -412,10 +417,9 @@
 	if (err)
 		goto out;
 
-	printk(KERN_INFO "%s: %s %s %dKiB %s\n",
+	printk(KERN_INFO "%s: %s %s %luKiB %s\n",
 		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
-		(card->csd.capacity << card->csd.read_blkbits) / 1024,
-		mmc_blk_readonly(card)?"(ro)":"");
+		get_capacity(md->disk) >> 1, mmc_blk_readonly(card)?"(ro)":"");
 
 	mmc_set_drvdata(card, md);
 	add_disk(md->disk);
diff -urN linux-2.6.15-rc7/drivers/net/ppp_generic.c linux-2.6.15/drivers/net/ppp_generic.c
--- linux-2.6.15-rc7/drivers/net/ppp_generic.c	2006-01-02 21:11:58.583148966 -0800
+++ linux-2.6.15/drivers/net/ppp_generic.c	2006-01-02 21:12:07.693551818 -0800
@@ -524,9 +524,6 @@
 	if (copy_from_user(&uprog, arg, sizeof(uprog)))
 		return -EFAULT;
 
-	if (uprog.len > BPF_MAXINSNS)
-		return -EINVAL;
-
 	if (!uprog.len) {
 		*p = NULL;
 		return 0;
diff -urN linux-2.6.15-rc7/drivers/net/tg3.c linux-2.6.15/drivers/net/tg3.c
--- linux-2.6.15-rc7/drivers/net/tg3.c	2006-01-02 21:11:58.639151442 -0800
+++ linux-2.6.15/drivers/net/tg3.c	2006-01-02 21:12:07.747554206 -0800
@@ -68,8 +68,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"3.46"
-#define DRV_MODULE_RELDATE	"Dec 19, 2005"
+#define DRV_MODULE_VERSION	"3.47"
+#define DRV_MODULE_RELDATE	"Dec 28, 2005"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -7151,8 +7151,13 @@
 	GET_REG32_LOOP(BUFMGR_MODE, 0x58);
 	GET_REG32_LOOP(RDMAC_MODE, 0x08);
 	GET_REG32_LOOP(WDMAC_MODE, 0x08);
-	GET_REG32_LOOP(RX_CPU_BASE, 0x280);
-	GET_REG32_LOOP(TX_CPU_BASE, 0x280);
+	GET_REG32_1(RX_CPU_MODE);
+	GET_REG32_1(RX_CPU_STATE);
+	GET_REG32_1(RX_CPU_PGMCTR);
+	GET_REG32_1(RX_CPU_HWBKPT);
+	GET_REG32_1(TX_CPU_MODE);
+	GET_REG32_1(TX_CPU_STATE);
+	GET_REG32_1(TX_CPU_PGMCTR);
 	GET_REG32_LOOP(GRCMBOX_INTERRUPT_0, 0x110);
 	GET_REG32_LOOP(FTQ_RESET, 0x120);
 	GET_REG32_LOOP(MSGINT_MODE, 0x0c);
diff -urN linux-2.6.15-rc7/drivers/net/tg3.h linux-2.6.15/drivers/net/tg3.h
--- linux-2.6.15-rc7/drivers/net/tg3.h	2006-01-02 21:11:58.641151530 -0800
+++ linux-2.6.15/drivers/net/tg3.h	2006-01-02 21:12:07.748554250 -0800
@@ -1124,7 +1124,14 @@
 /* 0x280 --> 0x400 unused */
 
 #define RX_CPU_BASE			0x00005000
+#define RX_CPU_MODE			0x00005000
+#define RX_CPU_STATE			0x00005004
+#define RX_CPU_PGMCTR			0x0000501c
+#define RX_CPU_HWBKPT			0x00005034
 #define TX_CPU_BASE			0x00005400
+#define TX_CPU_MODE			0x00005400
+#define TX_CPU_STATE			0x00005404
+#define TX_CPU_PGMCTR			0x0000541c
 
 /* Mailboxes */
 #define GRCMBOX_INTERRUPT_0		0x00005800 /* 64-bit */
diff -urN linux-2.6.15-rc7/drivers/scsi/scsi_scan.c linux-2.6.15/drivers/scsi/scsi_scan.c
--- linux-2.6.15-rc7/drivers/scsi/scsi_scan.c	2006-01-02 21:11:59.304180849 -0800
+++ linux-2.6.15/drivers/scsi/scsi_scan.c	2006-01-02 21:12:08.409583480 -0800
@@ -418,8 +418,9 @@
 	if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
 		list_del_init(&starget->siblings);
 		spin_unlock_irqrestore(shost->host_lock, flags);
+		transport_remove_device(&starget->dev);
 		device_del(&starget->dev);
-		transport_unregister_device(&starget->dev);
+		transport_destroy_device(&starget->dev);
 		put_device(&starget->dev);
 		return;
 
diff -urN linux-2.6.15-rc7/drivers/serial/amba-pl011.c linux-2.6.15/drivers/serial/amba-pl011.c
--- linux-2.6.15-rc7/drivers/serial/amba-pl011.c	2006-01-02 21:11:59.343182573 -0800
+++ linux-2.6.15/drivers/serial/amba-pl011.c	2006-01-02 21:12:08.448585205 -0800
@@ -160,7 +160,7 @@
 				flag = TTY_FRAME;
 		}
 
-		if (uart_handle_sysrq_char(&uap->port, ch, regs))
+		if (uart_handle_sysrq_char(&uap->port, ch & 255, regs))
 			goto ignore_char;
 
 		uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
diff -urN linux-2.6.15-rc7/drivers/serial/pxa.c linux-2.6.15/drivers/serial/pxa.c
--- linux-2.6.15-rc7/drivers/serial/pxa.c	2006-01-02 21:11:59.354183060 -0800
+++ linux-2.6.15/drivers/serial/pxa.c	2006-01-02 21:12:08.459585691 -0800
@@ -361,7 +361,7 @@
 	if (port->line == 3) /* HWUART */
 		up->mcr |= UART_MCR_AFE;
 	else
-	up->mcr = 0;
+		up->mcr = 0;
 
 	/*
 	 * Allocate the IRQ
@@ -641,7 +641,7 @@
 	int i;
 
 	/*
-	 *	First save the UER then disable the interrupts
+	 *	First save the IER then disable the interrupts
 	 */
 	ier = serial_in(up, UART_IER);
 	serial_out(up, UART_IER, UART_IER_UUE);
diff -urN linux-2.6.15-rc7/drivers/usb/input/aiptek.c linux-2.6.15/drivers/usb/input/aiptek.c
--- linux-2.6.15-rc7/drivers/usb/input/aiptek.c	2006-01-02 21:11:59.428186332 -0800
+++ linux-2.6.15/drivers/usb/input/aiptek.c	2006-01-02 21:12:08.532588920 -0800
@@ -2103,7 +2103,7 @@
 	 * values.
 	 */
 	input_set_abs_params(inputdev, ABS_X, 0, 2999, 0, 0);
-	input_set_abs_params(inputdev, ABS_X, 0, 2249, 0, 0);
+	input_set_abs_params(inputdev, ABS_Y, 0, 2249, 0, 0);
 	input_set_abs_params(inputdev, ABS_PRESSURE, 0, 511, 0, 0);
 	input_set_abs_params(inputdev, ABS_TILT_X, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0);
 	input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0);
diff -urN linux-2.6.15-rc7/drivers/usb/input/kbtab.c linux-2.6.15/drivers/usb/input/kbtab.c
--- linux-2.6.15-rc7/drivers/usb/input/kbtab.c	2006-01-02 21:11:59.434186597 -0800
+++ linux-2.6.15/drivers/usb/input/kbtab.c	2006-01-02 21:12:08.538589185 -0800
@@ -159,7 +159,7 @@
 	input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH);
 	input_dev->mscbit[0] |= BIT(MSC_SERIAL);
 	input_set_abs_params(input_dev, ABS_X, 0, 0x2000, 4, 0);
-	input_set_abs_params(input_dev, ABS_X, 0, 0x1750, 4, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, 0x1750, 4, 0);
 	input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0);
 
 	endpoint = &intf->cur_altsetting->endpoint[0].desc;
diff -urN linux-2.6.15-rc7/drivers/usb/input/wacom.c linux-2.6.15/drivers/usb/input/wacom.c
--- linux-2.6.15-rc7/drivers/usb/input/wacom.c	2006-01-02 21:11:59.440186863 -0800
+++ linux-2.6.15/drivers/usb/input/wacom.c	2006-01-02 21:12:08.544589450 -0800
@@ -854,7 +854,7 @@
 
 	input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS);
 	input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS);
-	input_set_abs_params(input_dev, ABS_X, 0, wacom->features->y_max, 4, 0);
+	input_set_abs_params(input_dev, ABS_X, 0, wacom->features->x_max, 4, 0);
 	input_set_abs_params(input_dev, ABS_Y, 0, wacom->features->y_max, 4, 0);
 	input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom->features->pressure_max, 0, 0);
 
diff -urN linux-2.6.15-rc7/fs/hostfs/hostfs_kern.c linux-2.6.15/fs/hostfs/hostfs_kern.c
--- linux-2.6.15-rc7/fs/hostfs/hostfs_kern.c	2006-01-02 21:11:59.661196635 -0800
+++ linux-2.6.15/fs/hostfs/hostfs_kern.c	2006-01-02 21:12:08.764599179 -0800
@@ -501,11 +501,16 @@
 	long long start;
 	int err = 0;
 
-	start = (long long) (page->index << PAGE_CACHE_SHIFT) + from;
+	start = (((long long) page->index) << PAGE_CACHE_SHIFT) + from;
 	buffer = kmap(page);
 	err = write_file(FILE_HOSTFS_I(file)->fd, &start, buffer + from,
 			 to - from);
 	if(err > 0) err = 0;
+
+	/* Actually, if !err, write_file has added to-from to start, so, despite
+	 * the appearance, we are comparing i_size against the _last_ written
+	 * location, as we should. */
+
 	if(!err && (start > inode->i_size))
 		inode->i_size = start;
 
@@ -910,10 +915,8 @@
 int hostfs_link_readpage(struct file *file, struct page *page)
 {
 	char *buffer, *name;
-	long long start;
 	int err;
 
-	start = page->index << PAGE_CACHE_SHIFT;
 	buffer = kmap(page);
 	name = inode_name(page->mapping->host, 0);
 	if(name == NULL) return(-ENOMEM);
diff -urN linux-2.6.15-rc7/fs/proc/generic.c linux-2.6.15/fs/proc/generic.c
--- linux-2.6.15-rc7/fs/proc/generic.c	2006-01-02 21:11:59.769201411 -0800
+++ linux-2.6.15/fs/proc/generic.c	2006-01-02 21:12:08.873603999 -0800
@@ -54,6 +54,18 @@
 	ssize_t	n, count;
 	char	*start;
 	struct proc_dir_entry * dp;
+	unsigned long long pos;
+
+	/*
+	 * Gaah, please just use "seq_file" instead. The legacy /proc
+	 * interfaces cut loff_t down to off_t for reads, and ignore
+	 * the offset entirely for writes..
+	 */
+	pos = *ppos;
+	if (pos > MAX_NON_LFS)
+		return 0;
+	if (nbytes > MAX_NON_LFS - pos)
+		nbytes = MAX_NON_LFS - pos;
 
 	dp = PDE(inode);
 	if (!(page = (char*) __get_free_page(GFP_KERNEL)))
@@ -202,30 +214,17 @@
 static loff_t
 proc_file_lseek(struct file *file, loff_t offset, int orig)
 {
-    lock_kernel();
-
-    switch (orig) {
-    case 0:
-	if (offset < 0)
-	    goto out;
-	file->f_pos = offset;
-	unlock_kernel();
-	return(file->f_pos);
-    case 1:
-	if (offset + file->f_pos < 0)
-	    goto out;
-	file->f_pos += offset;
-	unlock_kernel();
-	return(file->f_pos);
-    case 2:
-	goto out;
-    default:
-	goto out;
-    }
-
-out:
-    unlock_kernel();
-    return -EINVAL;
+	loff_t retval = -EINVAL;
+	switch (orig) {
+	case 1:
+		offset += file->f_pos;
+	/* fallthrough */
+	case 0:
+		if (offset < 0 || offset > MAX_NON_LFS)
+			break;
+		file->f_pos = retval = offset;
+	}
+	return retval;
 }
 
 static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
diff -urN linux-2.6.15-rc7/include/asm-i386/param.h linux-2.6.15/include/asm-i386/param.h
--- linux-2.6.15-rc7/include/asm-i386/param.h	2005-10-27 17:02:08.000000000 -0700
+++ linux-2.6.15/include/asm-i386/param.h	2006-01-02 21:12:09.076612976 -0800
@@ -1,9 +1,8 @@
-#include <linux/config.h>
-
 #ifndef _ASMi386_PARAM_H
 #define _ASMi386_PARAM_H
 
 #ifdef __KERNEL__
+# include <linux/config.h>
 # define HZ		CONFIG_HZ	/* Internal kernel timer frequency */
 # define USER_HZ	100		/* .. some user interfaces are in "ticks" */
 # define CLOCKS_PER_SEC		(USER_HZ)	/* like times() */
diff -urN linux-2.6.15-rc7/include/asm-x86_64/param.h linux-2.6.15/include/asm-x86_64/param.h
--- linux-2.6.15-rc7/include/asm-x86_64/param.h	2005-10-27 17:02:08.000000000 -0700
+++ linux-2.6.15/include/asm-x86_64/param.h	2006-01-02 21:12:09.625637254 -0800
@@ -1,9 +1,8 @@
-#include <linux/config.h>
-
 #ifndef _ASMx86_64_PARAM_H
 #define _ASMx86_64_PARAM_H
 
 #ifdef __KERNEL__
+# include <linux/config.h>
 # define HZ            CONFIG_HZ	/* Internal kernel timer frequency */
 # define USER_HZ       100		/* .. some user interfaces are in "ticks */
 #define CLOCKS_PER_SEC        (USER_HZ)       /* like times() */
diff -urN linux-2.6.15-rc7/include/net/if_inet6.h linux-2.6.15/include/net/if_inet6.h
--- linux-2.6.15-rc7/include/net/if_inet6.h	2006-01-02 21:12:00.639239883 -0800
+++ linux-2.6.15/include/net/if_inet6.h	2006-01-02 21:12:09.748642693 -0800
@@ -83,6 +83,7 @@
 	struct in6_addr		addr;
 	int			ifindex;
 	struct ipv6_mc_socklist *next;
+	rwlock_t		sflock;
 	unsigned int		sfmode;		/* MCAST_{INCLUDE,EXCLUDE} */
 	struct ip6_sf_socklist	*sflist;
 };
diff -urN linux-2.6.15-rc7/kernel/sysctl.c linux-2.6.15/kernel/sysctl.c
--- linux-2.6.15-rc7/kernel/sysctl.c	2006-01-02 21:12:00.696242404 -0800
+++ linux-2.6.15/kernel/sysctl.c	2006-01-02 21:12:09.805645213 -0800
@@ -2192,29 +2192,32 @@
 		  void __user *oldval, size_t __user *oldlenp,
 		  void __user *newval, size_t newlen, void **context)
 {
-	size_t l, len;
-	
 	if (!table->data || !table->maxlen) 
 		return -ENOTDIR;
 	
 	if (oldval && oldlenp) {
-		if (get_user(len, oldlenp))
+		size_t bufsize;
+		if (get_user(bufsize, oldlenp))
 			return -EFAULT;
-		if (len) {
-			l = strlen(table->data);
-			if (len > l) len = l;
-			if (len >= table->maxlen)
+		if (bufsize) {
+			size_t len = strlen(table->data), copied;
+
+			/* This shouldn't trigger for a well-formed sysctl */
+			if (len > table->maxlen)
 				len = table->maxlen;
-			if(copy_to_user(oldval, table->data, len))
-				return -EFAULT;
-			if(put_user(0, ((char __user *) oldval) + len))
+
+			/* Copy up to a max of bufsize-1 bytes of the string */
+			copied = (len >= bufsize) ? bufsize - 1 : len;
+
+			if (copy_to_user(oldval, table->data, copied) ||
+			    put_user(0, (char __user *)(oldval + copied)))
 				return -EFAULT;
-			if(put_user(len, oldlenp))
+			if (put_user(len, oldlenp))
 				return -EFAULT;
 		}
 	}
 	if (newval && newlen) {
-		len = newlen;
+		size_t len = newlen;
 		if (len > table->maxlen)
 			len = table->maxlen;
 		if(copy_from_user(table->data, newval, len))
@@ -2223,7 +2226,7 @@
 			len--;
 		((char *) table->data)[len] = 0;
 	}
-	return 0;
+	return 1;
 }
 
 /*
diff -urN linux-2.6.15-rc7/mm/mempolicy.c linux-2.6.15/mm/mempolicy.c
--- linux-2.6.15-rc7/mm/mempolicy.c	2006-01-02 21:12:00.718243377 -0800
+++ linux-2.6.15/mm/mempolicy.c	2006-01-02 21:12:09.827646186 -0800
@@ -161,6 +161,10 @@
 	switch (mode) {
 	case MPOL_INTERLEAVE:
 		policy->v.nodes = *nodes;
+		if (nodes_weight(*nodes) == 0) {
+			kmem_cache_free(policy_cache, policy);
+			return ERR_PTR(-EINVAL);
+		}
 		break;
 	case MPOL_PREFERRED:
 		policy->v.preferred_node = first_node(*nodes);
diff -urN linux-2.6.15-rc7/net/bridge/br_netfilter.c linux-2.6.15/net/bridge/br_netfilter.c
--- linux-2.6.15-rc7/net/bridge/br_netfilter.c	2006-01-02 21:12:00.750244792 -0800
+++ linux-2.6.15/net/bridge/br_netfilter.c	2006-01-02 21:12:09.858647557 -0800
@@ -369,6 +369,7 @@
 	if (hdr->nexthdr == NEXTHDR_HOP && check_hbh_len(skb))
 			goto inhdr_error;
 
+ 	nf_bridge_put(skb->nf_bridge);
 	if ((nf_bridge = nf_bridge_alloc(skb)) == NULL)
 		return NF_DROP;
 	setup_pre_routing(skb);
@@ -452,6 +453,7 @@
 			skb->ip_summed = CHECKSUM_NONE;
 	}
 
+ 	nf_bridge_put(skb->nf_bridge);
 	if ((nf_bridge = nf_bridge_alloc(skb)) == NULL)
 		return NF_DROP;
 	setup_pre_routing(skb);
diff -urN linux-2.6.15-rc7/net/core/filter.c linux-2.6.15/net/core/filter.c
--- linux-2.6.15-rc7/net/core/filter.c	2006-01-02 21:12:00.753244924 -0800
+++ linux-2.6.15/net/core/filter.c	2006-01-02 21:12:09.862647734 -0800
@@ -293,7 +293,7 @@
 	struct sock_filter *ftest;
 	int pc;
 
-	if (((unsigned int)flen >= (~0U / sizeof(struct sock_filter))) || flen == 0)
+	if (flen == 0 || flen > BPF_MAXINSNS)
 		return -EINVAL;
 
 	/* check the filter code now */
@@ -360,7 +360,7 @@
 	int err;
 
 	/* Make sure new filter is there and in the right amounts. */
-        if (fprog->filter == NULL || fprog->len > BPF_MAXINSNS)
+        if (fprog->filter == NULL)
                 return -EINVAL;
 
 	fp = sock_kmalloc(sk, fsize+sizeof(*fp), GFP_KERNEL);
diff -urN linux-2.6.15-rc7/net/ipv6/addrconf.c linux-2.6.15/net/ipv6/addrconf.c
--- linux-2.6.15-rc7/net/ipv6/addrconf.c	2006-01-02 21:12:00.822247976 -0800
+++ linux-2.6.15/net/ipv6/addrconf.c	2006-01-02 21:12:09.930650741 -0800
@@ -2467,11 +2467,9 @@
 		return;
 	}
 
-	if (idev->if_flags & IF_READY) {
-		addrconf_dad_kick(ifp);
-		spin_unlock_bh(&ifp->lock);
-	} else {
+	if (!(idev->if_flags & IF_READY)) {
 		spin_unlock_bh(&ifp->lock);
+		read_unlock_bh(&idev->lock);
 		/*
 		 * If the defice is not ready:
 		 * - keep it tentative if it is a permanent address.
@@ -2479,7 +2477,10 @@
 		 */
 		in6_ifa_hold(ifp);
 		addrconf_dad_stop(ifp);
+		return;
 	}
+	addrconf_dad_kick(ifp);
+	spin_unlock_bh(&ifp->lock);
 out:
 	read_unlock_bh(&idev->lock);
 }
diff -urN linux-2.6.15-rc7/net/ipv6/mcast.c linux-2.6.15/net/ipv6/mcast.c
--- linux-2.6.15-rc7/net/ipv6/mcast.c	2006-01-02 21:12:00.830248329 -0800
+++ linux-2.6.15/net/ipv6/mcast.c	2006-01-02 21:12:09.938651095 -0800
@@ -170,7 +170,7 @@
 #define MLDV2_QQIC(value) MLDV2_EXP(0x80, 4, 3, value)
 #define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value)
 
-#define IPV6_MLD_MAX_MSF	10
+#define IPV6_MLD_MAX_MSF	64
 
 int sysctl_mld_max_msf = IPV6_MLD_MAX_MSF;
 
@@ -224,6 +224,7 @@
 
 	mc_lst->ifindex = dev->ifindex;
 	mc_lst->sfmode = MCAST_EXCLUDE;
+	mc_lst->sflock = RW_LOCK_UNLOCKED;
 	mc_lst->sflist = NULL;
 
 	/*
@@ -360,6 +361,7 @@
 	struct ip6_sf_socklist *psl;
 	int i, j, rv;
 	int leavegroup = 0;
+	int pmclocked = 0;
 	int err;
 
 	if (pgsr->gsr_group.ss_family != AF_INET6 ||
@@ -403,6 +405,9 @@
 		pmc->sfmode = omode;
 	}
 
+	write_lock_bh(&pmc->sflock);
+	pmclocked = 1;
+
 	psl = pmc->sflist;
 	if (!add) {
 		if (!psl)
@@ -475,6 +480,8 @@
 	/* update the interface list */
 	ip6_mc_add_src(idev, group, omode, 1, source, 1);
 done:
+	if (pmclocked)
+		write_unlock_bh(&pmc->sflock);
 	read_unlock_bh(&ipv6_sk_mc_lock);
 	read_unlock_bh(&idev->lock);
 	in6_dev_put(idev);
@@ -510,6 +517,8 @@
 	dev = idev->dev;
 
 	err = 0;
+	read_lock_bh(&ipv6_sk_mc_lock);
+
 	if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) {
 		leavegroup = 1;
 		goto done;
@@ -549,6 +558,8 @@
 		newpsl = NULL;
 		(void) ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0);
 	}
+
+	write_lock_bh(&pmc->sflock);
 	psl = pmc->sflist;
 	if (psl) {
 		(void) ip6_mc_del_src(idev, group, pmc->sfmode,
@@ -558,8 +569,10 @@
 		(void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0);
 	pmc->sflist = newpsl;
 	pmc->sfmode = gsf->gf_fmode;
+	write_unlock_bh(&pmc->sflock);
 	err = 0;
 done:
+	read_unlock_bh(&ipv6_sk_mc_lock);
 	read_unlock_bh(&idev->lock);
 	in6_dev_put(idev);
 	dev_put(dev);
@@ -592,6 +605,11 @@
 	dev = idev->dev;
 
 	err = -EADDRNOTAVAIL;
+	/*
+	 * changes to the ipv6_mc_list require the socket lock and
+	 * a read lock on ip6_sk_mc_lock. We have the socket lock,
+	 * so reading the list is safe.
+	 */
 
 	for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) {
 		if (pmc->ifindex != gsf->gf_interface)
@@ -614,6 +632,10 @@
 	    copy_to_user(optval, gsf, GROUP_FILTER_SIZE(0))) {
 		return -EFAULT;
 	}
+	/* changes to psl require the socket lock, a read lock on
+	 * on ipv6_sk_mc_lock and a write lock on pmc->sflock. We
+	 * have the socket lock, so reading here is safe.
+	 */
 	for (i=0; i<copycount; i++) {
 		struct sockaddr_in6 *psin6;
 		struct sockaddr_storage ss;
@@ -650,6 +672,7 @@
 		read_unlock(&ipv6_sk_mc_lock);
 		return 1;
 	}
+	read_lock(&mc->sflock);
 	psl = mc->sflist;
 	if (!psl) {
 		rv = mc->sfmode == MCAST_EXCLUDE;
@@ -665,6 +688,7 @@
 		if (mc->sfmode == MCAST_EXCLUDE && i < psl->sl_count)
 			rv = 0;
 	}
+	read_unlock(&mc->sflock);
 	read_unlock(&ipv6_sk_mc_lock);
 
 	return rv;
@@ -1068,7 +1092,8 @@
 	ma->mca_flags |= MAF_TIMER_RUNNING;
 }
 
-static void mld_marksources(struct ifmcaddr6 *pmc, int nsrcs,
+/* mark EXCLUDE-mode sources */
+static int mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs,
 	struct in6_addr *srcs)
 {
 	struct ip6_sf_list *psf;
@@ -1078,13 +1103,53 @@
 	for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
 		if (scount == nsrcs)
 			break;
-		for (i=0; i<nsrcs; i++)
+		for (i=0; i<nsrcs; i++) {
+			/* skip inactive filters */
+			if (pmc->mca_sfcount[MCAST_INCLUDE] ||
+			    pmc->mca_sfcount[MCAST_EXCLUDE] !=
+			    psf->sf_count[MCAST_EXCLUDE])
+				continue;
+			if (ipv6_addr_equal(&srcs[i], &psf->sf_addr)) {
+				scount++;
+				break;
+			}
+		}
+	}
+	pmc->mca_flags &= ~MAF_GSQUERY;
+	if (scount == nsrcs)	/* all sources excluded */
+		return 0;
+	return 1;
+}
+
+static int mld_marksources(struct ifmcaddr6 *pmc, int nsrcs,
+	struct in6_addr *srcs)
+{
+	struct ip6_sf_list *psf;
+	int i, scount;
+
+	if (pmc->mca_sfmode == MCAST_EXCLUDE)
+		return mld_xmarksources(pmc, nsrcs, srcs);
+
+	/* mark INCLUDE-mode sources */
+
+	scount = 0;
+	for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+		if (scount == nsrcs)
+			break;
+		for (i=0; i<nsrcs; i++) {
 			if (ipv6_addr_equal(&srcs[i], &psf->sf_addr)) {
 				psf->sf_gsresp = 1;
 				scount++;
 				break;
 			}
+		}
+	}
+	if (!scount) {
+		pmc->mca_flags &= ~MAF_GSQUERY;
+		return 0;
 	}
+	pmc->mca_flags |= MAF_GSQUERY;
+	return 1;
 }
 
 int igmp6_event_query(struct sk_buff *skb)
@@ -1167,7 +1232,7 @@
 		/* mark sources to include, if group & source-specific */
 		if (mlh2->nsrcs != 0) {
 			if (!pskb_may_pull(skb, srcs_offset + 
-				mlh2->nsrcs * sizeof(struct in6_addr))) {
+			    ntohs(mlh2->nsrcs) * sizeof(struct in6_addr))) {
 				in6_dev_put(idev);
 				return -EINVAL;
 			}
@@ -1203,10 +1268,9 @@
 				else
 					ma->mca_flags &= ~MAF_GSQUERY;
 			}
-			if (ma->mca_flags & MAF_GSQUERY)
-				mld_marksources(ma, ntohs(mlh2->nsrcs),
-					mlh2->srcs);
-			igmp6_group_queried(ma, max_delay);
+			if (!(ma->mca_flags & MAF_GSQUERY) ||
+			   mld_marksources(ma, ntohs(mlh2->nsrcs), mlh2->srcs))
+				igmp6_group_queried(ma, max_delay);
 			spin_unlock_bh(&ma->mca_lock);
 			if (group_type != IPV6_ADDR_ANY)
 				break;
@@ -1281,7 +1345,18 @@
 	case MLD2_MODE_IS_EXCLUDE:
 		if (gdeleted || sdeleted)
 			return 0;
-		return !((pmc->mca_flags & MAF_GSQUERY) && !psf->sf_gsresp);
+		if (!((pmc->mca_flags & MAF_GSQUERY) && !psf->sf_gsresp)) {
+			if (pmc->mca_sfmode == MCAST_INCLUDE)
+				return 1;
+			/* don't include if this source is excluded
+			 * in all filters
+			 */
+			if (psf->sf_count[MCAST_INCLUDE])
+				return 0;
+			return pmc->mca_sfcount[MCAST_EXCLUDE] ==
+				psf->sf_count[MCAST_EXCLUDE];
+		}
+		return 0;
 	case MLD2_CHANGE_TO_INCLUDE:
 		if (gdeleted || sdeleted)
 			return 0;
@@ -1450,7 +1525,7 @@
 	struct mld2_report *pmr;
 	struct mld2_grec *pgr = NULL;
 	struct ip6_sf_list *psf, *psf_next, *psf_prev, **psf_list;
-	int scount, first, isquery, truncate;
+	int scount, stotal, first, isquery, truncate;
 
 	if (pmc->mca_flags & MAF_NOREPORT)
 		return skb;
@@ -1460,25 +1535,13 @@
 	truncate = type == MLD2_MODE_IS_EXCLUDE ||
 		    type == MLD2_CHANGE_TO_EXCLUDE;
 
+	stotal = scount = 0;
+
 	psf_list = sdeleted ? &pmc->mca_tomb : &pmc->mca_sources;
 
-	if (!*psf_list) {
-		if (type == MLD2_ALLOW_NEW_SOURCES ||
-		    type == MLD2_BLOCK_OLD_SOURCES)
-			return skb;
-		if (pmc->mca_crcount || isquery) {
-			/* make sure we have room for group header and at
-			 * least one source.
-			 */
-			if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)+
-			    sizeof(struct in6_addr)) {
-				mld_sendpack(skb);
-				skb = NULL; /* add_grhead will get a new one */
-			}
-			skb = add_grhead(skb, pmc, type, &pgr);
-		}
-		return skb;
-	}
+	if (!*psf_list)
+		goto empty_source;
+
 	pmr = skb ? (struct mld2_report *)skb->h.raw : NULL;
 
 	/* EX and TO_EX get a fresh packet, if needed */
@@ -1491,7 +1554,6 @@
 		}
 	}
 	first = 1;
-	scount = 0;
 	psf_prev = NULL;
 	for (psf=*psf_list; psf; psf=psf_next) {
 		struct in6_addr *psrc;
@@ -1525,7 +1587,7 @@
 		}
 		psrc = (struct in6_addr *)skb_put(skb, sizeof(*psrc));
 		*psrc = psf->sf_addr;
-		scount++;
+		scount++; stotal++;
 		if ((type == MLD2_ALLOW_NEW_SOURCES ||
 		     type == MLD2_BLOCK_OLD_SOURCES) && psf->sf_crcount) {
 			psf->sf_crcount--;
@@ -1540,6 +1602,21 @@
 		}
 		psf_prev = psf;
 	}
+
+empty_source:
+	if (!stotal) {
+		if (type == MLD2_ALLOW_NEW_SOURCES ||
+		    type == MLD2_BLOCK_OLD_SOURCES)
+			return skb;
+		if (pmc->mca_crcount || isquery) {
+			/* make sure we have room for group header */
+			if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)) {
+				mld_sendpack(skb);
+				skb = NULL; /* add_grhead will get a new one */
+			}
+			skb = add_grhead(skb, pmc, type, &pgr);
+		}
+	}
 	if (pgr)
 		pgr->grec_nsrcs = htons(scount);
 
@@ -1621,11 +1698,11 @@
 			skb = add_grec(skb, pmc, dtype, 1, 1);
 		}
 		if (pmc->mca_crcount) {
-			pmc->mca_crcount--;
 			if (pmc->mca_sfmode == MCAST_EXCLUDE) {
 				type = MLD2_CHANGE_TO_INCLUDE;
 				skb = add_grec(skb, pmc, type, 1, 0);
 			}
+			pmc->mca_crcount--;
 			if (pmc->mca_crcount == 0) {
 				mld_clear_zeros(&pmc->mca_tomb);
 				mld_clear_zeros(&pmc->mca_sources);
@@ -1659,12 +1736,12 @@
 
 		/* filter mode changes */
 		if (pmc->mca_crcount) {
-			pmc->mca_crcount--;
 			if (pmc->mca_sfmode == MCAST_EXCLUDE)
 				type = MLD2_CHANGE_TO_EXCLUDE;
 			else
 				type = MLD2_CHANGE_TO_INCLUDE;
 			skb = add_grec(skb, pmc, type, 0, 0);
+			pmc->mca_crcount--;
 		}
 		spin_unlock_bh(&pmc->mca_lock);
 	}
@@ -2023,6 +2100,9 @@
 {
 	int err;
 
+	/* callers have the socket lock and a write lock on ipv6_sk_mc_lock,
+	 * so no other readers or writers of iml or its sflist
+	 */
 	if (iml->sflist == 0) {
 		/* any-source empty exclude case */
 		return ip6_mc_del_src(idev, &iml->addr, iml->sfmode, 0, NULL, 0);
