Browse Source

Merge branch 'master' into upstream

Jeff Garzik 19 years ago
parent
commit
1a2e8a6f8e
51 changed files with 450 additions and 226 deletions
  1. 5 0
      Documentation/filesystems/sysfs.txt
  2. 1 1
      Makefile
  3. 1 1
      arch/arm/Makefile
  4. 1 1
      arch/arm/kernel/Makefile
  5. 3 1
      arch/arm/kernel/head-nommu.S
  6. 1 1
      arch/arm/vfp/vfpdouble.c
  7. 1 1
      arch/arm/vfp/vfpmodule.c
  8. 1 1
      arch/arm/vfp/vfpsingle.c
  9. 1 1
      arch/i386/kernel/cpu/intel_cacheinfo.c
  10. 1 0
      arch/ia64/kernel/entry.S
  11. 1 1
      arch/ia64/kernel/palinfo.c
  12. 1 1
      arch/ia64/kernel/salinfo.c
  13. 1 1
      arch/ia64/kernel/topology.c
  14. 2 62
      arch/mips/kernel/linux32.c
  15. 2 2
      arch/powerpc/kernel/sysfs.c
  16. 1 0
      arch/powerpc/kernel/systbl.S
  17. 1 0
      arch/powerpc/platforms/cell/spu_callbacks.c
  18. 1 1
      arch/s390/appldata/appldata_base.c
  19. 1 1
      arch/x86_64/kernel/mce.c
  20. 1 1
      arch/x86_64/kernel/mce_amd.c
  21. 1 1
      block/ll_rw_blk.c
  22. 1 1
      drivers/base/topology.c
  23. 14 0
      drivers/char/mem.c
  24. 1 1
      drivers/cpufreq/cpufreq.c
  25. 4 6
      drivers/mmc/pxamci.c
  26. 1 0
      drivers/usb/gadget/inode.c
  27. 4 0
      fs/compat.c
  28. 14 4
      fs/ext3/ioctl.c
  29. 1 1
      fs/ext3/resize.c
  30. 20 15
      fs/fuse/dev.c
  31. 9 3
      fs/fuse/fuse_i.h
  32. 18 22
      fs/fuse/inode.c
  33. 282 73
      fs/splice.c
  34. 2 1
      include/asm-i386/unistd.h
  35. 2 1
      include/asm-ia64/unistd.h
  36. 2 1
      include/asm-powerpc/unistd.h
  37. 3 1
      include/asm-x86_64/unistd.h
  38. 17 0
      include/linux/pipe_fs_i.h
  39. 3 0
      include/linux/syscalls.h
  40. 2 2
      kernel/hrtimer.c
  41. 1 1
      kernel/profile.c
  42. 2 2
      kernel/rcupdate.c
  43. 1 1
      kernel/sched.c
  44. 2 2
      kernel/softirq.c
  45. 2 2
      kernel/softlockup.c
  46. 2 2
      kernel/timer.c
  47. 1 1
      kernel/workqueue.c
  48. 1 1
      mm/page_alloc.c
  49. 1 1
      mm/slab.c
  50. 1 1
      mm/vmscan.c
  51. 7 1
      net/bridge/br_forward.c

+ 5 - 0
Documentation/filesystems/sysfs.txt

@@ -246,6 +246,7 @@ class/
 devices/
 devices/
 firmware/
 firmware/
 net/
 net/
+fs/
 
 
 devices/ contains a filesystem representation of the device tree. It maps
 devices/ contains a filesystem representation of the device tree. It maps
 directly to the internal kernel device tree, which is a hierarchy of
 directly to the internal kernel device tree, which is a hierarchy of
@@ -264,6 +265,10 @@ drivers/ contains a directory for each device driver that is loaded
 for devices on that particular bus (this assumes that drivers do not
 for devices on that particular bus (this assumes that drivers do not
 span multiple bus types).
 span multiple bus types).
 
 
+fs/ contains a directory for some filesystems.  Currently each
+filesystem wanting to export attributes must create its own hierarchy
+below fs/ (see ./fuse.txt for an example).
+
 
 
 More information can driver-model specific features can be found in
 More information can driver-model specific features can be found in
 Documentation/driver-model/. 
 Documentation/driver-model/. 

+ 1 - 1
Makefile

@@ -1,7 +1,7 @@
 VERSION = 2
 VERSION = 2
 PATCHLEVEL = 6
 PATCHLEVEL = 6
 SUBLEVEL = 17
 SUBLEVEL = 17
-EXTRAVERSION =-rc2
+EXTRAVERSION =-rc3
 NAME=Sliding Snow Leopard
 NAME=Sliding Snow Leopard
 
 
 # *DOCUMENTATION*
 # *DOCUMENTATION*

+ 1 - 1
arch/arm/Makefile

@@ -66,7 +66,7 @@ tune-$(CONFIG_CPU_XSC3)		:=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -
 tune-$(CONFIG_CPU_V6)		:=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
 tune-$(CONFIG_CPU_V6)		:=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
 
 
 ifeq ($(CONFIG_AEABI),y)
 ifeq ($(CONFIG_AEABI),y)
-CFLAGS_ABI	:=-mabi=aapcs -mno-thumb-interwork
+CFLAGS_ABI	:=-mabi=aapcs-linux -mno-thumb-interwork
 else
 else
 CFLAGS_ABI	:=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) $(call cc-option,-mno-thumb-interwork,)
 CFLAGS_ABI	:=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) $(call cc-option,-mno-thumb-interwork,)
 endif
 endif

+ 1 - 1
arch/arm/kernel/Makefile

@@ -29,7 +29,7 @@ ifneq ($(CONFIG_ARCH_EBSA110),y)
   obj-y		+= io.o
   obj-y		+= io.o
 endif
 endif
 
 
-head-y			:= head.o
+head-y			:= head$(MMUEXT).o
 obj-$(CONFIG_DEBUG_LL)	+= debug.o
 obj-$(CONFIG_DEBUG_LL)	+= debug.o
 
 
 extra-y := $(head-y) init_task.o vmlinux.lds
 extra-y := $(head-y) init_task.o vmlinux.lds

+ 3 - 1
arch/arm/kernel/head-nommu.S

@@ -20,10 +20,11 @@
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
 #include <asm/procinfo.h>
 #include <asm/procinfo.h>
 #include <asm/ptrace.h>
 #include <asm/ptrace.h>
-#include <asm/constants.h>
+#include <asm/thread_info.h>
 #include <asm/system.h>
 #include <asm/system.h>
 
 
 #define PROCINFO_INITFUNC       12
 #define PROCINFO_INITFUNC       12
+#define MACHINFO_TYPE		0
 
 
 /*
 /*
  * Kernel startup entry point.
  * Kernel startup entry point.
@@ -79,5 +80,6 @@ __after_proc_init:
 
 
 	mov	pc, r13				@ clear the BSS and jump
 	mov	pc, r13				@ clear the BSS and jump
 						@ to start_kernel
 						@ to start_kernel
+	.ltorg
 
 
 #include "head-common.S"
 #include "head-common.S"

+ 1 - 1
arch/arm/vfp/vfpdouble.c

@@ -197,7 +197,7 @@ u32 vfp_double_normaliseround(int dd, struct vfp_double *vd, u32 fpscr, u32 exce
 			 dd, d, exceptions);
 			 dd, d, exceptions);
 		vfp_put_double(dd, d);
 		vfp_put_double(dd, d);
 	}
 	}
-	return exceptions & ~VFP_NAN_FLAG;
+	return exceptions;
 }
 }
 
 
 /*
 /*

+ 1 - 1
arch/arm/vfp/vfpmodule.c

@@ -180,7 +180,7 @@ static u32 vfp_emulate_instruction(u32 inst, u32 fpscr, struct pt_regs *regs)
 		 * emulate it.
 		 * emulate it.
 		 */
 		 */
 	}
 	}
-	return exceptions;
+	return exceptions & ~VFP_NAN_FLAG;
 }
 }
 
 
 /*
 /*

+ 1 - 1
arch/arm/vfp/vfpsingle.c

@@ -203,7 +203,7 @@ u32 vfp_single_normaliseround(int sd, struct vfp_single *vs, u32 fpscr, u32 exce
 		vfp_put_float(sd, d);
 		vfp_put_float(sd, d);
 	}
 	}
 
 
-	return exceptions & ~VFP_NAN_FLAG;
+	return exceptions;
 }
 }
 
 
 /*
 /*

+ 1 - 1
arch/i386/kernel/cpu/intel_cacheinfo.c

@@ -642,7 +642,7 @@ static void __cpuexit cache_remove_dev(struct sys_device * sys_dev)
 	return;
 	return;
 }
 }
 
 
-static int __cpuinit cacheinfo_cpu_callback(struct notifier_block *nfb,
+static int cacheinfo_cpu_callback(struct notifier_block *nfb,
 					unsigned long action, void *hcpu)
 					unsigned long action, void *hcpu)
 {
 {
 	unsigned int cpu = (unsigned long)hcpu;
 	unsigned int cpu = (unsigned long)hcpu;

+ 1 - 0
arch/ia64/kernel/entry.S

@@ -1610,5 +1610,6 @@ sys_call_table:
 	data8 sys_get_robust_list
 	data8 sys_get_robust_list
 	data8 sys_sync_file_range		// 1300
 	data8 sys_sync_file_range		// 1300
 	data8 sys_tee
 	data8 sys_tee
+	data8 sys_vmsplice
 
 
 	.org sys_call_table + 8*NR_syscalls	// guard against failures to increase NR_syscalls
 	.org sys_call_table + 8*NR_syscalls	// guard against failures to increase NR_syscalls

+ 1 - 1
arch/ia64/kernel/palinfo.c

@@ -959,7 +959,7 @@ remove_palinfo_proc_entries(unsigned int hcpu)
 	}
 	}
 }
 }
 
 
-static int __devinit palinfo_cpu_callback(struct notifier_block *nfb,
+static int palinfo_cpu_callback(struct notifier_block *nfb,
 								unsigned long action,
 								unsigned long action,
 								void *hcpu)
 								void *hcpu)
 {
 {

+ 1 - 1
arch/ia64/kernel/salinfo.c

@@ -572,7 +572,7 @@ static struct file_operations salinfo_data_fops = {
 };
 };
 
 
 #ifdef	CONFIG_HOTPLUG_CPU
 #ifdef	CONFIG_HOTPLUG_CPU
-static int __devinit
+static int
 salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
 salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
 {
 {
 	unsigned int i, cpu = (unsigned long)hcpu;
 	unsigned int i, cpu = (unsigned long)hcpu;

+ 1 - 1
arch/ia64/kernel/topology.c

@@ -429,7 +429,7 @@ static int __cpuinit cache_remove_dev(struct sys_device * sys_dev)
  * When a cpu is hot-plugged, do a check and initiate
  * When a cpu is hot-plugged, do a check and initiate
  * cache kobject if necessary
  * cache kobject if necessary
  */
  */
-static int __cpuinit cache_cpu_callback(struct notifier_block *nfb,
+static int cache_cpu_callback(struct notifier_block *nfb,
 		unsigned long action, void *hcpu)
 		unsigned long action, void *hcpu)
 {
 {
 	unsigned int cpu = (unsigned long)hcpu;
 	unsigned int cpu = (unsigned long)hcpu;

+ 2 - 62
arch/mips/kernel/linux32.c

@@ -356,73 +356,13 @@ asmlinkage int sys32_llseek(unsigned int fd, unsigned int offset_high,
 asmlinkage ssize_t sys32_pread(unsigned int fd, char __user * buf,
 asmlinkage ssize_t sys32_pread(unsigned int fd, char __user * buf,
 			       size_t count, u32 unused, u64 a4, u64 a5)
 			       size_t count, u32 unused, u64 a4, u64 a5)
 {
 {
-	ssize_t ret;
-	struct file * file;
-	ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
-	loff_t pos;
-
-	ret = -EBADF;
-	file = fget(fd);
-	if (!file)
-		goto bad_file;
-	if (!(file->f_mode & FMODE_READ))
-		goto out;
-	pos = merge_64(a4, a5);
-	ret = rw_verify_area(READ, file, &pos, count);
-	if (ret < 0)
-		goto out;
-	ret = -EINVAL;
-	if (!file->f_op || !(read = file->f_op->read))
-		goto out;
-	if (pos < 0)
-		goto out;
-	ret = -ESPIPE;
-	if (!(file->f_mode & FMODE_PREAD))
-		goto out;
-	ret = read(file, buf, count, &pos);
-	if (ret > 0)
-		dnotify_parent(file->f_dentry, DN_ACCESS);
-out:
-	fput(file);
-bad_file:
-	return ret;
+	return sys_pread64(fd, buf, count, merge_64(a4, a5));
 }
 }
 
 
 asmlinkage ssize_t sys32_pwrite(unsigned int fd, const char __user * buf,
 asmlinkage ssize_t sys32_pwrite(unsigned int fd, const char __user * buf,
 			        size_t count, u32 unused, u64 a4, u64 a5)
 			        size_t count, u32 unused, u64 a4, u64 a5)
 {
 {
-	ssize_t ret;
-	struct file * file;
-	ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
-	loff_t pos;
-
-	ret = -EBADF;
-	file = fget(fd);
-	if (!file)
-		goto bad_file;
-	if (!(file->f_mode & FMODE_WRITE))
-		goto out;
-	pos = merge_64(a4, a5);
-	ret = rw_verify_area(WRITE, file, &pos, count);
-	if (ret < 0)
-		goto out;
-	ret = -EINVAL;
-	if (!file->f_op || !(write = file->f_op->write))
-		goto out;
-	if (pos < 0)
-		goto out;
-
-	ret = -ESPIPE;
-	if (!(file->f_mode & FMODE_PWRITE))
-		goto out;
-
-	ret = write(file, buf, count, &pos);
-	if (ret > 0)
-		dnotify_parent(file->f_dentry, DN_MODIFY);
-out:
-	fput(file);
-bad_file:
-	return ret;
+	return sys_pwrite64(fd, buf, count, merge_64(a4, a5));
 }
 }
 
 
 asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid,
 asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid,

+ 2 - 2
arch/powerpc/kernel/sysfs.c

@@ -279,7 +279,7 @@ static void unregister_cpu_online(unsigned int cpu)
 }
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 #endif /* CONFIG_HOTPLUG_CPU */
 
 
-static int __devinit sysfs_cpu_notify(struct notifier_block *self,
+static int sysfs_cpu_notify(struct notifier_block *self,
 				      unsigned long action, void *hcpu)
 				      unsigned long action, void *hcpu)
 {
 {
 	unsigned int cpu = (unsigned int)(long)hcpu;
 	unsigned int cpu = (unsigned int)(long)hcpu;
@@ -297,7 +297,7 @@ static int __devinit sysfs_cpu_notify(struct notifier_block *self,
 	return NOTIFY_OK;
 	return NOTIFY_OK;
 }
 }
 
 
-static struct notifier_block __devinitdata sysfs_cpu_nb = {
+static struct notifier_block sysfs_cpu_nb = {
 	.notifier_call	= sysfs_cpu_notify,
 	.notifier_call	= sysfs_cpu_notify,
 };
 };
 
 

+ 1 - 0
arch/powerpc/kernel/systbl.S

@@ -324,6 +324,7 @@ COMPAT_SYS(ppoll)
 SYSCALL(unshare)
 SYSCALL(unshare)
 SYSCALL(splice)
 SYSCALL(splice)
 SYSCALL(tee)
 SYSCALL(tee)
+SYSCALL(vmsplice)
 
 
 /*
 /*
  * please add new calls to arch/powerpc/platforms/cell/spu_callbacks.c
  * please add new calls to arch/powerpc/platforms/cell/spu_callbacks.c

+ 1 - 0
arch/powerpc/platforms/cell/spu_callbacks.c

@@ -318,6 +318,7 @@ void *spu_syscall_table[] = {
 	[__NR_unshare]			sys_unshare,
 	[__NR_unshare]			sys_unshare,
 	[__NR_splice]			sys_splice,
 	[__NR_splice]			sys_splice,
 	[__NR_tee]			sys_tee,
 	[__NR_tee]			sys_tee,
+	[__NR_vmsplice]			sys_vmsplice,
 };
 };
 
 
 long spu_sys_callback(struct spu_syscall_block *s)
 long spu_sys_callback(struct spu_syscall_block *s)

+ 1 - 1
arch/s390/appldata/appldata_base.c

@@ -652,7 +652,7 @@ appldata_cpu_notify(struct notifier_block *self,
 	return NOTIFY_OK;
 	return NOTIFY_OK;
 }
 }
 
 
-static struct notifier_block __devinitdata appldata_nb = {
+static struct notifier_block appldata_nb = {
 	.notifier_call = appldata_cpu_notify,
 	.notifier_call = appldata_cpu_notify,
 };
 };
 
 

+ 1 - 1
arch/x86_64/kernel/mce.c

@@ -629,7 +629,7 @@ static __cpuinit void mce_remove_device(unsigned int cpu)
 #endif
 #endif
 
 
 /* Get notified when a cpu comes on/off. Be hotplug friendly. */
 /* Get notified when a cpu comes on/off. Be hotplug friendly. */
-static __cpuinit int
+static int
 mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 {
 {
 	unsigned int cpu = (unsigned long)hcpu;
 	unsigned int cpu = (unsigned long)hcpu;

+ 1 - 1
arch/x86_64/kernel/mce_amd.c

@@ -482,7 +482,7 @@ static void threshold_remove_device(unsigned int cpu)
 #endif
 #endif
 
 
 /* get notified when a cpu comes on/off */
 /* get notified when a cpu comes on/off */
-static __cpuinit int threshold_cpu_callback(struct notifier_block *nfb,
+static int threshold_cpu_callback(struct notifier_block *nfb,
 					    unsigned long action, void *hcpu)
 					    unsigned long action, void *hcpu)
 {
 {
 	/* cpu was unsigned int to begin with */
 	/* cpu was unsigned int to begin with */

+ 1 - 1
block/ll_rw_blk.c

@@ -3385,7 +3385,7 @@ static int blk_cpu_notify(struct notifier_block *self, unsigned long action,
 }
 }
 
 
 
 
-static struct notifier_block __devinitdata blk_cpu_notifier = {
+static struct notifier_block blk_cpu_notifier = {
 	.notifier_call	= blk_cpu_notify,
 	.notifier_call	= blk_cpu_notify,
 };
 };
 
 

+ 1 - 1
drivers/base/topology.c

@@ -107,7 +107,7 @@ static int __cpuinit topology_remove_dev(struct sys_device * sys_dev)
 	return 0;
 	return 0;
 }
 }
 
 
-static int __cpuinit topology_cpu_callback(struct notifier_block *nfb,
+static int topology_cpu_callback(struct notifier_block *nfb,
 		unsigned long action, void *hcpu)
 		unsigned long action, void *hcpu)
 {
 {
 	unsigned int cpu = (unsigned long)hcpu;
 	unsigned int cpu = (unsigned long)hcpu;

+ 14 - 0
drivers/char/mem.c

@@ -27,6 +27,7 @@
 #include <linux/crash_dump.h>
 #include <linux/crash_dump.h>
 #include <linux/backing-dev.h>
 #include <linux/backing-dev.h>
 #include <linux/bootmem.h>
 #include <linux/bootmem.h>
+#include <linux/pipe_fs_i.h>
 
 
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/io.h>
@@ -578,6 +579,18 @@ static ssize_t write_null(struct file * file, const char __user * buf,
 	return count;
 	return count;
 }
 }
 
 
+static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf,
+			struct splice_desc *sd)
+{
+	return sd->len;
+}
+
+static ssize_t splice_write_null(struct pipe_inode_info *pipe,struct file *out,
+				 loff_t *ppos, size_t len, unsigned int flags)
+{
+	return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null);
+}
+
 #ifdef CONFIG_MMU
 #ifdef CONFIG_MMU
 /*
 /*
  * For fun, we are using the MMU for this.
  * For fun, we are using the MMU for this.
@@ -785,6 +798,7 @@ static struct file_operations null_fops = {
 	.llseek		= null_lseek,
 	.llseek		= null_lseek,
 	.read		= read_null,
 	.read		= read_null,
 	.write		= write_null,
 	.write		= write_null,
+	.splice_write	= splice_write_null,
 };
 };
 
 
 #if defined(CONFIG_ISA) || !defined(__mc68000__)
 #if defined(CONFIG_ISA) || !defined(__mc68000__)

+ 1 - 1
drivers/cpufreq/cpufreq.c

@@ -1497,7 +1497,7 @@ int cpufreq_update_policy(unsigned int cpu)
 }
 }
 EXPORT_SYMBOL(cpufreq_update_policy);
 EXPORT_SYMBOL(cpufreq_update_policy);
 
 
-static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
+static int cpufreq_cpu_callback(struct notifier_block *nfb,
 					unsigned long action, void *hcpu)
 					unsigned long action, void *hcpu)
 {
 {
 	unsigned int cpu = (unsigned long)hcpu;
 	unsigned int cpu = (unsigned long)hcpu;

+ 4 - 6
drivers/mmc/pxamci.c

@@ -65,11 +65,6 @@ struct pxamci_host {
 	unsigned int		dma_dir;
 	unsigned int		dma_dir;
 };
 };
 
 
-static inline unsigned int ns_to_clocks(unsigned int ns)
-{
-	return (ns * (CLOCKRATE / 1000000) + 999) / 1000;
-}
-
 static void pxamci_stop_clock(struct pxamci_host *host)
 static void pxamci_stop_clock(struct pxamci_host *host)
 {
 {
 	if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
 	if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
@@ -113,6 +108,7 @@ static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
 static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
 static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
 {
 {
 	unsigned int nob = data->blocks;
 	unsigned int nob = data->blocks;
+	unsigned long long clks;
 	unsigned int timeout;
 	unsigned int timeout;
 	u32 dcmd;
 	u32 dcmd;
 	int i;
 	int i;
@@ -125,7 +121,9 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
 	writel(nob, host->base + MMC_NOB);
 	writel(nob, host->base + MMC_NOB);
 	writel(1 << data->blksz_bits, host->base + MMC_BLKLEN);
 	writel(1 << data->blksz_bits, host->base + MMC_BLKLEN);
 
 
-	timeout = ns_to_clocks(data->timeout_ns) + data->timeout_clks;
+	clks = (unsigned long long)data->timeout_ns * CLOCKRATE;
+	do_div(clks, 1000000000UL);
+	timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
 	writel((timeout + 255) / 256, host->base + MMC_RDTO);
 	writel((timeout + 255) / 256, host->base + MMC_RDTO);
 
 
 	if (data->flags & MMC_DATA_READ) {
 	if (data->flags & MMC_DATA_READ) {

+ 1 - 0
drivers/usb/gadget/inode.c

@@ -1614,6 +1614,7 @@ static int activate_ep_files (struct dev_data *dev)
 				data, &ep_config_operations,
 				data, &ep_config_operations,
 				&data->dentry);
 				&data->dentry);
 		if (!data->inode) {
 		if (!data->inode) {
+			usb_ep_free_request(ep, data->req);
 			kfree (data);
 			kfree (data);
 			goto enomem;
 			goto enomem;
 		}
 		}

+ 4 - 0
fs/compat.c

@@ -1217,6 +1217,10 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
 
 
+	ret = security_file_permission(file, type == READ ? MAY_READ:MAY_WRITE);
+	if (ret)
+		goto out;
+
 	fnv = NULL;
 	fnv = NULL;
 	if (type == READ) {
 	if (type == READ) {
 		fn = file->f_op->read;
 		fn = file->f_op->read;

+ 14 - 4
fs/ext3/ioctl.c

@@ -48,6 +48,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
 		if (!S_ISDIR(inode->i_mode))
 		if (!S_ISDIR(inode->i_mode))
 			flags &= ~EXT3_DIRSYNC_FL;
 			flags &= ~EXT3_DIRSYNC_FL;
 
 
+		mutex_lock(&inode->i_mutex);
 		oldflags = ei->i_flags;
 		oldflags = ei->i_flags;
 
 
 		/* The JOURNAL_DATA flag is modifiable only by root */
 		/* The JOURNAL_DATA flag is modifiable only by root */
@@ -60,8 +61,10 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
 		 * This test looks nicer. Thanks to Pauline Middelink
 		 * This test looks nicer. Thanks to Pauline Middelink
 		 */
 		 */
 		if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) {
 		if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) {
-			if (!capable(CAP_LINUX_IMMUTABLE))
+			if (!capable(CAP_LINUX_IMMUTABLE)) {
+				mutex_unlock(&inode->i_mutex);
 				return -EPERM;
 				return -EPERM;
+			}
 		}
 		}
 
 
 		/*
 		/*
@@ -69,14 +72,18 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
 		 * the relevant capability.
 		 * the relevant capability.
 		 */
 		 */
 		if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) {
 		if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) {
-			if (!capable(CAP_SYS_RESOURCE))
+			if (!capable(CAP_SYS_RESOURCE)) {
+				mutex_unlock(&inode->i_mutex);
 				return -EPERM;
 				return -EPERM;
+			}
 		}
 		}
 
 
 
 
 		handle = ext3_journal_start(inode, 1);
 		handle = ext3_journal_start(inode, 1);
-		if (IS_ERR(handle))
+		if (IS_ERR(handle)) {
+			mutex_unlock(&inode->i_mutex);
 			return PTR_ERR(handle);
 			return PTR_ERR(handle);
+		}
 		if (IS_SYNC(inode))
 		if (IS_SYNC(inode))
 			handle->h_sync = 1;
 			handle->h_sync = 1;
 		err = ext3_reserve_inode_write(handle, inode, &iloc);
 		err = ext3_reserve_inode_write(handle, inode, &iloc);
@@ -93,11 +100,14 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
 		err = ext3_mark_iloc_dirty(handle, inode, &iloc);
 		err = ext3_mark_iloc_dirty(handle, inode, &iloc);
 flags_err:
 flags_err:
 		ext3_journal_stop(handle);
 		ext3_journal_stop(handle);
-		if (err)
+		if (err) {
+			mutex_unlock(&inode->i_mutex);
 			return err;
 			return err;
+		}
 
 
 		if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL))
 		if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL))
 			err = ext3_change_inode_journal_flag(inode, jflag);
 			err = ext3_change_inode_journal_flag(inode, jflag);
+		mutex_unlock(&inode->i_mutex);
 		return err;
 		return err;
 	}
 	}
 	case EXT3_IOC_GETVERSION:
 	case EXT3_IOC_GETVERSION:

+ 1 - 1
fs/ext3/resize.c

@@ -213,7 +213,7 @@ static int setup_new_group_blocks(struct super_block *sb,
 			goto exit_bh;
 			goto exit_bh;
 		}
 		}
 		lock_buffer(bh);
 		lock_buffer(bh);
-		memcpy(gdb->b_data, sbi->s_group_desc[i], bh->b_size);
+		memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, bh->b_size);
 		set_buffer_uptodate(gdb);
 		set_buffer_uptodate(gdb);
 		unlock_buffer(bh);
 		unlock_buffer(bh);
 		ext3_journal_dirty_metadata(handle, gdb);
 		ext3_journal_dirty_metadata(handle, gdb);

+ 20 - 15
fs/fuse/dev.c

@@ -128,14 +128,24 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
 	}
 	}
 }
 }
 
 
-void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req)
+/*
+ * Called with sbput_sem held for read (request_end) or write
+ * (fuse_put_super).  By the time fuse_put_super() is finished, all
+ * inodes belonging to background requests must be released, so the
+ * iputs have to be done within the locked region.
+ */
+void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req)
 {
 {
-	list_del_init(&req->bg_entry);
+	iput(req->inode);
+	iput(req->inode2);
+	spin_lock(&fc->lock);
+	list_del(&req->bg_entry);
 	if (fc->num_background == FUSE_MAX_BACKGROUND) {
 	if (fc->num_background == FUSE_MAX_BACKGROUND) {
 		fc->blocked = 0;
 		fc->blocked = 0;
 		wake_up_all(&fc->blocked_waitq);
 		wake_up_all(&fc->blocked_waitq);
 	}
 	}
 	fc->num_background--;
 	fc->num_background--;
+	spin_unlock(&fc->lock);
 }
 }
 
 
 /*
 /*
@@ -165,27 +175,22 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
 		wake_up(&req->waitq);
 		wake_up(&req->waitq);
 		fuse_put_request(fc, req);
 		fuse_put_request(fc, req);
 	} else {
 	} else {
-		struct inode *inode = req->inode;
-		struct inode *inode2 = req->inode2;
-		struct file *file = req->file;
 		void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
 		void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
 		req->end = NULL;
 		req->end = NULL;
-		req->inode = NULL;
-		req->inode2 = NULL;
-		req->file = NULL;
-		if (!list_empty(&req->bg_entry))
-			fuse_remove_background(fc, req);
 		spin_unlock(&fc->lock);
 		spin_unlock(&fc->lock);
+		down_read(&fc->sbput_sem);
+		if (fc->mounted)
+			fuse_release_background(fc, req);
+		up_read(&fc->sbput_sem);
+
+		/* fput must go outside sbput_sem, otherwise it can deadlock */
+		if (req->file)
+			fput(req->file);
 
 
 		if (end)
 		if (end)
 			end(fc, req);
 			end(fc, req);
 		else
 		else
 			fuse_put_request(fc, req);
 			fuse_put_request(fc, req);
-
-		if (file)
-			fput(file);
-		iput(inode);
-		iput(inode2);
 	}
 	}
 }
 }
 
 

+ 9 - 3
fs/fuse/fuse_i.h

@@ -258,9 +258,15 @@ struct fuse_conn {
 	/** waitq for blocked connection */
 	/** waitq for blocked connection */
 	wait_queue_head_t blocked_waitq;
 	wait_queue_head_t blocked_waitq;
 
 
+	/** RW semaphore for exclusion with fuse_put_super() */
+	struct rw_semaphore sbput_sem;
+
 	/** The next unique request id */
 	/** The next unique request id */
 	u64 reqctr;
 	u64 reqctr;
 
 
+	/** Mount is active */
+	unsigned mounted;
+
 	/** Connection established, cleared on umount, connection
 	/** Connection established, cleared on umount, connection
 	    abort and device release */
 	    abort and device release */
 	unsigned connected;
 	unsigned connected;
@@ -471,11 +477,11 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req);
 void request_send_background(struct fuse_conn *fc, struct fuse_req *req);
 void request_send_background(struct fuse_conn *fc, struct fuse_req *req);
 
 
 /**
 /**
- * Remove request from the the background list
+ * Release inodes and file associated with background request
  */
  */
-void fuse_remove_background(struct fuse_conn *fc, struct fuse_req *req);
+void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req);
 
 
-/** Abort all requests */
+/* Abort all requests */
 void fuse_abort_conn(struct fuse_conn *fc);
 void fuse_abort_conn(struct fuse_conn *fc);
 
 
 /**
 /**

+ 18 - 22
fs/fuse/inode.c

@@ -204,26 +204,17 @@ static void fuse_put_super(struct super_block *sb)
 {
 {
 	struct fuse_conn *fc = get_fuse_conn_super(sb);
 	struct fuse_conn *fc = get_fuse_conn_super(sb);
 
 
+	down_write(&fc->sbput_sem);
+	while (!list_empty(&fc->background))
+		fuse_release_background(fc,
+					list_entry(fc->background.next,
+						   struct fuse_req, bg_entry));
+
 	spin_lock(&fc->lock);
 	spin_lock(&fc->lock);
+	fc->mounted = 0;
 	fc->connected = 0;
 	fc->connected = 0;
-	while (!list_empty(&fc->background)) {
-		struct fuse_req *req = list_entry(fc->background.next,
-						  struct fuse_req, bg_entry);
-		struct inode *inode = req->inode;
-		struct inode *inode2 = req->inode2;
-
-		/* File would hold a reference to vfsmount */
-		BUG_ON(req->file);
-		req->inode = NULL;
-		req->inode2 = NULL;
-		fuse_remove_background(fc, req);
-
-		spin_unlock(&fc->lock);
-		iput(inode);
-		iput(inode2);
-		spin_lock(&fc->lock);
-	}
 	spin_unlock(&fc->lock);
 	spin_unlock(&fc->lock);
+	up_write(&fc->sbput_sem);
 	/* Flush all readers on this fs */
 	/* Flush all readers on this fs */
 	kill_fasync(&fc->fasync, SIGIO, POLL_IN);
 	kill_fasync(&fc->fasync, SIGIO, POLL_IN);
 	wake_up_all(&fc->waitq);
 	wake_up_all(&fc->waitq);
@@ -395,6 +386,7 @@ static struct fuse_conn *new_conn(void)
 		INIT_LIST_HEAD(&fc->processing);
 		INIT_LIST_HEAD(&fc->processing);
 		INIT_LIST_HEAD(&fc->io);
 		INIT_LIST_HEAD(&fc->io);
 		INIT_LIST_HEAD(&fc->background);
 		INIT_LIST_HEAD(&fc->background);
+		init_rwsem(&fc->sbput_sem);
 		kobj_set_kset_s(fc, connections_subsys);
 		kobj_set_kset_s(fc, connections_subsys);
 		kobject_init(&fc->kobj);
 		kobject_init(&fc->kobj);
 		atomic_set(&fc->num_waiting, 0);
 		atomic_set(&fc->num_waiting, 0);
@@ -508,11 +500,6 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 	if (file->f_op != &fuse_dev_operations)
 	if (file->f_op != &fuse_dev_operations)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	/* Setting file->private_data can't race with other mount()
-	   instances, since BKL is held for ->get_sb() */
-	if (file->private_data)
-		return -EINVAL;
-
 	fc = new_conn();
 	fc = new_conn();
 	if (!fc)
 	if (!fc)
 		return -ENOMEM;
 		return -ENOMEM;
@@ -548,7 +535,14 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 	if (err)
 	if (err)
 		goto err_free_req;
 		goto err_free_req;
 
 
+	/* Setting file->private_data can't race with other mount()
+	   instances, since BKL is held for ->get_sb() */
+	err = -EINVAL;
+	if (file->private_data)
+		goto err_kobject_del;
+
 	sb->s_root = root_dentry;
 	sb->s_root = root_dentry;
+	fc->mounted = 1;
 	fc->connected = 1;
 	fc->connected = 1;
 	kobject_get(&fc->kobj);
 	kobject_get(&fc->kobj);
 	file->private_data = fc;
 	file->private_data = fc;
@@ -563,6 +557,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 
 
 	return 0;
 	return 0;
 
 
+ err_kobject_del:
+	kobject_del(&fc->kobj);
  err_free_req:
  err_free_req:
 	fuse_request_free(init_req);
 	fuse_request_free(init_req);
  err_put_root:
  err_put_root:

+ 282 - 73
fs/splice.c

@@ -27,15 +27,22 @@
 #include <linux/buffer_head.h>
 #include <linux/buffer_head.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/syscalls.h>
 #include <linux/syscalls.h>
+#include <linux/uio.h>
+
+struct partial_page {
+	unsigned int offset;
+	unsigned int len;
+};
 
 
 /*
 /*
- * Passed to the actors
+ * Passed to splice_to_pipe
  */
  */
-struct splice_desc {
-	unsigned int len, total_len;	/* current and remaining length */
+struct splice_pipe_desc {
+	struct page **pages;		/* page map */
+	struct partial_page *partial;	/* pages[] may not be contig */
+	int nr_pages;			/* number of pages in map */
 	unsigned int flags;		/* splice flags */
 	unsigned int flags;		/* splice flags */
-	struct file *file;		/* file to read/write */
-	loff_t pos;			/* file position */
+	struct pipe_buf_operations *ops;/* ops associated with output pipe */
 };
 };
 
 
 /*
 /*
@@ -128,6 +135,19 @@ static void page_cache_pipe_buf_unmap(struct pipe_inode_info *info,
 	kunmap(buf->page);
 	kunmap(buf->page);
 }
 }
 
 
+static void *user_page_pipe_buf_map(struct file *file,
+				    struct pipe_inode_info *pipe,
+				    struct pipe_buffer *buf)
+{
+	return kmap(buf->page);
+}
+
+static void user_page_pipe_buf_unmap(struct pipe_inode_info *pipe,
+				     struct pipe_buffer *buf)
+{
+	kunmap(buf->page);
+}
+
 static void page_cache_pipe_buf_get(struct pipe_inode_info *info,
 static void page_cache_pipe_buf_get(struct pipe_inode_info *info,
 				    struct pipe_buffer *buf)
 				    struct pipe_buffer *buf)
 {
 {
@@ -143,19 +163,33 @@ static struct pipe_buf_operations page_cache_pipe_buf_ops = {
 	.get = page_cache_pipe_buf_get,
 	.get = page_cache_pipe_buf_get,
 };
 };
 
 
+static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe,
+				    struct pipe_buffer *buf)
+{
+	return 1;
+}
+
+static struct pipe_buf_operations user_page_pipe_buf_ops = {
+	.can_merge = 0,
+	.map = user_page_pipe_buf_map,
+	.unmap = user_page_pipe_buf_unmap,
+	.release = page_cache_pipe_buf_release,
+	.steal = user_page_pipe_buf_steal,
+	.get = page_cache_pipe_buf_get,
+};
+
 /*
 /*
  * Pipe output worker. This sets up our pipe format with the page cache
  * Pipe output worker. This sets up our pipe format with the page cache
  * pipe buffer operations. Otherwise very similar to the regular pipe_writev().
  * pipe buffer operations. Otherwise very similar to the regular pipe_writev().
  */
  */
-static ssize_t move_to_pipe(struct pipe_inode_info *pipe, struct page **pages,
-			    int nr_pages, unsigned long len,
-			    unsigned int offset, unsigned int flags)
+static ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
+			      struct splice_pipe_desc *spd)
 {
 {
-	int ret, do_wakeup, i;
+	int ret, do_wakeup, page_nr;
 
 
 	ret = 0;
 	ret = 0;
 	do_wakeup = 0;
 	do_wakeup = 0;
-	i = 0;
+	page_nr = 0;
 
 
 	if (pipe->inode)
 	if (pipe->inode)
 		mutex_lock(&pipe->inode->i_mutex);
 		mutex_lock(&pipe->inode->i_mutex);
@@ -171,27 +205,19 @@ static ssize_t move_to_pipe(struct pipe_inode_info *pipe, struct page **pages,
 		if (pipe->nrbufs < PIPE_BUFFERS) {
 		if (pipe->nrbufs < PIPE_BUFFERS) {
 			int newbuf = (pipe->curbuf + pipe->nrbufs) & (PIPE_BUFFERS - 1);
 			int newbuf = (pipe->curbuf + pipe->nrbufs) & (PIPE_BUFFERS - 1);
 			struct pipe_buffer *buf = pipe->bufs + newbuf;
 			struct pipe_buffer *buf = pipe->bufs + newbuf;
-			struct page *page = pages[i++];
-			unsigned long this_len;
 
 
-			this_len = PAGE_CACHE_SIZE - offset;
-			if (this_len > len)
-				this_len = len;
-
-			buf->page = page;
-			buf->offset = offset;
-			buf->len = this_len;
-			buf->ops = &page_cache_pipe_buf_ops;
+			buf->page = spd->pages[page_nr];
+			buf->offset = spd->partial[page_nr].offset;
+			buf->len = spd->partial[page_nr].len;
+			buf->ops = spd->ops;
 			pipe->nrbufs++;
 			pipe->nrbufs++;
+			page_nr++;
+			ret += buf->len;
+
 			if (pipe->inode)
 			if (pipe->inode)
 				do_wakeup = 1;
 				do_wakeup = 1;
 
 
-			ret += this_len;
-			len -= this_len;
-			offset = 0;
-			if (!--nr_pages)
-				break;
-			if (!len)
+			if (!--spd->nr_pages)
 				break;
 				break;
 			if (pipe->nrbufs < PIPE_BUFFERS)
 			if (pipe->nrbufs < PIPE_BUFFERS)
 				continue;
 				continue;
@@ -199,7 +225,7 @@ static ssize_t move_to_pipe(struct pipe_inode_info *pipe, struct page **pages,
 			break;
 			break;
 		}
 		}
 
 
-		if (flags & SPLICE_F_NONBLOCK) {
+		if (spd->flags & SPLICE_F_NONBLOCK) {
 			if (!ret)
 			if (!ret)
 				ret = -EAGAIN;
 				ret = -EAGAIN;
 			break;
 			break;
@@ -234,8 +260,8 @@ static ssize_t move_to_pipe(struct pipe_inode_info *pipe, struct page **pages,
 		kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
 		kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
 	}
 	}
 
 
-	while (i < nr_pages)
-		page_cache_release(pages[i++]);
+	while (page_nr < spd->nr_pages)
+		page_cache_release(spd->pages[page_nr++]);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -246,17 +272,24 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
 			   unsigned int flags)
 			   unsigned int flags)
 {
 {
 	struct address_space *mapping = in->f_mapping;
 	struct address_space *mapping = in->f_mapping;
-	unsigned int loff, offset, nr_pages;
+	unsigned int loff, nr_pages;
 	struct page *pages[PIPE_BUFFERS];
 	struct page *pages[PIPE_BUFFERS];
+	struct partial_page partial[PIPE_BUFFERS];
 	struct page *page;
 	struct page *page;
 	pgoff_t index, end_index;
 	pgoff_t index, end_index;
 	loff_t isize;
 	loff_t isize;
-	size_t bytes;
-	int i, error;
+	size_t total_len;
+	int error;
+	struct splice_pipe_desc spd = {
+		.pages = pages,
+		.partial = partial,
+		.flags = flags,
+		.ops = &page_cache_pipe_buf_ops,
+	};
 
 
 	index = *ppos >> PAGE_CACHE_SHIFT;
 	index = *ppos >> PAGE_CACHE_SHIFT;
-	loff = offset = *ppos & ~PAGE_CACHE_MASK;
-	nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	loff = *ppos & ~PAGE_CACHE_MASK;
+	nr_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 
 
 	if (nr_pages > PIPE_BUFFERS)
 	if (nr_pages > PIPE_BUFFERS)
 		nr_pages = PIPE_BUFFERS;
 		nr_pages = PIPE_BUFFERS;
@@ -266,15 +299,15 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
 	 * read-ahead if this is a non-zero offset (we are likely doing small
 	 * read-ahead if this is a non-zero offset (we are likely doing small
 	 * chunk splice and the page is already there) for a single page.
 	 * chunk splice and the page is already there) for a single page.
 	 */
 	 */
-	if (!offset || nr_pages > 1)
-		do_page_cache_readahead(mapping, in, index, nr_pages);
+	if (!loff || spd.nr_pages > 1)
+		do_page_cache_readahead(mapping, in, index, spd.nr_pages);
 
 
 	/*
 	/*
 	 * Now fill in the holes:
 	 * Now fill in the holes:
 	 */
 	 */
 	error = 0;
 	error = 0;
-	bytes = 0;
-	for (i = 0; i < nr_pages; i++, index++) {
+	total_len = 0;
+	for (spd.nr_pages = 0; spd.nr_pages < nr_pages; spd.nr_pages++, index++) {
 		unsigned int this_len;
 		unsigned int this_len;
 
 
 		if (!len)
 		if (!len)
@@ -283,7 +316,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
 		/*
 		/*
 		 * this_len is the max we'll use from this page
 		 * this_len is the max we'll use from this page
 		 */
 		 */
-		this_len = min(len, PAGE_CACHE_SIZE - loff);
+		this_len = min_t(unsigned long, len, PAGE_CACHE_SIZE - loff);
 find_page:
 find_page:
 		/*
 		/*
 		 * lookup the page for this index
 		 * lookup the page for this index
@@ -367,26 +400,29 @@ readpage:
 			 */
 			 */
 			if (end_index == index) {
 			if (end_index == index) {
 				loff = PAGE_CACHE_SIZE - (isize & ~PAGE_CACHE_MASK);
 				loff = PAGE_CACHE_SIZE - (isize & ~PAGE_CACHE_MASK);
-				if (bytes + loff > isize) {
+				if (total_len + loff > isize) {
 					page_cache_release(page);
 					page_cache_release(page);
 					break;
 					break;
 				}
 				}
 				/*
 				/*
 				 * force quit after adding this page
 				 * force quit after adding this page
 				 */
 				 */
-				nr_pages = i;
+				nr_pages = spd.nr_pages;
 				this_len = min(this_len, loff);
 				this_len = min(this_len, loff);
+				loff = 0;
 			}
 			}
 		}
 		}
 fill_it:
 fill_it:
-		pages[i] = page;
-		bytes += this_len;
+		pages[spd.nr_pages] = page;
+		partial[spd.nr_pages].offset = loff;
+		partial[spd.nr_pages].len = this_len;
 		len -= this_len;
 		len -= this_len;
+		total_len += this_len;
 		loff = 0;
 		loff = 0;
 	}
 	}
 
 
-	if (i)
-		return move_to_pipe(pipe, pages, i, bytes, offset, flags);
+	if (spd.nr_pages)
+		return splice_to_pipe(pipe, &spd);
 
 
 	return error;
 	return error;
 }
 }
@@ -439,14 +475,13 @@ EXPORT_SYMBOL(generic_file_splice_read);
 
 
 /*
 /*
  * Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos'
  * Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos'
- * using sendpage().
+ * using sendpage(). Return the number of bytes sent.
  */
  */
 static int pipe_to_sendpage(struct pipe_inode_info *info,
 static int pipe_to_sendpage(struct pipe_inode_info *info,
 			    struct pipe_buffer *buf, struct splice_desc *sd)
 			    struct pipe_buffer *buf, struct splice_desc *sd)
 {
 {
 	struct file *file = sd->file;
 	struct file *file = sd->file;
 	loff_t pos = sd->pos;
 	loff_t pos = sd->pos;
-	unsigned int offset;
 	ssize_t ret;
 	ssize_t ret;
 	void *ptr;
 	void *ptr;
 	int more;
 	int more;
@@ -461,16 +496,13 @@ static int pipe_to_sendpage(struct pipe_inode_info *info,
 	if (IS_ERR(ptr))
 	if (IS_ERR(ptr))
 		return PTR_ERR(ptr);
 		return PTR_ERR(ptr);
 
 
-	offset = pos & ~PAGE_CACHE_MASK;
 	more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len;
 	more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len;
 
 
-	ret = file->f_op->sendpage(file, buf->page, offset, sd->len, &pos,more);
+	ret = file->f_op->sendpage(file, buf->page, buf->offset, sd->len,
+				   &pos, more);
 
 
 	buf->ops->unmap(info, buf);
 	buf->ops->unmap(info, buf);
-	if (ret == sd->len)
-		return 0;
-
-	return -EIO;
+	return ret;
 }
 }
 
 
 /*
 /*
@@ -499,7 +531,7 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf,
 	struct file *file = sd->file;
 	struct file *file = sd->file;
 	struct address_space *mapping = file->f_mapping;
 	struct address_space *mapping = file->f_mapping;
 	gfp_t gfp_mask = mapping_gfp_mask(mapping);
 	gfp_t gfp_mask = mapping_gfp_mask(mapping);
-	unsigned int offset;
+	unsigned int offset, this_len;
 	struct page *page;
 	struct page *page;
 	pgoff_t index;
 	pgoff_t index;
 	char *src;
 	char *src;
@@ -515,6 +547,10 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf,
 	index = sd->pos >> PAGE_CACHE_SHIFT;
 	index = sd->pos >> PAGE_CACHE_SHIFT;
 	offset = sd->pos & ~PAGE_CACHE_MASK;
 	offset = sd->pos & ~PAGE_CACHE_MASK;
 
 
+	this_len = sd->len;
+	if (this_len + offset > PAGE_CACHE_SIZE)
+		this_len = PAGE_CACHE_SIZE - offset;
+
 	/*
 	/*
 	 * Reuse buf page, if SPLICE_F_MOVE is set.
 	 * Reuse buf page, if SPLICE_F_MOVE is set.
 	 */
 	 */
@@ -558,7 +594,7 @@ find_page:
 		 * the full page.
 		 * the full page.
 		 */
 		 */
 		if (!PageUptodate(page)) {
 		if (!PageUptodate(page)) {
-			if (sd->len < PAGE_CACHE_SIZE) {
+			if (this_len < PAGE_CACHE_SIZE) {
 				ret = mapping->a_ops->readpage(file, page);
 				ret = mapping->a_ops->readpage(file, page);
 				if (unlikely(ret))
 				if (unlikely(ret))
 					goto out;
 					goto out;
@@ -582,7 +618,7 @@ find_page:
 		}
 		}
 	}
 	}
 
 
-	ret = mapping->a_ops->prepare_write(file, page, 0, sd->len);
+	ret = mapping->a_ops->prepare_write(file, page, offset, offset+this_len);
 	if (ret == AOP_TRUNCATED_PAGE) {
 	if (ret == AOP_TRUNCATED_PAGE) {
 		page_cache_release(page);
 		page_cache_release(page);
 		goto find_page;
 		goto find_page;
@@ -592,18 +628,22 @@ find_page:
 	if (!(buf->flags & PIPE_BUF_FLAG_STOLEN)) {
 	if (!(buf->flags & PIPE_BUF_FLAG_STOLEN)) {
 		char *dst = kmap_atomic(page, KM_USER0);
 		char *dst = kmap_atomic(page, KM_USER0);
 
 
-		memcpy(dst + offset, src + buf->offset, sd->len);
+		memcpy(dst + offset, src + buf->offset, this_len);
 		flush_dcache_page(page);
 		flush_dcache_page(page);
 		kunmap_atomic(dst, KM_USER0);
 		kunmap_atomic(dst, KM_USER0);
 	}
 	}
 
 
-	ret = mapping->a_ops->commit_write(file, page, 0, sd->len);
+	ret = mapping->a_ops->commit_write(file, page, offset, offset+this_len);
 	if (ret == AOP_TRUNCATED_PAGE) {
 	if (ret == AOP_TRUNCATED_PAGE) {
 		page_cache_release(page);
 		page_cache_release(page);
 		goto find_page;
 		goto find_page;
 	} else if (ret)
 	} else if (ret)
 		goto out;
 		goto out;
 
 
+	/*
+	 * Return the number of bytes written.
+	 */
+	ret = this_len;
 	mark_page_accessed(page);
 	mark_page_accessed(page);
 	balance_dirty_pages_ratelimited(mapping);
 	balance_dirty_pages_ratelimited(mapping);
 out:
 out:
@@ -616,17 +656,14 @@ out_nomem:
 	return ret;
 	return ret;
 }
 }
 
 
-typedef int (splice_actor)(struct pipe_inode_info *, struct pipe_buffer *,
-			   struct splice_desc *);
-
 /*
 /*
  * Pipe input worker. Most of this logic works like a regular pipe, the
  * Pipe input worker. Most of this logic works like a regular pipe, the
  * key here is the 'actor' worker passed in that actually moves the data
  * key here is the 'actor' worker passed in that actually moves the data
  * to the wanted destination. See pipe_to_file/pipe_to_sendpage above.
  * to the wanted destination. See pipe_to_file/pipe_to_sendpage above.
  */
  */
-static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out,
-			      loff_t *ppos, size_t len, unsigned int flags,
-			      splice_actor *actor)
+ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
+			 loff_t *ppos, size_t len, unsigned int flags,
+			 splice_actor *actor)
 {
 {
 	int ret, do_wakeup, err;
 	int ret, do_wakeup, err;
 	struct splice_desc sd;
 	struct splice_desc sd;
@@ -652,16 +689,22 @@ static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out,
 				sd.len = sd.total_len;
 				sd.len = sd.total_len;
 
 
 			err = actor(pipe, buf, &sd);
 			err = actor(pipe, buf, &sd);
-			if (err) {
+			if (err <= 0) {
 				if (!ret && err != -ENODATA)
 				if (!ret && err != -ENODATA)
 					ret = err;
 					ret = err;
 
 
 				break;
 				break;
 			}
 			}
 
 
-			ret += sd.len;
-			buf->offset += sd.len;
-			buf->len -= sd.len;
+			ret += err;
+			buf->offset += err;
+			buf->len -= err;
+
+			sd.len -= err;
+			sd.pos += err;
+			sd.total_len -= err;
+			if (sd.len)
+				continue;
 
 
 			if (!buf->len) {
 			if (!buf->len) {
 				buf->ops = NULL;
 				buf->ops = NULL;
@@ -672,8 +715,6 @@ static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out,
 					do_wakeup = 1;
 					do_wakeup = 1;
 			}
 			}
 
 
-			sd.pos += sd.len;
-			sd.total_len -= sd.len;
 			if (!sd.total_len)
 			if (!sd.total_len)
 				break;
 				break;
 		}
 		}
@@ -741,7 +782,7 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
 	struct address_space *mapping = out->f_mapping;
 	struct address_space *mapping = out->f_mapping;
 	ssize_t ret;
 	ssize_t ret;
 
 
-	ret = move_from_pipe(pipe, out, ppos, len, flags, pipe_to_file);
+	ret = splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file);
 	if (ret > 0) {
 	if (ret > 0) {
 		struct inode *inode = mapping->host;
 		struct inode *inode = mapping->host;
 
 
@@ -783,7 +824,7 @@ EXPORT_SYMBOL(generic_file_splice_write);
 ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out,
 ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out,
 				loff_t *ppos, size_t len, unsigned int flags)
 				loff_t *ppos, size_t len, unsigned int flags)
 {
 {
-	return move_from_pipe(pipe, out, ppos, len, flags, pipe_to_sendpage);
+	return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_sendpage);
 }
 }
 
 
 EXPORT_SYMBOL(generic_splice_sendpage);
 EXPORT_SYMBOL(generic_splice_sendpage);
@@ -870,7 +911,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
 
 
 		/*
 		/*
 		 * We don't have an immediate reader, but we'll read the stuff
 		 * We don't have an immediate reader, but we'll read the stuff
-		 * out of the pipe right after the move_to_pipe(). So set
+		 * out of the pipe right after the splice_to_pipe(). So set
 		 * PIPE_READERS appropriately.
 		 * PIPE_READERS appropriately.
 		 */
 		 */
 		pipe->readers = 1;
 		pipe->readers = 1;
@@ -1010,6 +1051,174 @@ static long do_splice(struct file *in, loff_t __user *off_in,
 	return -EINVAL;
 	return -EINVAL;
 }
 }
 
 
+/*
+ * Map an iov into an array of pages and offset/length tupples. With the
+ * partial_page structure, we can map several non-contiguous ranges into
+ * our ones pages[] map instead of splitting that operation into pieces.
+ * Could easily be exported as a generic helper for other users, in which
+ * case one would probably want to add a 'max_nr_pages' parameter as well.
+ */
+static int get_iovec_page_array(const struct iovec __user *iov,
+				unsigned int nr_vecs, struct page **pages,
+				struct partial_page *partial)
+{
+	int buffers = 0, error = 0;
+
+	/*
+	 * It's ok to take the mmap_sem for reading, even
+	 * across a "get_user()".
+	 */
+	down_read(&current->mm->mmap_sem);
+
+	while (nr_vecs) {
+		unsigned long off, npages;
+		void __user *base;
+		size_t len;
+		int i;
+
+		/*
+		 * Get user address base and length for this iovec.
+		 */
+		error = get_user(base, &iov->iov_base);
+		if (unlikely(error))
+			break;
+		error = get_user(len, &iov->iov_len);
+		if (unlikely(error))
+			break;
+
+		/*
+		 * Sanity check this iovec. 0 read succeeds.
+		 */
+		if (unlikely(!len))
+			break;
+		error = -EFAULT;
+		if (unlikely(!base))
+			break;
+
+		/*
+		 * Get this base offset and number of pages, then map
+		 * in the user pages.
+		 */
+		off = (unsigned long) base & ~PAGE_MASK;
+		npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+		if (npages > PIPE_BUFFERS - buffers)
+			npages = PIPE_BUFFERS - buffers;
+
+		error = get_user_pages(current, current->mm,
+				       (unsigned long) base, npages, 0, 0,
+				       &pages[buffers], NULL);
+
+		if (unlikely(error <= 0))
+			break;
+
+		/*
+		 * Fill this contiguous range into the partial page map.
+		 */
+		for (i = 0; i < error; i++) {
+			const int plen = min_t(size_t, len, PAGE_SIZE) - off;
+
+			partial[buffers].offset = off;
+			partial[buffers].len = plen;
+
+			off = 0;
+			len -= plen;
+			buffers++;
+		}
+
+		/*
+		 * We didn't complete this iov, stop here since it probably
+		 * means we have to move some of this into a pipe to
+		 * be able to continue.
+		 */
+		if (len)
+			break;
+
+		/*
+		 * Don't continue if we mapped fewer pages than we asked for,
+		 * or if we mapped the max number of pages that we have
+		 * room for.
+		 */
+		if (error < npages || buffers == PIPE_BUFFERS)
+			break;
+
+		nr_vecs--;
+		iov++;
+	}
+
+	up_read(&current->mm->mmap_sem);
+
+	if (buffers)
+		return buffers;
+
+	return error;
+}
+
+/*
+ * vmsplice splices a user address range into a pipe. It can be thought of
+ * as splice-from-memory, where the regular splice is splice-from-file (or
+ * to file). In both cases the output is a pipe, naturally.
+ *
+ * Note that vmsplice only supports splicing _from_ user memory to a pipe,
+ * not the other way around. Splicing from user memory is a simple operation
+ * that can be supported without any funky alignment restrictions or nasty
+ * vm tricks. We simply map in the user memory and fill them into a pipe.
+ * The reverse isn't quite as easy, though. There are two possible solutions
+ * for that:
+ *
+ *	- memcpy() the data internally, at which point we might as well just
+ *	  do a regular read() on the buffer anyway.
+ *	- Lots of nasty vm tricks, that are neither fast nor flexible (it
+ *	  has restriction limitations on both ends of the pipe).
+ *
+ * Alas, it isn't here.
+ *
+ */
+static long do_vmsplice(struct file *file, const struct iovec __user *iov,
+			unsigned long nr_segs, unsigned int flags)
+{
+	struct pipe_inode_info *pipe = file->f_dentry->d_inode->i_pipe;
+	struct page *pages[PIPE_BUFFERS];
+	struct partial_page partial[PIPE_BUFFERS];
+	struct splice_pipe_desc spd = {
+		.pages = pages,
+		.partial = partial,
+		.flags = flags,
+		.ops = &user_page_pipe_buf_ops,
+	};
+
+	if (unlikely(!pipe))
+		return -EBADF;
+	if (unlikely(nr_segs > UIO_MAXIOV))
+		return -EINVAL;
+	else if (unlikely(!nr_segs))
+		return 0;
+
+	spd.nr_pages = get_iovec_page_array(iov, nr_segs, pages, partial);
+	if (spd.nr_pages <= 0)
+		return spd.nr_pages;
+
+	return splice_to_pipe(pipe, &spd);
+}
+
+asmlinkage long sys_vmsplice(int fd, const struct iovec __user *iov,
+			     unsigned long nr_segs, unsigned int flags)
+{
+	struct file *file;
+	long error;
+	int fput;
+
+	error = -EBADF;
+	file = fget_light(fd, &fput);
+	if (file) {
+		if (file->f_mode & FMODE_WRITE)
+			error = do_vmsplice(file, iov, nr_segs, flags);
+
+		fput_light(file, fput);
+	}
+
+	return error;
+}
+
 asmlinkage long sys_splice(int fd_in, loff_t __user *off_in,
 asmlinkage long sys_splice(int fd_in, loff_t __user *off_in,
 			   int fd_out, loff_t __user *off_out,
 			   int fd_out, loff_t __user *off_out,
 			   size_t len, unsigned int flags)
 			   size_t len, unsigned int flags)

+ 2 - 1
include/asm-i386/unistd.h

@@ -321,8 +321,9 @@
 #define __NR_splice		313
 #define __NR_splice		313
 #define __NR_sync_file_range	314
 #define __NR_sync_file_range	314
 #define __NR_tee		315
 #define __NR_tee		315
+#define __NR_vmsplice		316
 
 
-#define NR_syscalls 316
+#define NR_syscalls 317
 
 
 /*
 /*
  * user-visible error numbers are in the range -1 - -128: see
  * user-visible error numbers are in the range -1 - -128: see

+ 2 - 1
include/asm-ia64/unistd.h

@@ -290,12 +290,13 @@
 #define __NR_get_robust_list		1299
 #define __NR_get_robust_list		1299
 #define __NR_sync_file_range		1300
 #define __NR_sync_file_range		1300
 #define __NR_tee			1301
 #define __NR_tee			1301
+#define __NR_vmsplice			1302
 
 
 #ifdef __KERNEL__
 #ifdef __KERNEL__
 
 
 #include <linux/config.h>
 #include <linux/config.h>
 
 
-#define NR_syscalls			278 /* length of syscall table */
+#define NR_syscalls			279 /* length of syscall table */
 
 
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGACTION
 
 

+ 2 - 1
include/asm-powerpc/unistd.h

@@ -303,8 +303,9 @@
 #define __NR_unshare		282
 #define __NR_unshare		282
 #define __NR_splice		283
 #define __NR_splice		283
 #define __NR_tee		284
 #define __NR_tee		284
+#define __NR_vmsplice		285
 
 
-#define __NR_syscalls		285
+#define __NR_syscalls		286
 
 
 #ifdef __KERNEL__
 #ifdef __KERNEL__
 #define __NR__exit __NR_exit
 #define __NR__exit __NR_exit

+ 3 - 1
include/asm-x86_64/unistd.h

@@ -615,8 +615,10 @@ __SYSCALL(__NR_splice, sys_splice)
 __SYSCALL(__NR_tee, sys_tee)
 __SYSCALL(__NR_tee, sys_tee)
 #define __NR_sync_file_range	277
 #define __NR_sync_file_range	277
 __SYSCALL(__NR_sync_file_range, sys_sync_file_range)
 __SYSCALL(__NR_sync_file_range, sys_sync_file_range)
+#define __NR_vmsplice		278
+__SYSCALL(__NR_vmsplice, sys_vmsplice)
 
 
-#define __NR_syscall_max __NR_sync_file_range
+#define __NR_syscall_max __NR_vmsplice
 
 
 #ifndef __NO_STUBS
 #ifndef __NO_STUBS
 
 

+ 17 - 0
include/linux/pipe_fs_i.h

@@ -61,4 +61,21 @@ void __free_pipe_info(struct pipe_inode_info *);
 				 /* from/to, of course */
 				 /* from/to, of course */
 #define SPLICE_F_MORE	(0x04)	/* expect more data */
 #define SPLICE_F_MORE	(0x04)	/* expect more data */
 
 
+/*
+ * Passed to the actors
+ */
+struct splice_desc {
+	unsigned int len, total_len;	/* current and remaining length */
+	unsigned int flags;		/* splice flags */
+	struct file *file;		/* file to read/write */
+	loff_t pos;			/* file position */
+};
+
+typedef int (splice_actor)(struct pipe_inode_info *, struct pipe_buffer *,
+			   struct splice_desc *);
+
+extern ssize_t splice_from_pipe(struct pipe_inode_info *, struct file *,
+				loff_t *, size_t, unsigned int,
+				splice_actor *);
+
 #endif
 #endif

+ 3 - 0
include/linux/syscalls.h

@@ -574,6 +574,9 @@ asmlinkage long sys_splice(int fd_in, loff_t __user *off_in,
 			   int fd_out, loff_t __user *off_out,
 			   int fd_out, loff_t __user *off_out,
 			   size_t len, unsigned int flags);
 			   size_t len, unsigned int flags);
 
 
+asmlinkage long sys_vmsplice(int fd, const struct iovec __user *iov,
+			     unsigned long nr_segs, unsigned int flags);
+
 asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags);
 asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags);
 
 
 asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
 asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,

+ 2 - 2
kernel/hrtimer.c

@@ -836,7 +836,7 @@ static void migrate_hrtimers(int cpu)
 }
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 #endif /* CONFIG_HOTPLUG_CPU */
 
 
-static int __devinit hrtimer_cpu_notify(struct notifier_block *self,
+static int hrtimer_cpu_notify(struct notifier_block *self,
 					unsigned long action, void *hcpu)
 					unsigned long action, void *hcpu)
 {
 {
 	long cpu = (long)hcpu;
 	long cpu = (long)hcpu;
@@ -860,7 +860,7 @@ static int __devinit hrtimer_cpu_notify(struct notifier_block *self,
 	return NOTIFY_OK;
 	return NOTIFY_OK;
 }
 }
 
 
-static struct notifier_block __devinitdata hrtimers_nb = {
+static struct notifier_block hrtimers_nb = {
 	.notifier_call = hrtimer_cpu_notify,
 	.notifier_call = hrtimer_cpu_notify,
 };
 };
 
 

+ 1 - 1
kernel/profile.c

@@ -299,7 +299,7 @@ out:
 }
 }
 
 
 #ifdef CONFIG_HOTPLUG_CPU
 #ifdef CONFIG_HOTPLUG_CPU
-static int __devinit profile_cpu_callback(struct notifier_block *info,
+static int profile_cpu_callback(struct notifier_block *info,
 					unsigned long action, void *__cpu)
 					unsigned long action, void *__cpu)
 {
 {
 	int node, cpu = (unsigned long)__cpu;
 	int node, cpu = (unsigned long)__cpu;

+ 2 - 2
kernel/rcupdate.c

@@ -520,7 +520,7 @@ static void __devinit rcu_online_cpu(int cpu)
 	tasklet_init(&per_cpu(rcu_tasklet, cpu), rcu_process_callbacks, 0UL);
 	tasklet_init(&per_cpu(rcu_tasklet, cpu), rcu_process_callbacks, 0UL);
 }
 }
 
 
-static int __devinit rcu_cpu_notify(struct notifier_block *self, 
+static int rcu_cpu_notify(struct notifier_block *self,
 				unsigned long action, void *hcpu)
 				unsigned long action, void *hcpu)
 {
 {
 	long cpu = (long)hcpu;
 	long cpu = (long)hcpu;
@@ -537,7 +537,7 @@ static int __devinit rcu_cpu_notify(struct notifier_block *self,
 	return NOTIFY_OK;
 	return NOTIFY_OK;
 }
 }
 
 
-static struct notifier_block __devinitdata rcu_nb = {
+static struct notifier_block rcu_nb = {
 	.notifier_call	= rcu_cpu_notify,
 	.notifier_call	= rcu_cpu_notify,
 };
 };
 
 

+ 1 - 1
kernel/sched.c

@@ -4814,7 +4814,7 @@ static int migration_call(struct notifier_block *nfb, unsigned long action,
 /* Register at highest priority so that task migration (migrate_all_tasks)
 /* Register at highest priority so that task migration (migrate_all_tasks)
  * happens before everything else.
  * happens before everything else.
  */
  */
-static struct notifier_block __devinitdata migration_notifier = {
+static struct notifier_block migration_notifier = {
 	.notifier_call = migration_call,
 	.notifier_call = migration_call,
 	.priority = 10
 	.priority = 10
 };
 };

+ 2 - 2
kernel/softirq.c

@@ -446,7 +446,7 @@ static void takeover_tasklets(unsigned int cpu)
 }
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 #endif /* CONFIG_HOTPLUG_CPU */
 
 
-static int __devinit cpu_callback(struct notifier_block *nfb,
+static int cpu_callback(struct notifier_block *nfb,
 				  unsigned long action,
 				  unsigned long action,
 				  void *hcpu)
 				  void *hcpu)
 {
 {
@@ -484,7 +484,7 @@ static int __devinit cpu_callback(struct notifier_block *nfb,
 	return NOTIFY_OK;
 	return NOTIFY_OK;
 }
 }
 
 
-static struct notifier_block __devinitdata cpu_nfb = {
+static struct notifier_block cpu_nfb = {
 	.notifier_call = cpu_callback
 	.notifier_call = cpu_callback
 };
 };
 
 

+ 2 - 2
kernel/softlockup.c

@@ -104,7 +104,7 @@ static int watchdog(void * __bind_cpu)
 /*
 /*
  * Create/destroy watchdog threads as CPUs come and go:
  * Create/destroy watchdog threads as CPUs come and go:
  */
  */
-static int __devinit
+static int
 cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 {
 {
 	int hotcpu = (unsigned long)hcpu;
 	int hotcpu = (unsigned long)hcpu;
@@ -140,7 +140,7 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 	return NOTIFY_OK;
 	return NOTIFY_OK;
 }
 }
 
 
-static struct notifier_block __devinitdata cpu_nfb = {
+static struct notifier_block cpu_nfb = {
 	.notifier_call = cpu_callback
 	.notifier_call = cpu_callback
 };
 };
 
 

+ 2 - 2
kernel/timer.c

@@ -1314,7 +1314,7 @@ static void __devinit migrate_timers(int cpu)
 }
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 #endif /* CONFIG_HOTPLUG_CPU */
 
 
-static int __devinit timer_cpu_notify(struct notifier_block *self, 
+static int timer_cpu_notify(struct notifier_block *self,
 				unsigned long action, void *hcpu)
 				unsigned long action, void *hcpu)
 {
 {
 	long cpu = (long)hcpu;
 	long cpu = (long)hcpu;
@@ -1334,7 +1334,7 @@ static int __devinit timer_cpu_notify(struct notifier_block *self,
 	return NOTIFY_OK;
 	return NOTIFY_OK;
 }
 }
 
 
-static struct notifier_block __devinitdata timers_nb = {
+static struct notifier_block timers_nb = {
 	.notifier_call	= timer_cpu_notify,
 	.notifier_call	= timer_cpu_notify,
 };
 };
 
 

+ 1 - 1
kernel/workqueue.c

@@ -547,7 +547,7 @@ static void take_over_work(struct workqueue_struct *wq, unsigned int cpu)
 }
 }
 
 
 /* We're holding the cpucontrol mutex here */
 /* We're holding the cpucontrol mutex here */
-static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
+static int workqueue_cpu_callback(struct notifier_block *nfb,
 				  unsigned long action,
 				  unsigned long action,
 				  void *hcpu)
 				  void *hcpu)
 {
 {

+ 1 - 1
mm/page_alloc.c

@@ -1962,7 +1962,7 @@ static inline void free_zone_pagesets(int cpu)
 	}
 	}
 }
 }
 
 
-static int __cpuinit pageset_cpuup_callback(struct notifier_block *nfb,
+static int pageset_cpuup_callback(struct notifier_block *nfb,
 		unsigned long action,
 		unsigned long action,
 		void *hcpu)
 		void *hcpu)
 {
 {

+ 1 - 1
mm/slab.c

@@ -1036,7 +1036,7 @@ static inline void free_alien_cache(struct array_cache **ac_ptr)
 
 
 #endif
 #endif
 
 
-static int __devinit cpuup_callback(struct notifier_block *nfb,
+static int cpuup_callback(struct notifier_block *nfb,
 				    unsigned long action, void *hcpu)
 				    unsigned long action, void *hcpu)
 {
 {
 	long cpu = (long)hcpu;
 	long cpu = (long)hcpu;

+ 1 - 1
mm/vmscan.c

@@ -1328,7 +1328,7 @@ repeat:
    not required for correctness.  So if the last cpu in a node goes
    not required for correctness.  So if the last cpu in a node goes
    away, we get changed to run anywhere: as the first one comes back,
    away, we get changed to run anywhere: as the first one comes back,
    restore their cpu bindings. */
    restore their cpu bindings. */
-static int __devinit cpu_callback(struct notifier_block *nfb,
+static int cpu_callback(struct notifier_block *nfb,
 				  unsigned long action, void *hcpu)
 				  unsigned long action, void *hcpu)
 {
 {
 	pg_data_t *pgdat;
 	pg_data_t *pgdat;

+ 7 - 1
net/bridge/br_forward.c

@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/skbuff.h>
+#include <linux/if_vlan.h>
 #include <linux/netfilter_bridge.h>
 #include <linux/netfilter_bridge.h>
 #include "br_private.h"
 #include "br_private.h"
 
 
@@ -29,10 +30,15 @@ static inline int should_deliver(const struct net_bridge_port *p,
 	return 1;
 	return 1;
 }
 }
 
 
+static inline unsigned packet_length(const struct sk_buff *skb)
+{
+	return skb->len - (skb->protocol == htons(ETH_P_8021Q) ? VLAN_HLEN : 0);
+}
+
 int br_dev_queue_push_xmit(struct sk_buff *skb)
 int br_dev_queue_push_xmit(struct sk_buff *skb)
 {
 {
 	/* drop mtu oversized packets except tso */
 	/* drop mtu oversized packets except tso */
-	if (skb->len > skb->dev->mtu && !skb_shinfo(skb)->tso_size)
+	if (packet_length(skb) > skb->dev->mtu && !skb_shinfo(skb)->tso_size)
 		kfree_skb(skb);
 		kfree_skb(skb);
 	else {
 	else {
 #ifdef CONFIG_BRIDGE_NETFILTER
 #ifdef CONFIG_BRIDGE_NETFILTER