diff options
162 files changed, 1816 insertions, 1461 deletions
@@ -204,6 +204,9 @@ ifeq ($(ARCH),x86_64) endif # Additional ARCH settings for sparc +ifeq ($(ARCH),sparc32) + SRCARCH := sparc +endif ifeq ($(ARCH),sparc64) SRCARCH := sparc endif diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 6b1852f7f972..39e534f5a3b0 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -618,16 +618,15 @@ pfm_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, } -static int -pfmfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, - struct vfsmount *mnt) +static struct dentry * +pfmfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - return get_sb_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC, mnt); + return mount_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC); } static struct file_system_type pfm_fs_type = { .name = "pfmfs", - .get_sb = pfmfs_get_sb, + .mount = pfmfs_mount, .kill_sb = kill_anon_super, }; diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 5dec408d6703..3532b92de983 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -798,17 +798,17 @@ spufs_fill_super(struct super_block *sb, void *data, int silent) return spufs_create_root(sb, data); } -static int -spufs_get_sb(struct file_system_type *fstype, int flags, - const char *name, void *data, struct vfsmount *mnt) +static struct dentry * +spufs_mount(struct file_system_type *fstype, int flags, + const char *name, void *data) { - return get_sb_single(fstype, flags, data, spufs_fill_super, mnt); + return mount_single(fstype, flags, data, spufs_fill_super); } static struct file_system_type spufs_type = { .owner = THIS_MODULE, .name = "spufs", - .get_sb = spufs_get_sb, + .mount = spufs_mount, .kill_sb = kill_litter_super, }; diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index fabb40bc4e19..e0b98e71ff47 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -80,6 +80,7 @@ config S390 select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_TRACE_MCOUNT_TEST select HAVE_FTRACE_MCOUNT_RECORD + select HAVE_C_RECORDMCOUNT select HAVE_SYSCALL_TRACEPOINTS select HAVE_DYNAMIC_FTRACE select HAVE_FUNCTION_GRAPH_TRACER @@ -144,7 +145,7 @@ source "kernel/time/Kconfig" config 64BIT bool "64 bit kernel" help - Select this option if you have a 64 bit IBM zSeries machine + Select this option if you have an IBM z/Architecture machine and want to use the 64 bit addressing mode. config 32BIT @@ -196,9 +197,18 @@ config HOTPLUG_CPU can be controlled through /sys/devices/system/cpu/cpu#. Say N if you want to disable CPU hotplug. +config SCHED_MC + def_bool y + prompt "Multi-core scheduler support" + depends on SMP + help + Multi-core scheduler support improves the CPU scheduler's decision + making when dealing with multi-core CPU chips at a cost of slightly + increased overhead in some places. + config SCHED_BOOK bool "Book scheduler support" - depends on SMP + depends on SMP && SCHED_MC help Book scheduler support improves the CPU scheduler's decision making when dealing with machines that have several books. @@ -208,7 +218,7 @@ config MATHEMU depends on MARCH_G5 help This option is required for IEEE compliant floating point arithmetic - on older S/390 machines. Say Y unless you know your machine doesn't + on older ESA/390 machines. Say Y unless you know your machine doesn't need this. config COMPAT @@ -237,8 +247,8 @@ config S390_EXEC_PROTECT space programs and it also selects the addressing mode option above. The kernel parameter noexec=on will enable this feature and also switch the addressing modes, default is disabled. Enabling this (via - kernel parameter) on machines earlier than IBM System z9-109 EC/BC - will reduce system performance. + kernel parameter) on machines earlier than IBM System z9 this will + reduce system performance. comment "Code generation options" @@ -247,49 +257,46 @@ choice default MARCH_G5 config MARCH_G5 - bool "S/390 model G5 and G6" + bool "System/390 model G5 and G6" depends on !64BIT help Select this to build a 31 bit kernel that works - on all S/390 and zSeries machines. + on all ESA/390 and z/Architecture machines. config MARCH_Z900 - bool "IBM eServer zSeries model z800 and z900" + bool "IBM zSeries model z800 and z900" help - Select this to optimize for zSeries machines. This - will enable some optimizations that are not available - on older 31 bit only CPUs. + Select this to enable optimizations for model z800/z900 (2064 and + 2066 series). This will enable some optimizations that are not + available on older ESA/390 (31 Bit) only CPUs. config MARCH_Z990 - bool "IBM eServer zSeries model z890 and z990" + bool "IBM zSeries model z890 and z990" help - Select this enable optimizations for model z890/z990. - This will be slightly faster but does not work on - older machines such as the z900. + Select this to enable optimizations for model z890/z990 (2084 and + 2086 series). The kernel will be slightly faster but will not work + on older machines. config MARCH_Z9_109 bool "IBM System z9" help - Select this to enable optimizations for IBM System z9-109, IBM - System z9 Enterprise Class (z9 EC), and IBM System z9 Business - Class (z9 BC). The kernel will be slightly faster but will not - work on older machines such as the z990, z890, z900, and z800. + Select this to enable optimizations for IBM System z9 (2094 and + 2096 series). The kernel will be slightly faster but will not work + on older machines. config MARCH_Z10 bool "IBM System z10" help - Select this to enable optimizations for IBM System z10. The - kernel will be slightly faster but will not work on older - machines such as the z990, z890, z900, z800, z9-109, z9-ec - and z9-bc. + Select this to enable optimizations for IBM System z10 (2097 and + 2098 series). The kernel will be slightly faster but will not work + on older machines. config MARCH_Z196 bool "IBM zEnterprise 196" help - Select this to enable optimizations for IBM zEnterprise 196. - The kernel will be slightly faster but will not work on older - machines such as the z990, z890, z900, z800, z9-109, z9-ec, - z9-bc, z10-ec and z10-bc. + Select this to enable optimizations for IBM zEnterprise 196 + (2817 series). The kernel will be slightly faster but will not work + on older machines. endchoice diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c index 020e51c063d2..cd4a81be9cf8 100644 --- a/arch/s390/hypfs/hypfs_diag.c +++ b/arch/s390/hypfs/hypfs_diag.c @@ -638,18 +638,21 @@ __init int hypfs_diag_init(void) pr_err("The hardware system does not support hypfs\n"); return -ENODATA; } - rc = diag224_get_name_table(); - if (rc) { - diag204_free_buffer(); - pr_err("The hardware system does not provide all " - "functions required by hypfs\n"); - } if (diag204_info_type == INFO_EXT) { rc = hypfs_dbfs_init(); if (rc) - diag204_free_buffer(); + return rc; } - return rc; + if (MACHINE_IS_LPAR) { + rc = diag224_get_name_table(); + if (rc) { + pr_err("The hardware system does not provide all " + "functions required by hypfs\n"); + debugfs_remove(dbfs_d204_file); + return rc; + } + } + return 0; } void hypfs_diag_exit(void) diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index 74d98670be27..47cc446dab8f 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -316,10 +316,10 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent) return 0; } -static int hypfs_get_super(struct file_system_type *fst, int flags, - const char *devname, void *data, struct vfsmount *mnt) +static struct dentry *hypfs_mount(struct file_system_type *fst, int flags, + const char *devname, void *data) { - return get_sb_single(fst, flags, data, hypfs_fill_super, mnt); + return mount_single(fst, flags, data, hypfs_fill_super); } static void hypfs_kill_super(struct super_block *sb) @@ -455,7 +455,7 @@ static const struct file_operations hypfs_file_ops = { static struct file_system_type hypfs_type = { .owner = THIS_MODULE, .name = "s390_hypfs", - .get_sb = hypfs_get_super, + .mount = hypfs_mount, .kill_sb = hypfs_kill_super }; diff --git a/arch/s390/include/asm/dasd.h b/arch/s390/include/asm/dasd.h index 218bce81ec70..b604a9186f8e 100644 --- a/arch/s390/include/asm/dasd.h +++ b/arch/s390/include/asm/dasd.h @@ -217,6 +217,25 @@ typedef struct dasd_symmio_parms { int rssd_result_len; } __attribute__ ((packed)) dasd_symmio_parms_t; +/* + * Data returned by Sense Path Group ID (SNID) + */ +struct dasd_snid_data { + struct { + __u8 group:2; + __u8 reserve:2; + __u8 mode:1; + __u8 res:3; + } __attribute__ ((packed)) path_state; + __u8 pgid[11]; +} __attribute__ ((packed)); + +struct dasd_snid_ioctl_data { + struct dasd_snid_data data; + __u8 path_mask; +} __attribute__ ((packed)); + + /******************************************************************************** * SECTION: Definition of IOCTLs * @@ -261,25 +280,10 @@ typedef struct dasd_symmio_parms { /* Set Attributes (cache operations) */ #define BIODASDSATTR _IOW(DASD_IOCTL_LETTER,2,attrib_data_t) +/* Get Sense Path Group ID (SNID) data */ +#define BIODASDSNID _IOWR(DASD_IOCTL_LETTER, 1, struct dasd_snid_ioctl_data) + #define BIODASDSYMMIO _IOWR(DASD_IOCTL_LETTER, 240, dasd_symmio_parms_t) #endif /* DASD_H */ -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 4 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -4 - * c-argdecl-indent: 4 - * c-label-offset: -4 - * c-continued-statement-offset: 4 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index f3c1b823c9a8..33982e7ce04d 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -66,9 +66,9 @@ int main(void) DEFINE(__VDSO_ECTG_BASE, offsetof(struct vdso_per_cpu_data, ectg_timer_base)); DEFINE(__VDSO_ECTG_USER, offsetof(struct vdso_per_cpu_data, ectg_user_time)); /* constants used by the vdso */ - DEFINE(CLOCK_REALTIME, CLOCK_REALTIME); - DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC); - DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC); + DEFINE(__CLOCK_REALTIME, CLOCK_REALTIME); + DEFINE(__CLOCK_MONOTONIC, CLOCK_MONOTONIC); + DEFINE(__CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC); BLANK(); /* constants for SIGP */ DEFINE(__SIGP_STOP, sigp_stop); diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index d149609e46e6..3b7e7dddc324 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -282,8 +282,6 @@ static noinline __init void setup_facility_list(void) static noinline __init void setup_hpage(void) { #ifndef CONFIG_DEBUG_PAGEALLOC - unsigned int facilities; - if (!test_facility(2) || !test_facility(8)) return; S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE; diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 5efce7202984..1ecc337fb679 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -557,6 +557,7 @@ pgm_svcper: # per was called from kernel, must be kprobes # kernel_per: + REENABLE_IRQS mvi SP_SVCNR(%r15),0xff # set trap indication to pgm check mvi SP_SVCNR+1(%r15),0xff la %r2,SP_PTREGS(%r15) # address of register-save area diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index a2be23922f43..8f3e802174db 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -568,6 +568,7 @@ pgm_svcper: # per was called from kernel, must be kprobes # kernel_per: + REENABLE_IRQS xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number la %r2,SP_PTREGS(%r15) # address of register-save area brasl %r14,do_single_step diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 2a3d2bf6f083..d60fc4398516 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -316,6 +316,8 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) return 1; ss_probe: + if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO)) + local_irq_disable(); prepare_singlestep(p, regs); kcb->kprobe_status = KPROBE_HIT_SS; return 1; @@ -463,6 +465,8 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs) goto out; } reset_current_kprobe(); + if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO)) + local_irq_enable(); out: preempt_enable_no_resched(); @@ -502,8 +506,11 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) regs->psw.mask |= kcb->kprobe_saved_imask; if (kcb->kprobe_status == KPROBE_REENTER) restore_previous_kprobe(kcb); - else + else { reset_current_kprobe(); + if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO)) + local_irq_enable(); + } preempt_enable_no_resched(); break; case KPROBE_HIT_ACTIVE: diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index e3ceb911dc75..6f6350826c81 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -761,6 +761,9 @@ static void __init setup_hwcaps(void) case 0x2098: strcpy(elf_platform, "z10"); break; + case 0x2817: + strcpy(elf_platform, "z196"); + break; } } diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c index f04d93aa48ec..5c9e439bf3f6 100644 --- a/arch/s390/kernel/sysinfo.c +++ b/arch/s390/kernel/sysinfo.c @@ -106,11 +106,13 @@ static int stsi_15_1_x(struct sysinfo_15_1_x *info, char *page, int len) for (i = 0; i < TOPOLOGY_NR_MAG; i++) len += sprintf(page + len, " %d", info->mag[i]); len += sprintf(page + len, "\n"); +#ifdef CONFIG_SCHED_MC store_topology(info); len += sprintf(page + len, "CPU Topology SW: "); for (i = 0; i < TOPOLOGY_NR_MAG; i++) len += sprintf(page + len, " %d", info->mag[i]); len += sprintf(page + len, "\n"); +#endif return len; } diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index a9dee9048ee5..94b06c31fc8a 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -53,8 +53,10 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) cpumask_t mask; cpus_clear(mask); - if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) - return cpu_possible_map; + if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) { + cpumask_copy(&mask, cpumask_of(cpu)); + return mask; + } while (info) { if (cpu_isset(cpu, info->mask)) { mask = info->mask; diff --git a/arch/s390/kernel/vdso32/clock_getres.S b/arch/s390/kernel/vdso32/clock_getres.S index 9532c4e6a9d2..36aaa25d05da 100644 --- a/arch/s390/kernel/vdso32/clock_getres.S +++ b/arch/s390/kernel/vdso32/clock_getres.S @@ -19,9 +19,9 @@ .type __kernel_clock_getres,@function __kernel_clock_getres: .cfi_startproc - chi %r2,CLOCK_REALTIME + chi %r2,__CLOCK_REALTIME je 0f - chi %r2,CLOCK_MONOTONIC + chi %r2,__CLOCK_MONOTONIC jne 3f 0: ltr %r3,%r3 jz 2f /* res == NULL */ @@ -34,6 +34,6 @@ __kernel_clock_getres: 3: lhi %r1,__NR_clock_getres /* fallback to svc */ svc 0 br %r14 -4: .long CLOCK_REALTIME_RES +4: .long __CLOCK_REALTIME_RES .cfi_endproc .size __kernel_clock_getres,.-__kernel_clock_getres diff --git a/arch/s390/kernel/vdso32/clock_gettime.S b/arch/s390/kernel/vdso32/clock_gettime.S index 969643954273..b2224e0b974c 100644 --- a/arch/s390/kernel/vdso32/clock_gettime.S +++ b/arch/s390/kernel/vdso32/clock_gettime.S @@ -21,9 +21,9 @@ __kernel_clock_gettime: .cfi_startproc basr %r5,0 0: al %r5,21f-0b(%r5) /* get &_vdso_data */ - chi %r2,CLOCK_REALTIME + chi %r2,__CLOCK_REALTIME je 10f - chi %r2,CLOCK_MONOTONIC + chi %r2,__CLOCK_MONOTONIC jne 19f /* CLOCK_MONOTONIC */ diff --git a/arch/s390/kernel/vdso64/clock_getres.S b/arch/s390/kernel/vdso64/clock_getres.S index 9ce8caafdb4e..176e1f75f9aa 100644 --- a/arch/s390/kernel/vdso64/clock_getres.S +++ b/arch/s390/kernel/vdso64/clock_getres.S @@ -19,9 +19,9 @@ .type __kernel_clock_getres,@function __kernel_clock_getres: .cfi_startproc - cghi %r2,CLOCK_REALTIME + cghi %r2,__CLOCK_REALTIME je 0f - cghi %r2,CLOCK_MONOTONIC + cghi %r2,__CLOCK_MONOTONIC je 0f cghi %r2,-2 /* CLOCK_THREAD_CPUTIME_ID for this thread */ jne 2f @@ -39,6 +39,6 @@ __kernel_clock_getres: 2: lghi %r1,__NR_clock_getres /* fallback to svc */ svc 0 br %r14 -3: .quad CLOCK_REALTIME_RES +3: .quad __CLOCK_REALTIME_RES .cfi_endproc .size __kernel_clock_getres,.-__kernel_clock_getres diff --git a/arch/s390/kernel/vdso64/clock_gettime.S b/arch/s390/kernel/vdso64/clock_gettime.S index f40467884a03..d46c95ed5f19 100644 --- a/arch/s390/kernel/vdso64/clock_gettime.S +++ b/arch/s390/kernel/vdso64/clock_gettime.S @@ -20,11 +20,11 @@ __kernel_clock_gettime: .cfi_startproc larl %r5,_vdso_data - cghi %r2,CLOCK_REALTIME + cghi %r2,__CLOCK_REALTIME je 4f cghi %r2,-2 /* CLOCK_THREAD_CPUTIME_ID for this thread */ je 9f - cghi %r2,CLOCK_MONOTONIC + cghi %r2,__CLOCK_MONOTONIC jne 12f /* CLOCK_MONOTONIC */ diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index a9aaed3c3d97..45d9c87d083a 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -22,8 +22,6 @@ config SPARC select RTC_CLASS select RTC_DRV_M48T59 select HAVE_IRQ_WORK - select HAVE_PERF_EVENTS - select PERF_USE_VMALLOC select HAVE_DMA_ATTRS select HAVE_DMA_API_DEBUG select HAVE_ARCH_JUMP_LABEL @@ -50,7 +48,6 @@ config SPARC64 select RTC_DRV_BQ4802 select RTC_DRV_SUN4V select RTC_DRV_STARFIRE - select HAVE_IRQ_WORK select HAVE_PERF_EVENTS select PERF_USE_VMALLOC diff --git a/arch/sparc/include/asm/jump_label.h b/arch/sparc/include/asm/jump_label.h index 62e66d7b2fb6..65c0d3029796 100644 --- a/arch/sparc/include/asm/jump_label.h +++ b/arch/sparc/include/asm/jump_label.h @@ -4,7 +4,6 @@ #ifdef __KERNEL__ #include <linux/types.h> -#include <asm/system.h> #define JUMP_LABEL_NOP_SIZE 4 diff --git a/arch/sparc/kernel/irq_32.c b/arch/sparc/kernel/irq_32.c index 0116d8d10def..5ad6e5c5dbb3 100644 --- a/arch/sparc/kernel/irq_32.c +++ b/arch/sparc/kernel/irq_32.c @@ -365,7 +365,7 @@ static int request_fast_irq(unsigned int irq, unsigned long flags; unsigned int cpu_irq; int ret; -#ifdef CONFIG_SMP +#if defined CONFIG_SMP && !defined CONFIG_SPARC_LEON struct tt_entry *trap_table; extern struct tt_entry trapbase_cpu1, trapbase_cpu2, trapbase_cpu3; #endif @@ -425,7 +425,7 @@ static int request_fast_irq(unsigned int irq, table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_four = SPARC_NOP; INSTANTIATE(sparc_ttable) -#ifdef CONFIG_SMP +#if defined CONFIG_SMP && !defined CONFIG_SPARC_LEON trap_table = &trapbase_cpu1; INSTANTIATE(trap_table) trap_table = &trapbase_cpu2; INSTANTIATE(trap_table) trap_table = &trapbase_cpu3; INSTANTIATE(trap_table) diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c index e1656fc41ccb..7524689b03d2 100644 --- a/arch/sparc/kernel/leon_smp.c +++ b/arch/sparc/kernel/leon_smp.c @@ -56,8 +56,8 @@ void __init leon_configure_cache_smp(void); static inline unsigned long do_swap(volatile unsigned long *ptr, unsigned long val) { - __asm__ __volatile__("swapa [%1] %2, %0\n\t" : "=&r"(val) - : "r"(ptr), "i"(ASI_LEON_DCACHE_MISS) + __asm__ __volatile__("swapa [%2] %3, %0\n\t" : "=&r"(val) + : "0"(val), "r"(ptr), "i"(ASI_LEON_DCACHE_MISS) : "memory"); return val; } diff --git a/arch/sparc/kernel/rtrap_32.S b/arch/sparc/kernel/rtrap_32.S index 4da2e1f66290..5f5f74c2c2ca 100644 --- a/arch/sparc/kernel/rtrap_32.S +++ b/arch/sparc/kernel/rtrap_32.S @@ -78,9 +78,9 @@ signal_p: call do_notify_resume add %sp, STACKFRAME_SZ, %o0 ! pt_regs ptr - /* Fall through. */ - ld [%sp + STACKFRAME_SZ + PT_PSR], %t_psr - clr %l6 + b signal_p + ld [%curptr + TI_FLAGS], %g2 + ret_trap_continue: sethi %hi(PSR_SYSCALL), %g1 andn %t_psr, %g1, %t_psr diff --git a/arch/sparc/kernel/rtrap_64.S b/arch/sparc/kernel/rtrap_64.S index 090b9e9ad5e3..77f1b95e0806 100644 --- a/arch/sparc/kernel/rtrap_64.S +++ b/arch/sparc/kernel/rtrap_64.S @@ -34,37 +34,9 @@ __handle_preemption: __handle_user_windows: call fault_in_user_windows wrpr %g0, RTRAP_PSTATE, %pstate - wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate - /* Redo sched+sig checks */ - ldx [%g6 + TI_FLAGS], %l0 - andcc %l0, _TIF_NEED_RESCHED, %g0 - - be,pt %xcc, 1f - nop - call schedule - wrpr %g0, RTRAP_PSTATE, %pstate - wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate - ldx [%g6 + TI_FLAGS], %l0 - -1: andcc %l0, _TIF_DO_NOTIFY_RESUME_MASK, %g0 - be,pt %xcc, __handle_user_windows_continue - nop - mov %l5, %o1 - add %sp, PTREGS_OFF, %o0 - mov %l0, %o2 - - call do_notify_resume - wrpr %g0, RTRAP_PSTATE, %pstate - wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate - /* Signal delivery can modify pt_regs tstate, so we must - * reload it. - */ - ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1 - sethi %hi(0xf << 20), %l4 - and %l1, %l4, %l4 - ba,pt %xcc, __handle_user_windows_continue + ba,pt %xcc, __handle_preemption_continue + wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate - andn %l1, %l4, %l1 __handle_userfpu: rd %fprs, %l5 andcc %l5, FPRS_FEF, %g0 @@ -87,7 +59,7 @@ __handle_signal: ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1 sethi %hi(0xf << 20), %l4 and %l1, %l4, %l4 - ba,pt %xcc, __handle_signal_continue + ba,pt %xcc, __handle_preemption_continue andn %l1, %l4, %l1 /* When returning from a NMI (%pil==15) interrupt we want to @@ -177,11 +149,9 @@ __handle_preemption_continue: bne,pn %xcc, __handle_preemption andcc %l0, _TIF_DO_NOTIFY_RESUME_MASK, %g0 bne,pn %xcc, __handle_signal -__handle_signal_continue: ldub [%g6 + TI_WSAVED], %o2 brnz,pn %o2, __handle_user_windows nop -__handle_user_windows_continue: sethi %hi(TSTATE_PEF), %o0 andcc %l1, %o0, %g0 diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c index bd8601601afa..5b836f5aea90 100644 --- a/arch/sparc/mm/fault_32.c +++ b/arch/sparc/mm/fault_32.c @@ -539,6 +539,12 @@ do_sigbus: __do_fault_siginfo(BUS_ADRERR, SIGBUS, tsk->thread.kregs, address); } +static void check_stack_aligned(unsigned long sp) +{ + if (sp & 0x7UL) + force_sig(SIGILL, current); +} + void window_overflow_fault(void) { unsigned long sp; @@ -547,6 +553,8 @@ void window_overflow_fault(void) if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) force_user_fault(sp + 0x38, 1); force_user_fault(sp, 1); + + check_stack_aligned(sp); } void window_underflow_fault(unsigned long sp) @@ -554,6 +562,8 @@ void window_underflow_fault(unsigned long sp) if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) force_user_fault(sp + 0x38, 0); force_user_fault(sp, 0); + + check_stack_aligned(sp); } void window_ret_fault(struct pt_regs *regs) @@ -564,4 +574,6 @@ void window_ret_fault(struct pt_regs *regs) if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) force_user_fault(sp + 0x38, 0); force_user_fault(sp, 0); + + check_stack_aligned(sp); } diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index af0600143d1c..82bbb5967aa9 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -29,33 +29,33 @@ static struct vfsmount *dev_mnt; #if defined CONFIG_DEVTMPFS_MOUNT -static int dev_mount = 1; +static int mount_dev = 1; #else -static int dev_mount; +static int mount_dev; #endif static DEFINE_MUTEX(dirlock); static int __init mount_param(char *str) { - dev_mount = simple_strtoul(str, NULL, 0); + mount_dev = simple_strtoul(str, NULL, 0); return 1; } __setup("devtmpfs.mount=", mount_param); -static int dev_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *dev_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) { #ifdef CONFIG_TMPFS - return get_sb_single(fs_type, flags, data, shmem_fill_super, mnt); + return mount_single(fs_type, flags, data, shmem_fill_super); #else - return get_sb_single(fs_type, flags, data, ramfs_fill_super, mnt); + return mount_single(fs_type, flags, data, ramfs_fill_super); #endif } static struct file_system_type dev_fs_type = { .name = "devtmpfs", - .get_sb = dev_get_sb, + .mount = dev_mount, .kill_sb = kill_litter_super, }; @@ -351,7 +351,7 @@ int devtmpfs_mount(const char *mntdir) { int err; - if (!dev_mount) + if (!mount_dev) return 0; if (!dev_mnt) diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c index 97d98fbf5849..58c51cddc100 100644 --- a/drivers/ide/hpt366.c +++ b/drivers/ide/hpt366.c @@ -838,7 +838,7 @@ static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode) static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq) { - hpt3xxn_set_clock(drive->hwif, rq_data_dir(rq) ? 0x23 : 0x21); + hpt3xxn_set_clock(drive->hwif, rq_data_dir(rq) ? 0x21 : 0x23); } /** @@ -1173,8 +1173,9 @@ static u8 hpt3xx_cable_detect(ide_hwif_t *hwif) u16 mcr; pci_read_config_word(dev, mcr_addr, &mcr); - pci_write_config_word(dev, mcr_addr, (mcr | 0x8000)); - /* now read cable id register */ + pci_write_config_word(dev, mcr_addr, mcr | 0x8000); + /* Debounce, then read cable ID register */ + udelay(10); pci_read_config_byte(dev, 0x5a, &scr1); pci_write_config_word(dev, mcr_addr, mcr); } else if (chip_type >= HPT370) { @@ -1185,10 +1186,11 @@ static u8 hpt3xx_cable_detect(ide_hwif_t *hwif) u8 scr2 = 0; pci_read_config_byte(dev, 0x5b, &scr2); - pci_write_config_byte(dev, 0x5b, (scr2 & ~1)); - /* now read cable id register */ + pci_write_config_byte(dev, 0x5b, scr2 & ~1); + /* Debounce, then read cable ID register */ + udelay(10); pci_read_config_byte(dev, 0x5a, &scr1); - pci_write_config_byte(dev, 0x5b, scr2); + pci_write_config_byte(dev, 0x5b, scr2); } else pci_read_config_byte(dev, 0x5a, &scr1); diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 06b14bc9a1d4..d4136908f916 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -449,7 +449,6 @@ ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) ide_hwif_t *hwif = drive->hwif; const struct ide_dma_ops *dma_ops = hwif->dma_ops; struct ide_cmd *cmd = &hwif->cmd; - struct request *rq; ide_startstop_t ret = ide_stopped; /* @@ -487,14 +486,10 @@ ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) ide_dma_off_quietly(drive); /* - * un-busy drive etc and make sure request is sane + * make sure request is sane */ - rq = hwif->rq; - if (rq) { - hwif->rq = NULL; - rq->errors = 0; - ide_requeue_and_plug(drive, rq); - } + if (hwif->rq) + hwif->rq->errors = 0; return ret; } diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index 12d5bf76302c..8c8afc716b98 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -362,13 +362,13 @@ bail: return ret; } -static int ipathfs_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *ipathfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - int ret = get_sb_single(fs_type, flags, data, - ipathfs_fill_super, mnt); - if (ret >= 0) - ipath_super = mnt->mnt_sb; + struct dentry *ret; + ret = mount_single(fs_type, flags, data, ipathfs_fill_super); + if (!IS_ERR(ret)) + ipath_super = ret->d_sb; return ret; } @@ -411,7 +411,7 @@ bail: static struct file_system_type ipathfs_fs_type = { .owner = THIS_MODULE, .name = "ipathfs", - .get_sb = ipathfs_get_sb, + .mount = ipathfs_mount, .kill_sb = ipathfs_kill_super, }; diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c index 7e433d75c775..f99bddc01716 100644 --- a/drivers/infiniband/hw/qib/qib_fs.c +++ b/drivers/infiniband/hw/qib/qib_fs.c @@ -555,13 +555,13 @@ bail: return ret; } -static int qibfs_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *qibfs_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) { - int ret = get_sb_single(fs_type, flags, data, - qibfs_fill_super, mnt); - if (ret >= 0) - qib_super = mnt->mnt_sb; + struct dentry *ret; + ret = mount_single(fs_type, flags, data, qibfs_fill_super); + if (!IS_ERR(ret)) + qib_super = ret->d_sb; return ret; } @@ -603,7 +603,7 @@ int qibfs_remove(struct qib_devdata *dd) static struct file_system_type qibfs_fs_type = { .owner = THIS_MODULE, .name = "ipathfs", - .get_sb = qibfs_get_sb, + .mount = qibfs_mount, .kill_sb = qibfs_kill_super, }; diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c index 2b83850997c3..b4faed7fe0d3 100644 --- a/drivers/isdn/capi/capifs.c +++ b/drivers/isdn/capi/capifs.c @@ -125,16 +125,16 @@ fail: return -ENOMEM; } -static int capifs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *capifs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_single(fs_type, flags, data, capifs_fill_super, mnt); + return mount_single(fs_type, flags, data, capifs_fill_super); } static struct file_system_type capifs_fs_type = { .owner = THIS_MODULE, .name = "capifs", - .get_sb = capifs_get_sb, + .mount = capifs_mount, .kill_sb = kill_anon_super, }; diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index e4fb58db5454..5a1ffe3527aa 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -212,7 +212,7 @@ static struct page *read_sb_page(mddev_t *mddev, loff_t offset, target = rdev->sb_start + offset + index * (PAGE_SIZE/512); - if (sync_page_io(rdev->bdev, target, + if (sync_page_io(rdev, target, roundup(size, bdev_logical_block_size(rdev->bdev)), page, READ)) { page->index = index; @@ -343,7 +343,7 @@ static void write_page(struct bitmap *bitmap, struct page *page, int wait) atomic_inc(&bitmap->pending_writes); set_buffer_locked(bh); set_buffer_mapped(bh); - submit_bh(WRITE, bh); + submit_bh(WRITE | REQ_UNPLUG | REQ_SYNC, bh); bh = bh->b_this_page; } @@ -1101,7 +1101,7 @@ static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc) bitmap_checkfree(bitmap, page); } static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, - sector_t offset, int *blocks, + sector_t offset, sector_t *blocks, int create); /* @@ -1115,7 +1115,7 @@ void bitmap_daemon_work(mddev_t *mddev) unsigned long j; unsigned long flags; struct page *page = NULL, *lastpage = NULL; - int blocks; + sector_t blocks; void *paddr; struct dm_dirty_log *log = mddev->bitmap_info.log; @@ -1258,7 +1258,7 @@ void bitmap_daemon_work(mddev_t *mddev) } static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, - sector_t offset, int *blocks, + sector_t offset, sector_t *blocks, int create) __releases(bitmap->lock) __acquires(bitmap->lock) @@ -1316,7 +1316,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect } while (sectors) { - int blocks; + sector_t blocks; bitmap_counter_t *bmc; spin_lock_irq(&bitmap->lock); @@ -1381,7 +1381,7 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto success = 0; while (sectors) { - int blocks; + sector_t blocks; unsigned long flags; bitmap_counter_t *bmc; @@ -1423,7 +1423,7 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto } EXPORT_SYMBOL(bitmap_endwrite); -static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, +static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, int degraded) { bitmap_counter_t *bmc; @@ -1452,7 +1452,7 @@ static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *bloc return rv; } -int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, +int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, int degraded) { /* bitmap_start_sync must always report on multiples of whole @@ -1463,7 +1463,7 @@ int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, * Return the 'or' of the result. */ int rv = 0; - int blocks1; + sector_t blocks1; *blocks = 0; while (*blocks < (PAGE_SIZE>>9)) { @@ -1476,7 +1476,7 @@ int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, } EXPORT_SYMBOL(bitmap_start_sync); -void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted) +void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, int aborted) { bitmap_counter_t *bmc; unsigned long flags; @@ -1515,7 +1515,7 @@ void bitmap_close_sync(struct bitmap *bitmap) * RESYNC bit wherever it is still on */ sector_t sector = 0; - int blocks; + sector_t blocks; if (!bitmap) return; while (sector < bitmap->mddev->resync_max_sectors) { @@ -1528,7 +1528,7 @@ EXPORT_SYMBOL(bitmap_close_sync); void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector) { sector_t s = 0; - int blocks; + sector_t blocks; if (!bitmap) return; @@ -1562,7 +1562,7 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int n * be 0 at this point */ - int secs; + sector_t secs; bitmap_counter_t *bmc; spin_lock_irq(&bitmap->lock); bmc = bitmap_get_counter(bitmap, offset, &secs, 1); @@ -1790,7 +1790,7 @@ int bitmap_load(mddev_t *mddev) * All chunks should be clean, but some might need_sync. */ while (sector < mddev->resync_max_sectors) { - int blocks; + sector_t blocks; bitmap_start_sync(bitmap, sector, &blocks, 0); sector += blocks; } diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h index e872a7bad6b8..931a7a7c3796 100644 --- a/drivers/md/bitmap.h +++ b/drivers/md/bitmap.h @@ -271,8 +271,8 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors, int behind); void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors, int success, int behind); -int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int degraded); -void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted); +int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, int degraded); +void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, int aborted); void bitmap_close_sync(struct bitmap *bitmap); void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector); diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c index 1a8987884614..339fdc670751 100644 --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -210,7 +210,7 @@ static int make_request(mddev_t *mddev, struct bio *bio) } } if (failit) { - struct bio *b = bio_clone(bio, GFP_NOIO); + struct bio *b = bio_clone_mddev(bio, GFP_NOIO, mddev); b->bi_bdev = conf->rdev->bdev; b->bi_private = bio; b->bi_end_io = faulty_fail; diff --git a/drivers/md/md.c b/drivers/md/md.c index 225815197a3d..4e957f3140a8 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -57,8 +57,6 @@ #define DEBUG 0 #define dprintk(x...) ((void)(DEBUG && printk(x))) -static DEFINE_MUTEX(md_mutex); - #ifndef MODULE static void autostart_arrays(int part); #endif @@ -69,6 +67,8 @@ static DEFINE_SPINLOCK(pers_lock); static void md_print_devices(void); static DECLARE_WAIT_QUEUE_HEAD(resync_wait); +static struct workqueue_struct *md_wq; +static struct workqueue_struct *md_misc_wq; #define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); } @@ -149,6 +149,72 @@ static const struct block_device_operations md_fops; static int start_readonly; +/* bio_clone_mddev + * like bio_clone, but with a local bio set + */ + +static void mddev_bio_destructor(struct bio *bio) +{ + mddev_t *mddev, **mddevp; + + mddevp = (void*)bio; + mddev = mddevp[-1]; + + bio_free(bio, mddev->bio_set); +} + +struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs, + mddev_t *mddev) +{ + struct bio *b; + mddev_t **mddevp; + + if (!mddev || !mddev->bio_set) + return bio_alloc(gfp_mask, nr_iovecs); + + b = bio_alloc_bioset(gfp_mask, nr_iovecs, + mddev->bio_set); + if (!b) + return NULL; + mddevp = (void*)b; + mddevp[-1] = mddev; + b->bi_destructor = mddev_bio_destructor; + return b; +} +EXPORT_SYMBOL_GPL(bio_alloc_mddev); + +struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask, + mddev_t *mddev) +{ + struct bio *b; + mddev_t **mddevp; + + if (!mddev || !mddev->bio_set) + return bio_clone(bio, gfp_mask); + + b = bio_alloc_bioset(gfp_mask, bio->bi_max_vecs, + mddev->bio_set); + if (!b) + return NULL; + mddevp = (void*)b; + mddevp[-1] = mddev; + b->bi_destructor = mddev_bio_destructor; + __bio_clone(b, bio); + if (bio_integrity(bio)) { + int ret; + + ret = bio_integrity_clone(b, bio, gfp_mask, mddev->bio_set); + + if (ret < 0) { + bio_put(b); + return NULL; + } + } + + return b; +} +EXPORT_SYMBOL_GPL(bio_clone_mddev); + /* * We have a system wide 'event count' that is incremented * on any 'interesting' event, and readers of /proc/mdstat @@ -300,7 +366,7 @@ static void md_end_flush(struct bio *bio, int err) if (atomic_dec_and_test(&mddev->flush_pending)) { /* The pre-request flush has finished */ - schedule_work(&mddev->flush_work); + queue_work(md_wq, &mddev->flush_work); } bio_put(bio); } @@ -321,7 +387,7 @@ static void submit_flushes(mddev_t *mddev) atomic_inc(&rdev->nr_pending); atomic_inc(&rdev->nr_pending); rcu_read_unlock(); - bi = bio_alloc(GFP_KERNEL, 0); + bi = bio_alloc_mddev(GFP_KERNEL, 0, mddev); bi->bi_end_io = md_end_flush; bi->bi_private = rdev; bi->bi_bdev = rdev->bdev; @@ -369,7 +435,7 @@ void md_flush_request(mddev_t *mddev, struct bio *bio) submit_flushes(mddev); if (atomic_dec_and_test(&mddev->flush_pending)) - schedule_work(&mddev->flush_work); + queue_work(md_wq, &mddev->flush_work); } EXPORT_SYMBOL(md_flush_request); @@ -428,6 +494,8 @@ static void mddev_delayed_delete(struct work_struct *ws); static void mddev_put(mddev_t *mddev) { + struct bio_set *bs = NULL; + if (!atomic_dec_and_lock(&mddev->active, &all_mddevs_lock)) return; if (!mddev->raid_disks && list_empty(&mddev->disks) && @@ -435,19 +503,22 @@ static void mddev_put(mddev_t *mddev) /* Array is not configured at all, and not held active, * so destroy it */ list_del(&mddev->all_mddevs); + bs = mddev->bio_set; + mddev->bio_set = NULL; if (mddev->gendisk) { - /* we did a probe so need to clean up. - * Call schedule_work inside the spinlock - * so that flush_scheduled_work() after - * mddev_find will succeed in waiting for the - * work to be done. + /* We did a probe so need to clean up. Call + * queue_work inside the spinlock so that + * flush_workqueue() after mddev_find will + * succeed in waiting for the work to be done. */ INIT_WORK(&mddev->del_work, mddev_delayed_delete); - schedule_work(&mddev->del_work); + queue_work(md_misc_wq, &mddev->del_work); } else kfree(mddev); } spin_unlock(&all_mddevs_lock); + if (bs) + bioset_free(bs); } void mddev_init(mddev_t *mddev) @@ -691,7 +762,7 @@ void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, * if zero is reached. * If an error occurred, call md_error */ - struct bio *bio = bio_alloc(GFP_NOIO, 1); + struct bio *bio = bio_alloc_mddev(GFP_NOIO, 1, mddev); bio->bi_bdev = rdev->bdev; bio->bi_sector = sector; @@ -722,16 +793,16 @@ static void bi_complete(struct bio *bio, int error) complete((struct completion*)bio->bi_private); } -int sync_page_io(struct block_device *bdev, sector_t sector, int size, - struct page *page, int rw) +int sync_page_io(mdk_rdev_t *rdev, sector_t sector, int size, + struct page *page, int rw) { - struct bio *bio = bio_alloc(GFP_NOIO, 1); + struct bio *bio = bio_alloc_mddev(GFP_NOIO, 1, rdev->mddev); struct completion event; int ret; rw |= REQ_SYNC | REQ_UNPLUG; - bio->bi_bdev = bdev; + bio->bi_bdev = rdev->bdev; bio->bi_sector = sector; bio_add_page(bio, page, size, 0); init_completion(&event); @@ -757,7 +828,7 @@ static int read_disk_sb(mdk_rdev_t * rdev, int size) return 0; - if (!sync_page_io(rdev->bdev, rdev->sb_start, size, rdev->sb_page, READ)) + if (!sync_page_io(rdev, rdev->sb_start, size, rdev->sb_page, READ)) goto fail; rdev->sb_loaded = 1; return 0; @@ -1850,7 +1921,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev) synchronize_rcu(); INIT_WORK(&rdev->del_work, md_delayed_delete); kobject_get(&rdev->kobj); - schedule_work(&rdev->del_work); + queue_work(md_misc_wq, &rdev->del_work); } /* @@ -2108,6 +2179,8 @@ repeat: if (!mddev->persistent) { clear_bit(MD_CHANGE_CLEAN, &mddev->flags); clear_bit(MD_CHANGE_DEVS, &mddev->flags); + if (!mddev->external) + clear_bit(MD_CHANGE_PENDING, &mddev->flags); wake_up(&mddev->sb_wait); return; } @@ -4192,10 +4265,10 @@ static int md_alloc(dev_t dev, char *name) shift = partitioned ? MdpMinorShift : 0; unit = MINOR(mddev->unit) >> shift; - /* wait for any previous instance if this device - * to be completed removed (mddev_delayed_delete). + /* wait for any previous instance of this device to be + * completely removed (mddev_delayed_delete). */ - flush_scheduled_work(); + flush_workqueue(md_misc_wq); mutex_lock(&disks_mutex); error = -EEXIST; @@ -4378,6 +4451,9 @@ int md_run(mddev_t *mddev) sysfs_notify_dirent_safe(rdev->sysfs_state); } + if (mddev->bio_set == NULL) + mddev->bio_set = bioset_create(BIO_POOL_SIZE, sizeof(mddev)); + spin_lock(&pers_lock); pers = find_pers(mddev->level, mddev->clevel); if (!pers || !try_module_get(pers->owner)) { @@ -5885,16 +5961,14 @@ static int md_open(struct block_device *bdev, fmode_t mode) mddev_t *mddev = mddev_find(bdev->bd_dev); int err; - mutex_lock(&md_mutex); if (mddev->gendisk != bdev->bd_disk) { /* we are racing with mddev_put which is discarding this * bd_disk. */ mddev_put(mddev); /* Wait until bdev->bd_disk is definitely gone */ - flush_scheduled_work(); + flush_workqueue(md_misc_wq); /* Then retry the open from the top */ - mutex_unlock(&md_mutex); return -ERESTARTSYS; } BUG_ON(mddev != bdev->bd_disk->private_data); @@ -5908,7 +5982,6 @@ static int md_open(struct block_device *bdev, fmode_t mode) check_disk_size_change(mddev->gendisk, bdev); out: - mutex_unlock(&md_mutex); return err; } @@ -5917,10 +5990,8 @@ static int md_release(struct gendisk *disk, fmode_t mode) mddev_t *mddev = disk->private_data; BUG_ON(!mddev); - mutex_lock(&md_mutex); atomic_dec(&mddev->openers); mddev_put(mddev); - mutex_unlock(&md_mutex); return 0; } @@ -6052,7 +6123,7 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev) set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); if (mddev->event_work.func) - schedule_work(&mddev->event_work); + queue_work(md_misc_wq, &mddev->event_work); md_new_event_inintr(mddev); } @@ -7212,12 +7283,23 @@ static void md_geninit(void) static int __init md_init(void) { - if (register_blkdev(MD_MAJOR, "md")) - return -1; - if ((mdp_major=register_blkdev(0, "mdp"))<=0) { - unregister_blkdev(MD_MAJOR, "md"); - return -1; - } + int ret = -ENOMEM; + + md_wq = alloc_workqueue("md", WQ_RESCUER, 0); + if (!md_wq) + goto err_wq; + + md_misc_wq = alloc_workqueue("md_misc", 0, 0); + if (!md_misc_wq) + goto err_misc_wq; + + if ((ret = register_blkdev(MD_MAJOR, "md")) < 0) + goto err_md; + + if ((ret = register_blkdev(0, "mdp")) < 0) + goto err_mdp; + mdp_major = ret; + blk_register_region(MKDEV(MD_MAJOR, 0), 1UL<<MINORBITS, THIS_MODULE, md_probe, NULL, NULL); blk_register_region(MKDEV(mdp_major, 0), 1UL<<MINORBITS, THIS_MODULE, @@ -7228,8 +7310,16 @@ static int __init md_init(void) md_geninit(); return 0; -} +err_mdp: + unregister_blkdev(MD_MAJOR, "md"); +err_md: + destroy_workqueue(md_misc_wq); +err_misc_wq: + destroy_workqueue(md_wq); +err_wq: + return ret; +} #ifndef MODULE @@ -7316,6 +7406,8 @@ static __exit void md_exit(void) export_array(mddev); mddev->hold_active = 0; } + destroy_workqueue(md_misc_wq); + destroy_workqueue(md_wq); } subsys_initcall(md_init); diff --git a/drivers/md/md.h b/drivers/md/md.h index 112a2c32db0c..d05bab55df4e 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -331,6 +331,8 @@ struct mddev_s struct attribute_group *to_remove; struct plug_handle *plug; /* if used by personality */ + struct bio_set *bio_set; + /* Generic flush handling. * The last to finish preflush schedules a worker to submit * the rest of the request (without the REQ_FLUSH flag). @@ -495,7 +497,7 @@ extern void md_flush_request(mddev_t *mddev, struct bio *bio); extern void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, sector_t sector, int size, struct page *page); extern void md_super_wait(mddev_t *mddev); -extern int sync_page_io(struct block_device *bdev, sector_t sector, int size, +extern int sync_page_io(mdk_rdev_t *rdev, sector_t sector, int size, struct page *page, int rw); extern void md_do_sync(mddev_t *mddev); extern void md_new_event(mddev_t *mddev); @@ -517,4 +519,8 @@ extern void md_rdev_init(mdk_rdev_t *rdev); extern void mddev_suspend(mddev_t *mddev); extern void mddev_resume(mddev_t *mddev); +extern struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask, + mddev_t *mddev); +extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs, + mddev_t *mddev); #endif /* _MD_MD_H */ diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 378a25894c57..45f8324196ec 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -100,7 +100,7 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data) * Allocate bios : 1 for reading, n-1 for writing */ for (j = pi->raid_disks ; j-- ; ) { - bio = bio_alloc(gfp_flags, RESYNC_PAGES); + bio = bio_kmalloc(gfp_flags, RESYNC_PAGES); if (!bio) goto out_free_bio; r1_bio->bios[j] = bio; @@ -306,6 +306,28 @@ static void raid1_end_read_request(struct bio *bio, int error) rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev); } +static void r1_bio_write_done(r1bio_t *r1_bio, int vcnt, struct bio_vec *bv, + int behind) +{ + if (atomic_dec_and_test(&r1_bio->remaining)) + { + /* it really is the end of this request */ + if (test_bit(R1BIO_BehindIO, &r1_bio->state)) { + /* free extra copy of the data pages */ + int i = vcnt; + while (i--) + safe_put_page(bv[i].bv_page); + } + /* clear the bitmap if all writes complete successfully */ + bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector, + r1_bio->sectors, + !test_bit(R1BIO_Degraded, &r1_bio->state), + behind); + md_write_end(r1_bio->mddev); + raid_end_bio_io(r1_bio); + } +} + static void raid1_end_write_request(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); @@ -373,21 +395,7 @@ static void raid1_end_write_request(struct bio *bio, int error) * Let's see if all mirrored write operations have finished * already. */ - if (atomic_dec_and_test(&r1_bio->remaining)) { - if (test_bit(R1BIO_BehindIO, &r1_bio->state)) { - /* free extra copy of the data pages */ - int i = bio->bi_vcnt; - while (i--) - safe_put_page(bio->bi_io_vec[i].bv_page); - } - /* clear the bitmap if all writes complete successfully */ - bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector, - r1_bio->sectors, - !test_bit(R1BIO_Degraded, &r1_bio->state), - behind); - md_write_end(r1_bio->mddev); - raid_end_bio_io(r1_bio); - } + r1_bio_write_done(r1_bio, bio->bi_vcnt, bio->bi_io_vec, behind); if (to_put) bio_put(to_put); @@ -411,11 +419,13 @@ static void raid1_end_write_request(struct bio *bio, int error) static int read_balance(conf_t *conf, r1bio_t *r1_bio) { const sector_t this_sector = r1_bio->sector; - int new_disk = conf->last_used, disk = new_disk; - int wonly_disk = -1; const int sectors = r1_bio->sectors; + int new_disk = -1; + int start_disk; + int i; sector_t new_distance, current_distance; mdk_rdev_t *rdev; + int choose_first; rcu_read_lock(); /* @@ -426,54 +436,33 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) retry: if (conf->mddev->recovery_cp < MaxSector && (this_sector + sectors >= conf->next_resync)) { - /* Choose the first operational device, for consistancy */ - new_disk = 0; - - for (rdev = rcu_dereference(conf->mirrors[new_disk].rdev); - r1_bio->bios[new_disk] == IO_BLOCKED || - !rdev || !test_bit(In_sync, &rdev->flags) - || test_bit(WriteMostly, &rdev->flags); - rdev = rcu_dereference(conf->mirrors[++new_disk].rdev)) { - - if (rdev && test_bit(In_sync, &rdev->flags) && - r1_bio->bios[new_disk] != IO_BLOCKED) - wonly_disk = new_disk; - - if (new_disk == conf->raid_disks - 1) { - new_disk = wonly_disk; - break; - } - } - goto rb_out; + choose_first = 1; + start_disk = 0; + } else { + choose_first = 0; + start_disk = conf->last_used; } - /* make sure the disk is operational */ - for (rdev = rcu_dereference(conf->mirrors[new_disk].rdev); - r1_bio->bios[new_disk] == IO_BLOCKED || - !rdev || !test_bit(In_sync, &rdev->flags) || - test_bit(WriteMostly, &rdev->flags); - rdev = rcu_dereference(conf->mirrors[new_disk].rdev)) { - - if (rdev && test_bit(In_sync, &rdev->flags) && - r1_bio->bios[new_disk] != IO_BLOCKED) - wonly_disk = new_disk; - - if (new_disk <= 0) - new_disk = conf->raid_disks; - new_disk--; - if (new_disk == disk) { - new_disk = wonly_disk; + for (i = 0 ; i < conf->raid_disks ; i++) { + int disk = start_disk + i; + if (disk >= conf->raid_disks) + disk -= conf->raid_disks; + + rdev = rcu_dereference(conf->mirrors[disk].rdev); + if (r1_bio->bios[disk] == IO_BLOCKED + || rdev == NULL + || !test_bit(In_sync, &rdev->flags)) + continue; + + new_disk = disk; + if (!test_bit(WriteMostly, &rdev->flags)) break; - } } - if (new_disk < 0) + if (new_disk < 0 || choose_first) goto rb_out; - disk = new_disk; - /* now disk == new_disk == starting point for search */ - /* * Don't change to another disk for sequential reads: */ @@ -482,20 +471,21 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) if (this_sector == conf->mirrors[new_disk].head_position) goto rb_out; - current_distance = abs(this_sector - conf->mirrors[disk].head_position); - - /* Find the disk whose head is closest */ + current_distance = abs(this_sector + - conf->mirrors[new_disk].head_position); - do { - if (disk <= 0) - disk = conf->raid_disks; - disk--; + /* look for a better disk - i.e. head is closer */ + start_disk = new_disk; + for (i = 1; i < conf->raid_disks; i++) { + int disk = start_disk + 1; + if (disk >= conf->raid_disks) + disk -= conf->raid_disks; rdev = rcu_dereference(conf->mirrors[disk].rdev); - - if (!rdev || r1_bio->bios[disk] == IO_BLOCKED || - !test_bit(In_sync, &rdev->flags) || - test_bit(WriteMostly, &rdev->flags)) + if (r1_bio->bios[disk] == IO_BLOCKED + || rdev == NULL + || !test_bit(In_sync, &rdev->flags) + || test_bit(WriteMostly, &rdev->flags)) continue; if (!atomic_read(&rdev->nr_pending)) { @@ -507,11 +497,9 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) current_distance = new_distance; new_disk = disk; } - } while (disk != conf->last_used); + } rb_out: - - if (new_disk >= 0) { rdev = rcu_dereference(conf->mirrors[new_disk].rdev); if (!rdev) @@ -658,7 +646,7 @@ static void raise_barrier(conf_t *conf) /* block any new IO from starting */ conf->barrier++; - /* No wait for all pending IO to complete */ + /* Now wait for all pending IO to complete */ wait_event_lock_irq(conf->wait_barrier, !conf->nr_pending && conf->barrier < RESYNC_DEPTH, conf->resync_lock, @@ -735,23 +723,26 @@ static void unfreeze_array(conf_t *conf) } -/* duplicate the data pages for behind I/O */ -static struct page **alloc_behind_pages(struct bio *bio) +/* duplicate the data pages for behind I/O + * We return a list of bio_vec rather than just page pointers + * as it makes freeing easier + */ +static struct bio_vec *alloc_behind_pages(struct bio *bio) { int i; struct bio_vec *bvec; - struct page **pages = kzalloc(bio->bi_vcnt * sizeof(struct page *), + struct bio_vec *pages = kzalloc(bio->bi_vcnt * sizeof(struct bio_vec), GFP_NOIO); if (unlikely(!pages)) goto do_sync_io; bio_for_each_segment(bvec, bio, i) { - pages[i] = alloc_page(GFP_NOIO); - if (unlikely(!pages[i])) + pages[i].bv_page = alloc_page(GFP_NOIO); + if (unlikely(!pages[i].bv_page)) goto do_sync_io; - memcpy(kmap(pages[i]) + bvec->bv_offset, + memcpy(kmap(pages[i].bv_page) + bvec->bv_offset, kmap(bvec->bv_page) + bvec->bv_offset, bvec->bv_len); - kunmap(pages[i]); + kunmap(pages[i].bv_page); kunmap(bvec->bv_page); } @@ -759,8 +750,8 @@ static struct page **alloc_behind_pages(struct bio *bio) do_sync_io: if (pages) - for (i = 0; i < bio->bi_vcnt && pages[i]; i++) - put_page(pages[i]); + for (i = 0; i < bio->bi_vcnt && pages[i].bv_page; i++) + put_page(pages[i].bv_page); kfree(pages); PRINTK("%dB behind alloc failed, doing sync I/O\n", bio->bi_size); return NULL; @@ -775,8 +766,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) int i, targets = 0, disks; struct bitmap *bitmap; unsigned long flags; - struct bio_list bl; - struct page **behind_pages = NULL; + struct bio_vec *behind_pages = NULL; const int rw = bio_data_dir(bio); const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA)); @@ -851,7 +841,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) } r1_bio->read_disk = rdisk; - read_bio = bio_clone(bio, GFP_NOIO); + read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev); r1_bio->bios[rdisk] = read_bio; @@ -873,13 +863,6 @@ static int make_request(mddev_t *mddev, struct bio * bio) * bios[x] to bio */ disks = conf->raid_disks; -#if 0 - { static int first=1; - if (first) printk("First Write sector %llu disks %d\n", - (unsigned long long)r1_bio->sector, disks); - first = 0; - } -#endif retry_write: blocked_rdev = NULL; rcu_read_lock(); @@ -937,16 +920,17 @@ static int make_request(mddev_t *mddev, struct bio * bio) (behind_pages = alloc_behind_pages(bio)) != NULL) set_bit(R1BIO_BehindIO, &r1_bio->state); - atomic_set(&r1_bio->remaining, 0); + atomic_set(&r1_bio->remaining, 1); atomic_set(&r1_bio->behind_remaining, 0); - bio_list_init(&bl); + bitmap_startwrite(bitmap, bio->bi_sector, r1_bio->sectors, + test_bit(R1BIO_BehindIO, &r1_bio->state)); for (i = 0; i < disks; i++) { struct bio *mbio; if (!r1_bio->bios[i]) continue; - mbio = bio_clone(bio, GFP_NOIO); + mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); r1_bio->bios[i] = mbio; mbio->bi_sector = r1_bio->sector + conf->mirrors[i].rdev->data_offset; @@ -963,39 +947,29 @@ static int make_request(mddev_t *mddev, struct bio * bio) * we clear any unused pointer in the io_vec, rather * than leave them unchanged. This is important * because when we come to free the pages, we won't - * know the originial bi_idx, so we just free + * know the original bi_idx, so we just free * them all */ __bio_for_each_segment(bvec, mbio, j, 0) - bvec->bv_page = behind_pages[j]; + bvec->bv_page = behind_pages[j].bv_page; if (test_bit(WriteMostly, &conf->mirrors[i].rdev->flags)) atomic_inc(&r1_bio->behind_remaining); } atomic_inc(&r1_bio->remaining); - - bio_list_add(&bl, mbio); + spin_lock_irqsave(&conf->device_lock, flags); + bio_list_add(&conf->pending_bio_list, mbio); + blk_plug_device(mddev->queue); + spin_unlock_irqrestore(&conf->device_lock, flags); } + r1_bio_write_done(r1_bio, bio->bi_vcnt, behind_pages, behind_pages != NULL); kfree(behind_pages); /* the behind pages are attached to the bios now */ - bitmap_startwrite(bitmap, bio->bi_sector, r1_bio->sectors, - test_bit(R1BIO_BehindIO, &r1_bio->state)); - spin_lock_irqsave(&conf->device_lock, flags); - bio_list_merge(&conf->pending_bio_list, &bl); - bio_list_init(&bl); - - blk_plug_device(mddev->queue); - spin_unlock_irqrestore(&conf->device_lock, flags); - - /* In case raid1d snuck into freeze_array */ + /* In case raid1d snuck in to freeze_array */ wake_up(&conf->wait_barrier); if (do_sync) md_wakeup_thread(mddev->thread); -#if 0 - while ((bio = bio_list_pop(&bl)) != NULL) - generic_make_request(bio); -#endif return 0; } @@ -1183,7 +1157,7 @@ static int raid1_remove_disk(mddev_t *mddev, int number) err = -EBUSY; goto abort; } - /* Only remove non-faulty devices is recovery + /* Only remove non-faulty devices if recovery * is not possible. */ if (!test_bit(Faulty, &rdev->flags) && @@ -1245,7 +1219,7 @@ static void end_sync_write(struct bio *bio, int error) break; } if (!uptodate) { - int sync_blocks = 0; + sector_t sync_blocks = 0; sector_t s = r1_bio->sector; long sectors_to_go = r1_bio->sectors; /* make sure these bits doesn't get cleared. */ @@ -1388,7 +1362,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) * active, and resync is currently active */ rdev = conf->mirrors[d].rdev; - if (sync_page_io(rdev->bdev, + if (sync_page_io(rdev, sect + rdev->data_offset, s<<9, bio->bi_io_vec[idx].bv_page, @@ -1414,7 +1388,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) continue; rdev = conf->mirrors[d].rdev; atomic_add(s, &rdev->corrected_errors); - if (sync_page_io(rdev->bdev, + if (sync_page_io(rdev, sect + rdev->data_offset, s<<9, bio->bi_io_vec[idx].bv_page, @@ -1429,7 +1403,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) if (r1_bio->bios[d]->bi_end_io != end_sync_read) continue; rdev = conf->mirrors[d].rdev; - if (sync_page_io(rdev->bdev, + if (sync_page_io(rdev, sect + rdev->data_offset, s<<9, bio->bi_io_vec[idx].bv_page, @@ -1513,7 +1487,7 @@ static void fix_read_error(conf_t *conf, int read_disk, rdev = conf->mirrors[d].rdev; if (rdev && test_bit(In_sync, &rdev->flags) && - sync_page_io(rdev->bdev, + sync_page_io(rdev, sect + rdev->data_offset, s<<9, conf->tmppage, READ)) @@ -1539,7 +1513,7 @@ static void fix_read_error(conf_t *conf, int read_disk, rdev = conf->mirrors[d].rdev; if (rdev && test_bit(In_sync, &rdev->flags)) { - if (sync_page_io(rdev->bdev, + if (sync_page_io(rdev, sect + rdev->data_offset, s<<9, conf->tmppage, WRITE) == 0) @@ -1556,7 +1530,7 @@ static void fix_read_error(conf_t *conf, int read_disk, rdev = conf->mirrors[d].rdev; if (rdev && test_bit(In_sync, &rdev->flags)) { - if (sync_page_io(rdev->bdev, + if (sync_page_io(rdev, sect + rdev->data_offset, s<<9, conf->tmppage, READ) == 0) @@ -1646,7 +1620,8 @@ static void raid1d(mddev_t *mddev) mddev->ro ? IO_BLOCKED : NULL; r1_bio->read_disk = disk; bio_put(bio); - bio = bio_clone(r1_bio->master_bio, GFP_NOIO); + bio = bio_clone_mddev(r1_bio->master_bio, + GFP_NOIO, mddev); r1_bio->bios[r1_bio->read_disk] = bio; rdev = conf->mirrors[disk].rdev; if (printk_ratelimit()) @@ -1705,7 +1680,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i int i; int wonly = -1; int write_targets = 0, read_targets = 0; - int sync_blocks; + sector_t sync_blocks; int still_degraded = 0; if (!conf->r1buf_pool) @@ -1755,11 +1730,11 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i msleep_interruptible(1000); bitmap_cond_end_sync(mddev->bitmap, sector_nr); + r1_bio = mempool_alloc(conf->r1buf_pool, GFP_NOIO); raise_barrier(conf); conf->next_resync = sector_nr; - r1_bio = mempool_alloc(conf->r1buf_pool, GFP_NOIO); rcu_read_lock(); /* * If we get a correctably read error during resync or recovery, @@ -1971,7 +1946,6 @@ static conf_t *setup_conf(mddev_t *mddev) init_waitqueue_head(&conf->wait_barrier); bio_list_init(&conf->pending_bio_list); - bio_list_init(&conf->flushing_bio_list); conf->last_used = -1; for (i = 0; i < conf->raid_disks; i++) { diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h index adf8cfd73313..cbfdf1a6acd9 100644 --- a/drivers/md/raid1.h +++ b/drivers/md/raid1.h @@ -35,8 +35,6 @@ struct r1_private_data_s { struct list_head retry_list; /* queue pending writes and submit them on unplug */ struct bio_list pending_bio_list; - /* queue of writes that have been unplugged */ - struct bio_list flushing_bio_list; /* for use when syncing mirrors: */ diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index f0d082f749be..c67aa54694ae 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -120,7 +120,7 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data) * Allocate bios. */ for (j = nalloc ; j-- ; ) { - bio = bio_alloc(gfp_flags, RESYNC_PAGES); + bio = bio_kmalloc(gfp_flags, RESYNC_PAGES); if (!bio) goto out_free_bio; r10_bio->devs[j].bio = bio; @@ -801,7 +801,6 @@ static int make_request(mddev_t *mddev, struct bio * bio) const int rw = bio_data_dir(bio); const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); const unsigned long do_fua = (bio->bi_rw & REQ_FUA); - struct bio_list bl; unsigned long flags; mdk_rdev_t *blocked_rdev; @@ -890,7 +889,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) } mirror = conf->mirrors + disk; - read_bio = bio_clone(bio, GFP_NOIO); + read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev); r10_bio->devs[slot].bio = read_bio; @@ -950,16 +949,16 @@ static int make_request(mddev_t *mddev, struct bio * bio) goto retry_write; } - atomic_set(&r10_bio->remaining, 0); + atomic_set(&r10_bio->remaining, 1); + bitmap_startwrite(mddev->bitmap, bio->bi_sector, r10_bio->sectors, 0); - bio_list_init(&bl); for (i = 0; i < conf->copies; i++) { struct bio *mbio; int d = r10_bio->devs[i].devnum; if (!r10_bio->devs[i].bio) continue; - mbio = bio_clone(bio, GFP_NOIO); + mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); r10_bio->devs[i].bio = mbio; mbio->bi_sector = r10_bio->devs[i].addr+ @@ -970,22 +969,22 @@ static int make_request(mddev_t *mddev, struct bio * bio) mbio->bi_private = r10_bio; atomic_inc(&r10_bio->remaining); - bio_list_add(&bl, mbio); + spin_lock_irqsave(&conf->device_lock, flags); + bio_list_add(&conf->pending_bio_list, mbio); + blk_plug_device(mddev->queue); + spin_unlock_irqrestore(&conf->device_lock, flags); } - if (unlikely(!atomic_read(&r10_bio->remaining))) { - /* the array is dead */ + if (atomic_dec_and_test(&r10_bio->remaining)) { + /* This matches the end of raid10_end_write_request() */ + bitmap_endwrite(r10_bio->mddev->bitmap, r10_bio->sector, + r10_bio->sectors, + !test_bit(R10BIO_Degraded, &r10_bio->state), + 0); md_write_end(mddev); raid_end_bio_io(r10_bio); - return 0; } - bitmap_startwrite(mddev->bitmap, bio->bi_sector, r10_bio->sectors, 0); - spin_lock_irqsave(&conf->device_lock, flags); - bio_list_merge(&conf->pending_bio_list, &bl); - blk_plug_device(mddev->queue); - spin_unlock_irqrestore(&conf->device_lock, flags); - /* In case raid10d snuck in to freeze_array */ wake_up(&conf->wait_barrier); @@ -1558,7 +1557,7 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio) test_bit(In_sync, &rdev->flags)) { atomic_inc(&rdev->nr_pending); rcu_read_unlock(); - success = sync_page_io(rdev->bdev, + success = sync_page_io(rdev, r10_bio->devs[sl].addr + sect + rdev->data_offset, s<<9, @@ -1597,7 +1596,7 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio) atomic_inc(&rdev->nr_pending); rcu_read_unlock(); atomic_add(s, &rdev->corrected_errors); - if (sync_page_io(rdev->bdev, + if (sync_page_io(rdev, r10_bio->devs[sl].addr + sect + rdev->data_offset, s<<9, conf->tmppage, WRITE) @@ -1634,7 +1633,7 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio) char b[BDEVNAME_SIZE]; atomic_inc(&rdev->nr_pending); rcu_read_unlock(); - if (sync_page_io(rdev->bdev, + if (sync_page_io(rdev, r10_bio->devs[sl].addr + sect + rdev->data_offset, s<<9, conf->tmppage, @@ -1747,7 +1746,8 @@ static void raid10d(mddev_t *mddev) mdname(mddev), bdevname(rdev->bdev,b), (unsigned long long)r10_bio->sector); - bio = bio_clone(r10_bio->master_bio, GFP_NOIO); + bio = bio_clone_mddev(r10_bio->master_bio, + GFP_NOIO, mddev); r10_bio->devs[r10_bio->read_slot].bio = bio; bio->bi_sector = r10_bio->devs[r10_bio->read_slot].addr + rdev->data_offset; @@ -1820,7 +1820,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i int disk; int i; int max_sync; - int sync_blocks; + sector_t sync_blocks; sector_t sectors_skipped = 0; int chunks_skipped = 0; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 31140d1259dc..dc574f303f8b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3876,9 +3876,9 @@ static int chunk_aligned_read(mddev_t *mddev, struct bio * raid_bio) return 0; } /* - * use bio_clone to make a copy of the bio + * use bio_clone_mddev to make a copy of the bio */ - align_bi = bio_clone(raid_bio, GFP_NOIO); + align_bi = bio_clone_mddev(raid_bio, GFP_NOIO, mddev); if (!align_bi) return 0; /* @@ -4360,7 +4360,7 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski raid5_conf_t *conf = mddev->private; struct stripe_head *sh; sector_t max_sector = mddev->dev_sectors; - int sync_blocks; + sector_t sync_blocks; int still_degraded = 0; int i; diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index 0a53500636c9..d2d5d23416dd 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -91,11 +91,10 @@ static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root); static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent); -static int ibmasmfs_get_super(struct file_system_type *fst, - int flags, const char *name, void *data, - struct vfsmount *mnt) +static struct dentry *ibmasmfs_mount(struct file_system_type *fst, + int flags, const char *name, void *data) { - return get_sb_single(fst, flags, data, ibmasmfs_fill_super, mnt); + return mount_single(fst, flags, data, ibmasmfs_fill_super); } static const struct super_operations ibmasmfs_s_ops = { @@ -108,7 +107,7 @@ static const struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations; static struct file_system_type ibmasmfs_type = { .owner = THIS_MODULE, .name = "ibmasmfs", - .get_sb = ibmasmfs_get_super, + .mount = ibmasmfs_mount, .kill_sb = kill_litter_super, }; diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 5ef45487b65f..a34a0fe14884 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -1030,17 +1030,15 @@ static const struct file_operations mtd_fops = { #endif }; -static int mtd_inodefs_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, - struct vfsmount *mnt) +static struct dentry *mtd_inodefs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC, - mnt); + return mount_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC); } static struct file_system_type mtd_inodefs_type = { .name = "mtd_inodefs", - .get_sb = mtd_inodefs_get_sb, + .mount = mtd_inodefs_mount, .kill_sb = kill_anon_super, }; diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c index 38e2ab07e7a3..16b02a1fc100 100644 --- a/drivers/mtd/mtdsuper.c +++ b/drivers/mtd/mtdsuper.c @@ -54,11 +54,10 @@ static int get_sb_mtd_set(struct super_block *sb, void *_mtd) /* * get a superblock on an MTD-backed filesystem */ -static int get_sb_mtd_aux(struct file_system_type *fs_type, int flags, +static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct mtd_info *mtd, - int (*fill_super)(struct super_block *, void *, int), - struct vfsmount *mnt) + int (*fill_super)(struct super_block *, void *, int)) { struct super_block *sb; int ret; @@ -79,57 +78,49 @@ static int get_sb_mtd_aux(struct file_system_type *fs_type, int flags, ret = fill_super(sb, data, flags & MS_SILENT ? 1 : 0); if (ret < 0) { deactivate_locked_super(sb); - return ret; + return ERR_PTR(ret); } /* go */ sb->s_flags |= MS_ACTIVE; - simple_set_mnt(mnt, sb); - - return 0; + return dget(sb->s_root); /* new mountpoint for an already mounted superblock */ already_mounted: DEBUG(1, "MTDSB: Device %d (\"%s\") is already mounted\n", mtd->index, mtd->name); - simple_set_mnt(mnt, sb); - ret = 0; - goto out_put; + put_mtd_device(mtd); + return dget(sb->s_root); out_error: - ret = PTR_ERR(sb); -out_put: put_mtd_device(mtd); - return ret; + return ERR_CAST(sb); } /* * get a superblock on an MTD-backed filesystem by MTD device number */ -static int get_sb_mtd_nr(struct file_system_type *fs_type, int flags, +static struct dentry *mount_mtd_nr(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, int mtdnr, - int (*fill_super)(struct super_block *, void *, int), - struct vfsmount *mnt) + int (*fill_super)(struct super_block *, void *, int)) { struct mtd_info *mtd; mtd = get_mtd_device(NULL, mtdnr); if (IS_ERR(mtd)) { DEBUG(0, "MTDSB: Device #%u doesn't appear to exist\n", mtdnr); - return PTR_ERR(mtd); + return ERR_CAST(mtd); } - return get_sb_mtd_aux(fs_type, flags, dev_name, data, mtd, fill_super, - mnt); + return mount_mtd_aux(fs_type, flags, dev_name, data, mtd, fill_super); } /* * set up an MTD-based superblock */ -int get_sb_mtd(struct file_system_type *fs_type, int flags, +struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, - int (*fill_super)(struct super_block *, void *, int), - struct vfsmount *mnt) + int (*fill_super)(struct super_block *, void *, int)) { #ifdef CONFIG_BLOCK struct block_device *bdev; @@ -138,7 +129,7 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, int mtdnr; if (!dev_name) - return -EINVAL; + return ERR_PTR(-EINVAL); DEBUG(2, "MTDSB: dev_name \"%s\"\n", dev_name); @@ -156,10 +147,10 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, mtd = get_mtd_device_nm(dev_name + 4); if (!IS_ERR(mtd)) - return get_sb_mtd_aux( + return mount_mtd_aux( fs_type, flags, dev_name, data, mtd, - fill_super, mnt); + fill_super); printk(KERN_NOTICE "MTD:" " MTD device with name \"%s\" not found.\n", @@ -174,9 +165,9 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, /* It was a valid number */ DEBUG(1, "MTDSB: mtd%%d, mtdnr %d\n", mtdnr); - return get_sb_mtd_nr(fs_type, flags, + return mount_mtd_nr(fs_type, flags, dev_name, data, - mtdnr, fill_super, mnt); + mtdnr, fill_super); } } } @@ -189,7 +180,7 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, if (IS_ERR(bdev)) { ret = PTR_ERR(bdev); DEBUG(1, "MTDSB: lookup_bdev() returned %d\n", ret); - return ret; + return ERR_PTR(ret); } DEBUG(1, "MTDSB: lookup_bdev() returned 0\n"); @@ -202,8 +193,7 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, if (major != MTD_BLOCK_MAJOR) goto not_an_MTD_device; - return get_sb_mtd_nr(fs_type, flags, dev_name, data, mtdnr, fill_super, - mnt); + return mount_mtd_nr(fs_type, flags, dev_name, data, mtdnr, fill_super); not_an_MTD_device: #endif /* CONFIG_BLOCK */ @@ -212,10 +202,10 @@ not_an_MTD_device: printk(KERN_NOTICE "MTD: Attempt to mount non-MTD device \"%s\"\n", dev_name); - return -EINVAL; + return ERR_PTR(-EINVAL); } -EXPORT_SYMBOL_GPL(get_sb_mtd); +EXPORT_SYMBOL_GPL(mount_mtd); /* * destroy an MTD-based superblock diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index 449de59bf35b..e9ff6f7770be 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -259,17 +259,17 @@ static int oprofilefs_fill_super(struct super_block *sb, void *data, int silent) } -static int oprofilefs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *oprofilefs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_single(fs_type, flags, data, oprofilefs_fill_super, mnt); + return mount_single(fs_type, flags, data, oprofilefs_fill_super); } static struct file_system_type oprofilefs_type = { .owner = THIS_MODULE, .name = "oprofilefs", - .get_sb = oprofilefs_get_sb, + .mount = oprofilefs_mount, .kill_sb = kill_litter_super, }; diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 50cf96389d2c..bf61274af3bb 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -2802,6 +2802,73 @@ dasd_eckd_steal_lock(struct dasd_device *device) } /* + * SNID - Sense Path Group ID + * This ioctl may be used in situations where I/O is stalled due to + * a reserve, so if the normal dasd_smalloc_request fails, we use the + * preallocated dasd_reserve_req. + */ +static int dasd_eckd_snid(struct dasd_device *device, + void __user *argp) +{ + struct dasd_ccw_req *cqr; + int rc; + struct ccw1 *ccw; + int useglobal; + struct dasd_snid_ioctl_data usrparm; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (copy_from_user(&usrparm, argp, sizeof(usrparm))) + return -EFAULT; + + useglobal = 0; + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, + sizeof(struct dasd_snid_data), device); + if (IS_ERR(cqr)) { + mutex_lock(&dasd_reserve_mutex); + useglobal = 1; + cqr = &dasd_reserve_req->cqr; + memset(cqr, 0, sizeof(*cqr)); + memset(&dasd_reserve_req->ccw, 0, + sizeof(dasd_reserve_req->ccw)); + cqr->cpaddr = &dasd_reserve_req->ccw; + cqr->data = &dasd_reserve_req->data; + cqr->magic = DASD_ECKD_MAGIC; + } + ccw = cqr->cpaddr; + ccw->cmd_code = DASD_ECKD_CCW_SNID; + ccw->flags |= CCW_FLAG_SLI; + ccw->count = 12; + ccw->cda = (__u32)(addr_t) cqr->data; + cqr->startdev = device; + cqr->memdev = device; + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); + set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); + cqr->retries = 5; + cqr->expires = 10 * HZ; + cqr->buildclk = get_clock(); + cqr->status = DASD_CQR_FILLED; + cqr->lpm = usrparm.path_mask; + + rc = dasd_sleep_on_immediatly(cqr); + /* verify that I/O processing didn't modify the path mask */ + if (!rc && usrparm.path_mask && (cqr->lpm != usrparm.path_mask)) + rc = -EIO; + if (!rc) { + usrparm.data = *((struct dasd_snid_data *)cqr->data); + if (copy_to_user(argp, &usrparm, sizeof(usrparm))) + rc = -EFAULT; + } + + if (useglobal) + mutex_unlock(&dasd_reserve_mutex); + else + dasd_sfree_request(cqr, cqr->memdev); + return rc; +} + +/* * Read performance statistics */ static int @@ -3036,6 +3103,8 @@ dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp) return dasd_eckd_reserve(device); case BIODASDSLCK: return dasd_eckd_steal_lock(device); + case BIODASDSNID: + return dasd_eckd_snid(device, argp); case BIODASDSYMMIO: return dasd_symm_io(device, argp); default: diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 0eb49655a6cd..12097c24f2f5 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -27,6 +27,7 @@ #define DASD_ECKD_CCW_WRITE_CKD 0x1d #define DASD_ECKD_CCW_READ_CKD 0x1e #define DASD_ECKD_CCW_PSF 0x27 +#define DASD_ECKD_CCW_SNID 0x34 #define DASD_ECKD_CCW_RSSD 0x3e #define DASD_ECKD_CCW_LOCATE_RECORD 0x47 #define DASD_ECKD_CCW_SNSS 0x54 diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 29c2d73d719d..6c408670e08d 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -1077,15 +1077,14 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) /* FIXME: What to do with the request? */ switch (PTR_ERR(irb)) { case -ETIMEDOUT: - DBF_LH(1, "(%s): Request timed out\n", - dev_name(&cdev->dev)); + DBF_LH(1, "(%08x): Request timed out\n", + device->cdev_id); case -EIO: __tape_end_request(device, request, -EIO); break; default: - DBF_LH(1, "(%s): Unexpected i/o error %li\n", - dev_name(&cdev->dev), - PTR_ERR(irb)); + DBF_LH(1, "(%08x): Unexpected i/o error %li\n", + device->cdev_id, PTR_ERR(irb)); } return; } diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index 03f07e5dd6e9..3c3f342149ec 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c @@ -47,8 +47,8 @@ tape_std_assign_timeout(unsigned long data) device->cdev_id); rc = tape_cancel_io(device, request); if(rc) - DBF_EVENT(3, "(%s): Assign timeout: Cancel failed with rc = %i\n", - dev_name(&device->cdev->dev), rc); + DBF_EVENT(3, "(%08x): Assign timeout: Cancel failed with rc = " + "%i\n", device->cdev_id, rc); } int diff --git a/drivers/staging/autofs/init.c b/drivers/staging/autofs/init.c index 765c72f42976..5e4b372ea663 100644 --- a/drivers/staging/autofs/init.c +++ b/drivers/staging/autofs/init.c @@ -14,16 +14,16 @@ #include <linux/init.h> #include "autofs_i.h" -static int autofs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *autofs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_nodev(fs_type, flags, data, autofs_fill_super, mnt); + return mount_nodev(fs_type, flags, data, autofs_fill_super); } static struct file_system_type autofs_fs_type = { .owner = THIS_MODULE, .name = "autofs", - .get_sb = autofs_get_sb, + .mount = autofs_mount, .kill_sb = autofs_kill_sb, }; diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c index c62d30017c07..61685ccceda8 100644 --- a/drivers/staging/pohmelfs/inode.c +++ b/drivers/staging/pohmelfs/inode.c @@ -1937,11 +1937,10 @@ err_out_exit: /* * Some VFS magic here... */ -static int pohmelfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *pohmelfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_nodev(fs_type, flags, data, pohmelfs_fill_super, - mnt); + return mount_nodev(fs_type, flags, data, pohmelfs_fill_super); } /* @@ -1958,7 +1957,7 @@ static void pohmelfs_kill_super(struct super_block *sb) static struct file_system_type pohmel_fs_type = { .owner = THIS_MODULE, .name = "pohmel", - .get_sb = pohmelfs_get_sb, + .mount = pohmelfs_mount, .kill_sb = pohmelfs_kill_super, }; diff --git a/drivers/staging/smbfs/inode.c b/drivers/staging/smbfs/inode.c index 552951aa7498..f9c493591ce7 100644 --- a/drivers/staging/smbfs/inode.c +++ b/drivers/staging/smbfs/inode.c @@ -793,16 +793,16 @@ out: return error; } -static int smb_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *smb_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_nodev(fs_type, flags, data, smb_fill_super, mnt); + return mount_nodev(fs_type, flags, data, smb_fill_super); } static struct file_system_type smb_fs_type = { .owner = THIS_MODULE, .name = "smbfs", - .get_sb = smb_get_sb, + .mount = smb_mount, .kill_sb = kill_anon_super, .fs_flags = FS_BINARY_MOUNTDATA, }; diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index e2f63c0ea09d..9819a4cc3b26 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -574,16 +574,16 @@ static void fs_remove_file (struct dentry *dentry) /* --------------------------------------------------------------------- */ -static int usb_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *usb_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_single(fs_type, flags, data, usbfs_fill_super, mnt); + return mount_single(fs_type, flags, data, usbfs_fill_super); } static struct file_system_type usb_fs_type = { .owner = THIS_MODULE, .name = "usbfs", - .get_sb = usb_get_sb, + .mount = usb_mount, .kill_sb = kill_litter_super, }; diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index f276e9594f00..4a830df4fc31 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -1176,9 +1176,9 @@ invalid: /* "mount -t functionfs dev_name /dev/function" ends up here */ -static int -ffs_fs_get_sb(struct file_system_type *t, int flags, - const char *dev_name, void *opts, struct vfsmount *mnt) +static struct dentry * +ffs_fs_mount(struct file_system_type *t, int flags, + const char *dev_name, void *opts) { struct ffs_sb_fill_data data = { .perms = { @@ -1194,14 +1194,14 @@ ffs_fs_get_sb(struct file_system_type *t, int flags, ret = functionfs_check_dev_callback(dev_name); if (unlikely(ret < 0)) - return ret; + return ERR_PTR(ret); ret = ffs_fs_parse_opts(&data, opts); if (unlikely(ret < 0)) - return ret; + return ERR_PTR(ret); data.dev_name = dev_name; - return get_sb_single(t, flags, &data, ffs_sb_fill, mnt); + return mount_single(t, flags, &data, ffs_sb_fill); } static void @@ -1220,7 +1220,7 @@ ffs_fs_kill_sb(struct super_block *sb) static struct file_system_type ffs_fs_type = { .owner = THIS_MODULE, .name = "functionfs", - .get_sb = ffs_fs_get_sb, + .mount = ffs_fs_mount, .kill_sb = ffs_fs_kill_sb, }; diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index ba145e7fbe03..3ed73f49cf18 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -2097,11 +2097,11 @@ enomem0: } /* "mount -t gadgetfs path /dev/gadget" ends up here */ -static int -gadgetfs_get_sb (struct file_system_type *t, int flags, - const char *path, void *opts, struct vfsmount *mnt) +static struct dentry * +gadgetfs_mount (struct file_system_type *t, int flags, + const char *path, void *opts) { - return get_sb_single (t, flags, opts, gadgetfs_fill_super, mnt); + return mount_single (t, flags, opts, gadgetfs_fill_super); } static void @@ -2119,7 +2119,7 @@ gadgetfs_kill_sb (struct super_block *sb) static struct file_system_type gadgetfs_type = { .owner = THIS_MODULE, .name = shortname, - .get_sb = gadgetfs_get_sb, + .mount = gadgetfs_mount, .kill_sb = gadgetfs_kill_sb, }; diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c index d6662b789b6b..f6339d11d59c 100644 --- a/drivers/xen/xenfs/super.c +++ b/drivers/xen/xenfs/super.c @@ -121,17 +121,17 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent) return rc; } -static int xenfs_get_sb(struct file_system_type *fs_type, +static int xenfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, - void *data, struct vfsmount *mnt) + void *data) { - return get_sb_single(fs_type, flags, data, xenfs_fill_super, mnt); + return mount_single(fs_type, flags, data, xenfs_fill_super); } static struct file_system_type xenfs_type = { .owner = THIS_MODULE, .name = "xenfs", - .get_sb = xenfs_get_sb, + .mount = xenfs_mount, .kill_sb = kill_litter_super, }; diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 48d4215c60a8..c55c614500ad 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -68,7 +68,7 @@ static int v9fs_set_super(struct super_block *s, void *data) * v9fs_fill_super - populate superblock with info * @sb: superblock * @v9ses: session information - * @flags: flags propagated from v9fs_get_sb() + * @flags: flags propagated from v9fs_mount() * */ @@ -99,18 +99,16 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses, } /** - * v9fs_get_sb - mount a superblock + * v9fs_mount - mount a superblock * @fs_type: file system type * @flags: mount flags * @dev_name: device name that was mounted * @data: mount options - * @mnt: mountpoint record to be instantiated * */ -static int v9fs_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, - struct vfsmount *mnt) +static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) { struct super_block *sb = NULL; struct inode *inode = NULL; @@ -124,7 +122,7 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL); if (!v9ses) - return -ENOMEM; + return ERR_PTR(-ENOMEM); fid = v9fs_session_init(v9ses, dev_name, data); if (IS_ERR(fid)) { @@ -186,15 +184,15 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, v9fs_fid_add(root, fid); P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n"); - simple_set_mnt(mnt, sb); - return 0; + return dget(sb->s_root); clunk_fid: p9_client_clunk(fid); close_session: v9fs_session_close(v9ses); kfree(v9ses); - return retval; + return ERR_PTR(retval); + release_sb: /* * we will do the session_close and root dentry release @@ -204,7 +202,7 @@ release_sb: */ p9_client_clunk(fid); deactivate_locked_super(sb); - return retval; + return ERR_PTR(retval); } /** @@ -300,7 +298,7 @@ static const struct super_operations v9fs_super_ops_dotl = { struct file_system_type v9fs_fs_type = { .name = "9p", - .get_sb = v9fs_get_sb, + .mount = v9fs_mount, .kill_sb = v9fs_kill_super, .owner = THIS_MODULE, .fs_flags = FS_RENAME_DOES_D_MOVE, diff --git a/fs/adfs/super.c b/fs/adfs/super.c index d9803f73236f..959dbff2d42d 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -490,17 +490,16 @@ error: return -EINVAL; } -static int adfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *adfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, adfs_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, adfs_fill_super); } static struct file_system_type adfs_fs_type = { .owner = THIS_MODULE, .name = "adfs", - .get_sb = adfs_get_sb, + .mount = adfs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/affs/super.c b/fs/affs/super.c index fa4fbe1e238a..0cf7f4384cbd 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -573,17 +573,16 @@ affs_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } -static int affs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *affs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, affs_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, affs_fill_super); } static struct file_system_type affs_fs_type = { .owner = THIS_MODULE, .name = "affs", - .get_sb = affs_get_sb, + .mount = affs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/afs/super.c b/fs/afs/super.c index eacf76d98ae0..27201cffece4 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -29,9 +29,8 @@ #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ static void afs_i_init_once(void *foo); -static int afs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data, struct vfsmount *mnt); +static struct dentry *afs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data); static struct inode *afs_alloc_inode(struct super_block *sb); static void afs_put_super(struct super_block *sb); static void afs_destroy_inode(struct inode *inode); @@ -40,7 +39,7 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf); struct file_system_type afs_fs_type = { .owner = THIS_MODULE, .name = "afs", - .get_sb = afs_get_sb, + .mount = afs_mount, .kill_sb = kill_anon_super, .fs_flags = 0, }; @@ -359,11 +358,8 @@ error: /* * get an AFS superblock */ -static int afs_get_sb(struct file_system_type *fs_type, - int flags, - const char *dev_name, - void *options, - struct vfsmount *mnt) +static struct dentry *afs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *options) { struct afs_mount_params params; struct super_block *sb; @@ -427,12 +423,11 @@ static int afs_get_sb(struct file_system_type *fs_type, ASSERTCMP(sb->s_flags, &, MS_ACTIVE); } - simple_set_mnt(mnt, sb); afs_put_volume(params.volume); afs_put_cell(params.cell); kfree(new_opts); _leave(" = 0 [%p]", sb); - return 0; + return dget(sb->s_root); error: afs_put_volume(params.volume); @@ -440,7 +435,7 @@ error: key_put(params.key); kfree(new_opts); _leave(" = %d", ret); - return ret; + return ERR_PTR(ret); } /* diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 5365527ca43f..57ce55b2564c 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -26,12 +26,10 @@ static struct vfsmount *anon_inode_mnt __read_mostly; static struct inode *anon_inode_inode; static const struct file_operations anon_inode_fops; -static int anon_inodefs_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, - struct vfsmount *mnt) +static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_pseudo(fs_type, "anon_inode:", NULL, ANON_INODE_FS_MAGIC, - mnt); + return mount_pseudo(fs_type, "anon_inode:", NULL, ANON_INODE_FS_MAGIC); } /* @@ -45,7 +43,7 @@ static char *anon_inodefs_dname(struct dentry *dentry, char *buffer, int buflen) static struct file_system_type anon_inode_fs_type = { .name = "anon_inodefs", - .get_sb = anon_inodefs_get_sb, + .mount = anon_inodefs_mount, .kill_sb = kill_anon_super, }; static const struct dentry_operations anon_inodefs_dentry_operations = { diff --git a/fs/autofs4/init.c b/fs/autofs4/init.c index 9722e4bd8957..c038727b4050 100644 --- a/fs/autofs4/init.c +++ b/fs/autofs4/init.c @@ -14,16 +14,16 @@ #include <linux/init.h> #include "autofs_i.h" -static int autofs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *autofs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_nodev(fs_type, flags, data, autofs4_fill_super, mnt); + return mount_nodev(fs_type, flags, data, autofs4_fill_super); } static struct file_system_type autofs_fs_type = { .owner = THIS_MODULE, .name = "autofs", - .get_sb = autofs_get_sb, + .mount = autofs_mount, .kill_sb = autofs4_kill_sb, }; diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index dc39d2824885..aa4e7c7ae3c6 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -913,18 +913,17 @@ befs_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } -static int -befs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, - void *data, struct vfsmount *mnt) +static struct dentry * +befs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, + void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, befs_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, befs_fill_super); } static struct file_system_type befs_fs_type = { .owner = THIS_MODULE, .name = "befs", - .get_sb = befs_get_sb, + .mount = befs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 883e77acd5a8..76db6d7d49bb 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -450,16 +450,16 @@ out: return ret; } -static int bfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *bfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, bfs_fill_super, mnt); + return mount_bdev(fs_type, flags, dev_name, data, bfs_fill_super); } static struct file_system_type bfs_fs_type = { .owner = THIS_MODULE, .name = "bfs", - .get_sb = bfs_get_sb, + .mount = bfs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 29990f0eee0c..1befe2ec8186 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -706,10 +706,10 @@ static int bm_fill_super(struct super_block * sb, void * data, int silent) return err; } -static int bm_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *bm_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_single(fs_type, flags, data, bm_fill_super, mnt); + return mount_single(fs_type, flags, data, bm_fill_super); } static struct linux_binfmt misc_format = { @@ -720,7 +720,7 @@ static struct linux_binfmt misc_format = { static struct file_system_type bm_fs_type = { .owner = THIS_MODULE, .name = "binfmt_misc", - .get_sb = bm_get_sb, + .mount = bm_mount, .kill_sb = kill_litter_super, }; diff --git a/fs/block_dev.c b/fs/block_dev.c index dea3b628a6ce..06e8ff12b97c 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -464,15 +464,15 @@ static const struct super_operations bdev_sops = { .evict_inode = bdev_evict_inode, }; -static int bd_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *bd_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_pseudo(fs_type, "bdev:", &bdev_sops, 0x62646576, mnt); + return mount_pseudo(fs_type, "bdev:", &bdev_sops, 0x62646576); } static struct file_system_type bd_type = { .name = "bdev", - .get_sb = bd_get_sb, + .mount = bd_mount, .kill_sb = kill_anon_super, }; diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 144f8a5730f5..ebe46c628748 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -560,8 +560,8 @@ static int btrfs_test_super(struct super_block *s, void *data) * Note: This is based on get_sb_bdev from fs/super.c with a few additions * for multiple device setup. Make sure to keep it in sync. */ -static int btrfs_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) { struct block_device *bdev = NULL; struct super_block *s; @@ -580,7 +580,7 @@ static int btrfs_get_sb(struct file_system_type *fs_type, int flags, &subvol_name, &subvol_objectid, &fs_devices); if (error) - return error; + return ERR_PTR(error); error = btrfs_scan_one_device(dev_name, mode, fs_type, &fs_devices); if (error) @@ -656,11 +656,8 @@ static int btrfs_get_sb(struct file_system_type *fs_type, int flags, root = new_root; } - mnt->mnt_sb = s; - mnt->mnt_root = root; - kfree(subvol_name); - return 0; + return root; error_s: error = PTR_ERR(s); @@ -669,7 +666,7 @@ error_close_devices: error_free_subvol_name: kfree(subvol_name); error: - return error; + return ERR_PTR(error); } static int btrfs_remount(struct super_block *sb, int *flags, char *data) @@ -746,7 +743,7 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) static struct file_system_type btrfs_fs_type = { .owner = THIS_MODULE, .name = "btrfs", - .get_sb = btrfs_get_sb, + .mount = btrfs_mount, .kill_sb = kill_anon_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/ceph/super.c b/fs/ceph/super.c index d6e0e0421891..08b460ae0539 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -635,7 +635,7 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc, /* * mount: join the ceph cluster, and open root directory. */ -static int ceph_mount(struct ceph_fs_client *fsc, struct vfsmount *mnt, +static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc, const char *path) { int err; @@ -678,16 +678,14 @@ static int ceph_mount(struct ceph_fs_client *fsc, struct vfsmount *mnt, } } - mnt->mnt_root = root; - mnt->mnt_sb = fsc->sb; - fsc->mount_state = CEPH_MOUNT_MOUNTED; dout("mount success\n"); - err = 0; + mutex_unlock(&fsc->client->mount_mutex); + return root; out: mutex_unlock(&fsc->client->mount_mutex); - return err; + return ERR_PTR(err); fail: if (first) { @@ -777,41 +775,45 @@ static int ceph_register_bdi(struct super_block *sb, return err; } -static int ceph_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - struct vfsmount *mnt) +static struct dentry *ceph_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { struct super_block *sb; struct ceph_fs_client *fsc; + struct dentry *res; int err; int (*compare_super)(struct super_block *, void *) = ceph_compare_super; const char *path = NULL; struct ceph_mount_options *fsopt = NULL; struct ceph_options *opt = NULL; - dout("ceph_get_sb\n"); + dout("ceph_mount\n"); err = parse_mount_options(&fsopt, &opt, flags, data, dev_name, &path); - if (err < 0) + if (err < 0) { + res = ERR_PTR(err); goto out_final; + } /* create client (which we may/may not use) */ fsc = create_fs_client(fsopt, opt); if (IS_ERR(fsc)) { - err = PTR_ERR(fsc); + res = ERR_CAST(fsc); kfree(fsopt); kfree(opt); goto out_final; } err = ceph_mdsc_init(fsc); - if (err < 0) + if (err < 0) { + res = ERR_PTR(err); goto out; + } if (ceph_test_opt(fsc->client, NOSHARE)) compare_super = NULL; sb = sget(fs_type, compare_super, ceph_set_super, fsc); if (IS_ERR(sb)) { - err = PTR_ERR(sb); + res = ERR_CAST(sb); goto out; } @@ -823,16 +825,18 @@ static int ceph_get_sb(struct file_system_type *fs_type, } else { dout("get_sb using new client %p\n", fsc); err = ceph_register_bdi(sb, fsc); - if (err < 0) + if (err < 0) { + res = ERR_PTR(err); goto out_splat; + } } - err = ceph_mount(fsc, mnt, path); - if (err < 0) + res = ceph_real_mount(fsc, path); + if (IS_ERR(res)) goto out_splat; - dout("root %p inode %p ino %llx.%llx\n", mnt->mnt_root, - mnt->mnt_root->d_inode, ceph_vinop(mnt->mnt_root->d_inode)); - return 0; + dout("root %p inode %p ino %llx.%llx\n", res, + res->d_inode, ceph_vinop(res->d_inode)); + return res; out_splat: ceph_mdsc_close_sessions(fsc->mdsc); @@ -843,8 +847,8 @@ out: ceph_mdsc_destroy(fsc); destroy_fs_client(fsc); out_final: - dout("ceph_get_sb fail %d\n", err); - return err; + dout("ceph_mount fail %ld\n", PTR_ERR(res)); + return res; } static void ceph_kill_sb(struct super_block *s) @@ -860,7 +864,7 @@ static void ceph_kill_sb(struct super_block *s) static struct file_system_type ceph_fs_type = { .owner = THIS_MODULE, .name = "ceph", - .get_sb = ceph_get_sb, + .mount = ceph_mount, .kill_sb = ceph_kill_sb, .fs_flags = FS_RENAME_DOES_D_MOVE, }; diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 917b7d449bb2..0ed213970ced 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -2,6 +2,9 @@ config CIFS tristate "CIFS support (advanced network filesystem, SMBFS successor)" depends on INET select NLS + select CRYPTO + select CRYPTO_MD5 + select CRYPTO_ARC4 help This is the client VFS module for the Common Internet File System (CIFS) protocol which is the successor to the Server Message Block diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 7ac0056294cf..f856732161ab 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -43,18 +43,32 @@ extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24); static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, - const struct session_key *key, char *signature) + struct TCP_Server_Info *server, char *signature) { - struct MD5Context context; + int rc; - if ((cifs_pdu == NULL) || (signature == NULL) || (key == NULL)) + if (cifs_pdu == NULL || signature == NULL || server == NULL) return -EINVAL; - cifs_MD5_init(&context); - cifs_MD5_update(&context, (char *)&key->data, key->len); - cifs_MD5_update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length); + if (!server->secmech.sdescmd5) { + cERROR(1, "%s: Can't generate signature\n", __func__); + return -1; + } + + rc = crypto_shash_init(&server->secmech.sdescmd5->shash); + if (rc) { + cERROR(1, "%s: Oould not init md5\n", __func__); + return rc; + } + + crypto_shash_update(&server->secmech.sdescmd5->shash, + server->session_key.response, server->session_key.len); + + crypto_shash_update(&server->secmech.sdescmd5->shash, + cifs_pdu->Protocol, cifs_pdu->smb_buf_length); + + rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature); - cifs_MD5_final(signature, &context); return 0; } @@ -79,8 +93,7 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, server->sequence_number++; spin_unlock(&GlobalMid_Lock); - rc = cifs_calculate_signature(cifs_pdu, &server->session_key, - smb_signature); + rc = cifs_calculate_signature(cifs_pdu, server, smb_signature); if (rc) memset(cifs_pdu->Signature.SecuritySignature, 0, 8); else @@ -90,16 +103,28 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, } static int cifs_calc_signature2(const struct kvec *iov, int n_vec, - const struct session_key *key, char *signature) + struct TCP_Server_Info *server, char *signature) { - struct MD5Context context; int i; + int rc; - if ((iov == NULL) || (signature == NULL) || (key == NULL)) + if (iov == NULL || signature == NULL || server == NULL) return -EINVAL; - cifs_MD5_init(&context); - cifs_MD5_update(&context, (char *)&key->data, key->len); + if (!server->secmech.sdescmd5) { + cERROR(1, "%s: Can't generate signature\n", __func__); + return -1; + } + + rc = crypto_shash_init(&server->secmech.sdescmd5->shash); + if (rc) { + cERROR(1, "%s: Oould not init md5\n", __func__); + return rc; + } + + crypto_shash_update(&server->secmech.sdescmd5->shash, + server->session_key.response, server->session_key.len); + for (i = 0; i < n_vec; i++) { if (iov[i].iov_len == 0) continue; @@ -112,18 +137,18 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, if (i == 0) { if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ break; /* nothing to sign or corrupt header */ - cifs_MD5_update(&context, iov[0].iov_base+4, - iov[0].iov_len-4); + crypto_shash_update(&server->secmech.sdescmd5->shash, + iov[i].iov_base + 4, iov[i].iov_len - 4); } else - cifs_MD5_update(&context, iov[i].iov_base, iov[i].iov_len); + crypto_shash_update(&server->secmech.sdescmd5->shash, + iov[i].iov_base, iov[i].iov_len); } - cifs_MD5_final(signature, &context); + rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature); - return 0; + return rc; } - int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, __u32 *pexpected_response_sequence_number) { @@ -146,8 +171,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, server->sequence_number++; spin_unlock(&GlobalMid_Lock); - rc = cifs_calc_signature2(iov, n_vec, &server->session_key, - smb_signature); + rc = cifs_calc_signature2(iov, n_vec, server, smb_signature); if (rc) memset(cifs_pdu->Signature.SecuritySignature, 0, 8); else @@ -157,14 +181,14 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, } int cifs_verify_signature(struct smb_hdr *cifs_pdu, - const struct session_key *session_key, + struct TCP_Server_Info *server, __u32 expected_sequence_number) { unsigned int rc; char server_response_sig[8]; char what_we_think_sig_should_be[20]; - if (cifs_pdu == NULL || session_key == NULL) + if (cifs_pdu == NULL || server == NULL) return -EINVAL; if (cifs_pdu->Command == SMB_COM_NEGOTIATE) @@ -193,7 +217,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, cpu_to_le32(expected_sequence_number); cifs_pdu->Signature.Sequence.Reserved = 0; - rc = cifs_calculate_signature(cifs_pdu, session_key, + rc = cifs_calculate_signature(cifs_pdu, server, what_we_think_sig_should_be); if (rc) @@ -209,18 +233,28 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, } -/* We fill in key by putting in 40 byte array which was allocated by caller */ -int cifs_calculate_session_key(struct session_key *key, const char *rn, - const char *password) +/* first calculate 24 bytes ntlm response and then 16 byte session key */ +int setup_ntlm_response(struct cifsSesInfo *ses) { - char temp_key[16]; - if ((key == NULL) || (rn == NULL)) + unsigned int temp_len = CIFS_SESS_KEY_SIZE + CIFS_AUTH_RESP_SIZE; + char temp_key[CIFS_SESS_KEY_SIZE]; + + if (!ses) return -EINVAL; - E_md4hash(password, temp_key); - mdfour(key->data.ntlm, temp_key, 16); - memcpy(key->data.ntlm+16, rn, CIFS_SESS_KEY_SIZE); - key->len = 40; + ses->auth_key.response = kmalloc(temp_len, GFP_KERNEL); + if (!ses->auth_key.response) { + cERROR(1, "NTLM can't allocate (%u bytes) memory", temp_len); + return -ENOMEM; + } + ses->auth_key.len = temp_len; + + SMBNTencrypt(ses->password, ses->server->cryptkey, + ses->auth_key.response + CIFS_SESS_KEY_SIZE); + + E_md4hash(ses->password, temp_key); + mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE); + return 0; } @@ -294,15 +328,15 @@ build_avpair_blob(struct cifsSesInfo *ses, const struct nls_table *nls_cp) * two times the unicode length of a server name + * size of a timestamp (which is 8 bytes). */ - ses->tilen = size + 2 * (2 * dlen) + 2 * (2 * wlen) + 8; - ses->tiblob = kzalloc(ses->tilen, GFP_KERNEL); - if (!ses->tiblob) { - ses->tilen = 0; + ses->auth_key.len = size + 2 * (2 * dlen) + 2 * (2 * wlen) + 8; + ses->auth_key.response = kzalloc(ses->auth_key.len, GFP_KERNEL); + if (!ses->auth_key.response) { + ses->auth_key.len = 0; cERROR(1, "Challenge target info allocation failure"); return -ENOMEM; } - blobptr = ses->tiblob; + blobptr = ses->auth_key.response; attrptr = (struct ntlmssp2_name *) blobptr; attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME); @@ -357,7 +391,7 @@ build_avpair_blob(struct cifsSesInfo *ses, const struct nls_table *nls_cp) * about target string i.e. for some, just user name might suffice. */ static int -find_domain_name(struct cifsSesInfo *ses) +find_domain_name(struct cifsSesInfo *ses, const struct nls_table *nls_cp) { unsigned int attrsize; unsigned int type; @@ -366,11 +400,11 @@ find_domain_name(struct cifsSesInfo *ses) unsigned char *blobend; struct ntlmssp2_name *attrptr; - if (!ses->tilen || !ses->tiblob) + if (!ses->auth_key.len || !ses->auth_key.response) return 0; - blobptr = ses->tiblob; - blobend = ses->tiblob + ses->tilen; + blobptr = ses->auth_key.response; + blobend = blobptr + ses->auth_key.len; while (blobptr + onesize < blobend) { attrptr = (struct ntlmssp2_name *) blobptr; @@ -386,16 +420,13 @@ find_domain_name(struct cifsSesInfo *ses) if (!attrsize) break; if (!ses->domainName) { - struct nls_table *default_nls; ses->domainName = kmalloc(attrsize + 1, GFP_KERNEL); if (!ses->domainName) return -ENOMEM; - default_nls = load_nls_default(); cifs_from_ucs2(ses->domainName, (__le16 *)blobptr, attrsize, attrsize, - default_nls, false); - unload_nls(default_nls); + nls_cp, false); break; } } @@ -405,82 +436,136 @@ find_domain_name(struct cifsSesInfo *ses) return 0; } -static int calc_ntlmv2_hash(struct cifsSesInfo *ses, +static int calc_ntlmv2_hash(struct cifsSesInfo *ses, char *ntlmv2_hash, const struct nls_table *nls_cp) { int rc = 0; int len; - char nt_hash[16]; - struct HMACMD5Context *pctxt; + char nt_hash[CIFS_NTHASH_SIZE]; wchar_t *user; wchar_t *domain; + wchar_t *server; - pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); - - if (pctxt == NULL) - return -ENOMEM; + if (!ses->server->secmech.sdeschmacmd5) { + cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); + return -1; + } /* calculate md4 hash of password */ E_md4hash(ses->password, nt_hash); - /* convert Domainname to unicode and uppercase */ - hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); + crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash, + CIFS_NTHASH_SIZE); + + rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); + if (rc) { + cERROR(1, "calc_ntlmv2_hash: could not init hmacmd5\n"); + return rc; + } /* convert ses->userName to unicode and uppercase */ len = strlen(ses->userName); user = kmalloc(2 + (len * 2), GFP_KERNEL); - if (user == NULL) + if (user == NULL) { + cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n"); + rc = -ENOMEM; goto calc_exit_2; + } len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); UniStrupr(user); - hmac_md5_update((char *)user, 2*len, pctxt); + + crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, + (char *)user, 2 * len); /* convert ses->domainName to unicode and uppercase */ if (ses->domainName) { len = strlen(ses->domainName); domain = kmalloc(2 + (len * 2), GFP_KERNEL); - if (domain == NULL) + if (domain == NULL) { + cERROR(1, "calc_ntlmv2_hash: domain mem alloc failure"); + rc = -ENOMEM; goto calc_exit_1; + } len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, nls_cp); - /* the following line was removed since it didn't work well - with lower cased domain name that passed as an option. - Maybe converting the domain name earlier makes sense */ - /* UniStrupr(domain); */ - - hmac_md5_update((char *)domain, 2*len, pctxt); - + crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, + (char *)domain, 2 * len); kfree(domain); + } else if (ses->serverName) { + len = strlen(ses->serverName); + + server = kmalloc(2 + (len * 2), GFP_KERNEL); + if (server == NULL) { + cERROR(1, "calc_ntlmv2_hash: server mem alloc failure"); + rc = -ENOMEM; + goto calc_exit_1; + } + len = cifs_strtoUCS((__le16 *)server, ses->serverName, len, + nls_cp); + crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, + (char *)server, 2 * len); + kfree(server); } + + rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, + ntlmv2_hash); + calc_exit_1: kfree(user); calc_exit_2: - /* BB FIXME what about bytes 24 through 40 of the signing key? - compare with the NTLM example */ - hmac_md5_final(ses->ntlmv2_hash, pctxt); + return rc; +} + +static int +CalcNTLMv2_response(const struct cifsSesInfo *ses, char *ntlmv2_hash) +{ + int rc; + unsigned int offset = CIFS_SESS_KEY_SIZE + 8; + + if (!ses->server->secmech.sdeschmacmd5) { + cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); + return -1; + } + + crypto_shash_setkey(ses->server->secmech.hmacmd5, + ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); + + rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); + if (rc) { + cERROR(1, "CalcNTLMv2_response: could not init hmacmd5"); + return rc; + } + + if (ses->server->secType == RawNTLMSSP) + memcpy(ses->auth_key.response + offset, + ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); + else + memcpy(ses->auth_key.response + offset, + ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); + crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, + ses->auth_key.response + offset, ses->auth_key.len - offset); + + rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, + ses->auth_key.response + CIFS_SESS_KEY_SIZE); - kfree(pctxt); return rc; } + int -setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, - const struct nls_table *nls_cp) +setup_ntlmv2_rsp(struct cifsSesInfo *ses, const struct nls_table *nls_cp) { int rc; - struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf; - struct HMACMD5Context context; - - buf->blob_signature = cpu_to_le32(0x00000101); - buf->reserved = 0; - buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); - get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); - buf->reserved2 = 0; + int baselen; + unsigned int tilen; + struct ntlmv2_resp *buf; + char ntlmv2_hash[16]; + unsigned char *tiblob = NULL; /* target info blob */ if (ses->server->secType == RawNTLMSSP) { if (!ses->domainName) { - rc = find_domain_name(ses); + rc = find_domain_name(ses, nls_cp); if (rc) { cERROR(1, "error %d finding domain name", rc); goto setup_ntlmv2_rsp_ret; @@ -490,51 +575,179 @@ setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, rc = build_avpair_blob(ses, nls_cp); if (rc) { cERROR(1, "error %d building av pair blob", rc); - return rc; + goto setup_ntlmv2_rsp_ret; } } - /* calculate buf->ntlmv2_hash */ - rc = calc_ntlmv2_hash(ses, nls_cp); + baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp); + tilen = ses->auth_key.len; + tiblob = ses->auth_key.response; + + ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL); + if (!ses->auth_key.response) { + rc = ENOMEM; + ses->auth_key.len = 0; + cERROR(1, "%s: Can't allocate auth blob", __func__); + goto setup_ntlmv2_rsp_ret; + } + ses->auth_key.len += baselen; + + buf = (struct ntlmv2_resp *) + (ses->auth_key.response + CIFS_SESS_KEY_SIZE); + buf->blob_signature = cpu_to_le32(0x00000101); + buf->reserved = 0; + buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); + get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); + buf->reserved2 = 0; + + memcpy(ses->auth_key.response + baselen, tiblob, tilen); + + /* calculate ntlmv2_hash */ + rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp); if (rc) { cERROR(1, "could not get v2 hash rc %d", rc); goto setup_ntlmv2_rsp_ret; } - CalcNTLMv2_response(ses, resp_buf); + + /* calculate first part of the client response (CR1) */ + rc = CalcNTLMv2_response(ses, ntlmv2_hash); + if (rc) { + cERROR(1, "Could not calculate CR1 rc: %d", rc); + goto setup_ntlmv2_rsp_ret; + } /* now calculate the session key for NTLMv2 */ - hmac_md5_init_limK_to_64(ses->ntlmv2_hash, 16, &context); - hmac_md5_update(resp_buf, 16, &context); - hmac_md5_final(ses->auth_key.data.ntlmv2.key, &context); + crypto_shash_setkey(ses->server->secmech.hmacmd5, + ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); + + rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); + if (rc) { + cERROR(1, "%s: Could not init hmacmd5\n", __func__); + goto setup_ntlmv2_rsp_ret; + } - memcpy(&ses->auth_key.data.ntlmv2.resp, resp_buf, - sizeof(struct ntlmv2_resp)); - ses->auth_key.len = 16 + sizeof(struct ntlmv2_resp); + crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, + ses->auth_key.response + CIFS_SESS_KEY_SIZE, + CIFS_HMAC_MD5_HASH_SIZE); - return 0; + rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, + ses->auth_key.response); setup_ntlmv2_rsp_ret: - kfree(ses->tiblob); - ses->tiblob = NULL; - ses->tilen = 0; + kfree(tiblob); return rc; } -void CalcNTLMv2_response(const struct cifsSesInfo *ses, - char *v2_session_response) +int +calc_seckey(struct cifsSesInfo *ses) { - struct HMACMD5Context context; - /* rest of v2 struct already generated */ - memcpy(v2_session_response + 8, ses->cryptKey, 8); - hmac_md5_init_limK_to_64(ses->ntlmv2_hash, 16, &context); + int rc; + struct crypto_blkcipher *tfm_arc4; + struct scatterlist sgin, sgout; + struct blkcipher_desc desc; + unsigned char sec_key[CIFS_SESS_KEY_SIZE]; /* a nonce */ + + get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE); + + tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); + if (!tfm_arc4 || IS_ERR(tfm_arc4)) { + cERROR(1, "could not allocate crypto API arc4\n"); + return PTR_ERR(tfm_arc4); + } - hmac_md5_update(v2_session_response+8, - sizeof(struct ntlmv2_resp) - 8, &context); + desc.tfm = tfm_arc4; - if (ses->tilen) - hmac_md5_update(ses->tiblob, ses->tilen, &context); + crypto_blkcipher_setkey(tfm_arc4, ses->auth_key.response, + CIFS_SESS_KEY_SIZE); - hmac_md5_final(v2_session_response, &context); -/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ + sg_init_one(&sgin, sec_key, CIFS_SESS_KEY_SIZE); + sg_init_one(&sgout, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); + + rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, CIFS_CPHTXT_SIZE); + if (rc) { + cERROR(1, "could not encrypt session key rc: %d\n", rc); + crypto_free_blkcipher(tfm_arc4); + return rc; + } + + /* make secondary_key/nonce as session key */ + memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE); + /* and make len as that of session key only */ + ses->auth_key.len = CIFS_SESS_KEY_SIZE; + + crypto_free_blkcipher(tfm_arc4); + + return 0; +} + +void +cifs_crypto_shash_release(struct TCP_Server_Info *server) +{ + if (server->secmech.md5) + crypto_free_shash(server->secmech.md5); + + if (server->secmech.hmacmd5) + crypto_free_shash(server->secmech.hmacmd5); + + kfree(server->secmech.sdeschmacmd5); + + kfree(server->secmech.sdescmd5); +} + +int +cifs_crypto_shash_allocate(struct TCP_Server_Info *server) +{ + int rc; + unsigned int size; + + server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0); + if (!server->secmech.hmacmd5 || + IS_ERR(server->secmech.hmacmd5)) { + cERROR(1, "could not allocate crypto hmacmd5\n"); + return PTR_ERR(server->secmech.hmacmd5); + } + + server->secmech.md5 = crypto_alloc_shash("md5", 0, 0); + if (!server->secmech.md5 || IS_ERR(server->secmech.md5)) { + cERROR(1, "could not allocate crypto md5\n"); + rc = PTR_ERR(server->secmech.md5); + goto crypto_allocate_md5_fail; + } + + size = sizeof(struct shash_desc) + + crypto_shash_descsize(server->secmech.hmacmd5); + server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL); + if (!server->secmech.sdeschmacmd5) { + cERROR(1, "cifs_crypto_shash_allocate: can't alloc hmacmd5\n"); + rc = -ENOMEM; + goto crypto_allocate_hmacmd5_sdesc_fail; + } + server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5; + server->secmech.sdeschmacmd5->shash.flags = 0x0; + + + size = sizeof(struct shash_desc) + + crypto_shash_descsize(server->secmech.md5); + server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL); + if (!server->secmech.sdescmd5) { + cERROR(1, "cifs_crypto_shash_allocate: can't alloc md5\n"); + rc = -ENOMEM; + goto crypto_allocate_md5_sdesc_fail; + } + server->secmech.sdescmd5->shash.tfm = server->secmech.md5; + server->secmech.sdescmd5->shash.flags = 0x0; + + return 0; + +crypto_allocate_md5_sdesc_fail: + kfree(server->secmech.sdeschmacmd5); + +crypto_allocate_hmacmd5_sdesc_fail: + crypto_free_shash(server->secmech.md5); + +crypto_allocate_md5_fail: + crypto_free_shash(server->secmech.hmacmd5); + + return rc; } diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 34371637f210..75c4eaa79588 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -318,7 +318,6 @@ cifs_alloc_inode(struct super_block *sb) return NULL; cifs_inode->cifsAttrs = 0x20; /* default */ cifs_inode->time = 0; - cifs_inode->write_behind_rc = 0; /* Until the file is open and we have gotten oplock info back from the server, can not assume caching of file data or metadata */ @@ -545,9 +544,9 @@ static const struct super_operations cifs_super_ops = { #endif }; -static int -cifs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry * +cifs_do_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { int rc; struct super_block *sb; @@ -557,18 +556,17 @@ cifs_get_sb(struct file_system_type *fs_type, cFYI(1, "Devname: %s flags: %d ", dev_name, flags); if (IS_ERR(sb)) - return PTR_ERR(sb); + return ERR_CAST(sb); sb->s_flags = flags; rc = cifs_read_super(sb, data, dev_name, flags & MS_SILENT ? 1 : 0); if (rc) { deactivate_locked_super(sb); - return rc; + return ERR_PTR(rc); } sb->s_flags |= MS_ACTIVE; - simple_set_mnt(mnt, sb); - return 0; + return dget(sb->s_root); } static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, @@ -634,7 +632,7 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) struct file_system_type cifs_fs_type = { .owner = THIS_MODULE, .name = "cifs", - .get_sb = cifs_get_sb, + .mount = cifs_do_mount, .kill_sb = kill_anon_super, /* .fs_flags */ }; diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index f35795a16b42..897b2b2b28b5 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -112,5 +112,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); extern const struct export_operations cifs_export_ops; #endif /* EXPERIMENTAL */ -#define CIFS_VERSION "1.67" +#define CIFS_VERSION "1.68" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 3365e77f6f24..f259e4d7612d 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -25,6 +25,9 @@ #include <linux/workqueue.h> #include "cifs_fs_sb.h" #include "cifsacl.h" +#include <crypto/internal/hash.h> +#include <linux/scatterlist.h> + /* * The sizes of various internal tables and strings */ @@ -74,7 +77,7 @@ * CIFS vfs client Status information (based on what we know.) */ - /* associated with each tcp and smb session */ +/* associated with each tcp and smb session */ enum statusEnum { CifsNew = 0, CifsGood, @@ -99,14 +102,29 @@ enum protocolEnum { struct session_key { unsigned int len; - union { - char ntlm[CIFS_SESS_KEY_SIZE + 16]; - char krb5[CIFS_SESS_KEY_SIZE + 16]; /* BB: length correct? */ - struct { - char key[16]; - struct ntlmv2_resp resp; - } ntlmv2; - } data; + char *response; +}; + +/* crypto security descriptor definition */ +struct sdesc { + struct shash_desc shash; + char ctx[]; +}; + +/* crypto hashing related structure/fields, not specific to a sec mech */ +struct cifs_secmech { + struct crypto_shash *hmacmd5; /* hmac-md5 hash function */ + struct crypto_shash *md5; /* md5 hash function */ + struct sdesc *sdeschmacmd5; /* ctxt to generate ntlmv2 hash, CR1 */ + struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */ +}; + +/* per smb session structure/fields */ +struct ntlmssp_auth { + __u32 client_flags; /* sent by client in type 1 ntlmsssp exchange */ + __u32 server_flags; /* sent by server in type 2 ntlmssp exchange */ + unsigned char ciphertext[CIFS_CPHTXT_SIZE]; /* sent to server */ + char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlmssp */ }; struct cifs_cred { @@ -179,12 +197,14 @@ struct TCP_Server_Info { int capabilities; /* allow selective disabling of caps by smb sess */ int timeAdj; /* Adjust for difference in server time zone in sec */ __u16 CurrentMid; /* multiplex id - rotating counter */ + char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */ /* 16th byte of RFC1001 workstation name is always null */ char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; __u32 sequence_number; /* needed for CIFS PDU signature */ struct session_key session_key; unsigned long lstrp; /* when we got last response from this server */ u16 dialect; /* dialect index that server chose */ + struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */ /* extended security flavors that server supports */ bool sec_kerberos; /* supports plain Kerberos */ bool sec_mskerberos; /* supports legacy MS Kerberos */ @@ -222,11 +242,8 @@ struct cifsSesInfo { char userName[MAX_USERNAME_SIZE + 1]; char *domainName; char *password; - char cryptKey[CIFS_CRYPTO_KEY_SIZE]; struct session_key auth_key; - char ntlmv2_hash[16]; - unsigned int tilen; /* length of the target info blob */ - unsigned char *tiblob; /* target info blob in challenge response */ + struct ntlmssp_auth *ntlmssp; /* ciphertext, flags, server challenge */ bool need_reconnect:1; /* connection reset, uid now invalid */ }; /* no more than one of the following three session flags may be set */ @@ -395,16 +412,19 @@ struct cifsFileInfo { struct list_head llist; /* list of byte range locks we have. */ bool invalidHandle:1; /* file closed via session abend */ bool oplock_break_cancelled:1; - atomic_t count; /* reference count */ + int count; /* refcount protected by cifs_file_list_lock */ struct mutex fh_mutex; /* prevents reopen race after dead ses*/ struct cifs_search_info srch_inf; struct work_struct oplock_break; /* work for oplock breaks */ }; -/* Take a reference on the file private data */ +/* + * Take a reference on the file private data. Must be called with + * cifs_file_list_lock held. + */ static inline void cifsFileInfo_get(struct cifsFileInfo *cifs_file) { - atomic_inc(&cifs_file->count); + ++cifs_file->count; } void cifsFileInfo_put(struct cifsFileInfo *cifs_file); @@ -417,7 +437,6 @@ struct cifsInodeInfo { struct list_head lockList; /* BB add in lists for dirty pages i.e. write caching info for oplock */ struct list_head openFileList; - int write_behind_rc; __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ unsigned long time; /* jiffies of last update/check of inode */ bool clientCanCacheRead:1; /* read oplock */ @@ -668,7 +687,7 @@ require use of the stronger protocol */ * GlobalMid_Lock protects: * list operations on pending_mid_q and oplockQ * updates to XID counters, multiplex id and SMB sequence numbers - * GlobalSMBSesLock protects: + * cifs_file_list_lock protects: * list operations on tcp and SMB session lists and tCon lists * f_owner.lock protects certain per file struct operations * mapping->page_lock protects certain per page operations diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index b0f4b5656d4c..de36b09763a8 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -131,9 +131,20 @@ #define CIFS_CRYPTO_KEY_SIZE (8) /* + * Size of the ntlm client response + */ +#define CIFS_AUTH_RESP_SIZE (24) + +/* * Size of the session key (crypto key encrypted with the password */ -#define CIFS_SESS_KEY_SIZE (24) +#define CIFS_SESS_KEY_SIZE (16) + +#define CIFS_CLIENT_CHALLENGE_SIZE (8) +#define CIFS_SERVER_CHALLENGE_SIZE (8) +#define CIFS_HMAC_MD5_HASH_SIZE (16) +#define CIFS_CPHTXT_SIZE (16) +#define CIFS_NTHASH_SIZE (16) /* * Maximum user name length diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index e593c40ba7ba..edb6d90efdf2 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -362,13 +362,15 @@ extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *); extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, __u32 *); extern int cifs_verify_signature(struct smb_hdr *, - const struct session_key *session_key, + struct TCP_Server_Info *server, __u32 expected_sequence_number); -extern int cifs_calculate_session_key(struct session_key *key, const char *rn, - const char *pass); -extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *); -extern int setup_ntlmv2_rsp(struct cifsSesInfo *, char *, - const struct nls_table *); +extern void SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *); +extern int setup_ntlm_response(struct cifsSesInfo *); +extern int setup_ntlmv2_rsp(struct cifsSesInfo *, const struct nls_table *); +extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *); +extern void cifs_crypto_shash_release(struct TCP_Server_Info *); +extern int calc_seckey(struct cifsSesInfo *); + #ifdef CONFIG_CIFS_WEAK_PW_HASH extern void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, char *lnm_session_key); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index e98f1f317b15..2f2632b6df5a 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -503,7 +503,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) if (rsp->EncryptionKeyLength == cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { - memcpy(ses->cryptKey, rsp->EncryptionKey, + memcpy(ses->server->cryptkey, rsp->EncryptionKey, CIFS_CRYPTO_KEY_SIZE); } else if (server->secMode & SECMODE_PW_ENCRYPT) { rc = -EIO; /* need cryptkey unless plain text */ @@ -574,7 +574,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); server->timeAdj *= 60; if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { - memcpy(ses->cryptKey, pSMBr->u.EncryptionKey, + memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey, CIFS_CRYPTO_KEY_SIZE); } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && (pSMBr->EncryptionKeyLength == 0)) { diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 7e73176acb58..9eb327defa1d 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -175,6 +175,9 @@ cifs_reconnect(struct TCP_Server_Info *server) } server->sequence_number = 0; server->session_estab = false; + kfree(server->session_key.response); + server->session_key.response = NULL; + server->session_key.len = 0; spin_lock(&GlobalMid_Lock); list_for_each(tmp, &server->pending_mid_q) { @@ -1064,7 +1067,7 @@ cifs_parse_mount_options(char *options, const char *devname, } i = cifs_convert_address((struct sockaddr *)&vol->srcaddr, value, strlen(value)); - if (i < 0) { + if (i == 0) { printk(KERN_WARNING "CIFS: Could not parse" " srcaddr: %s\n", value); @@ -1560,8 +1563,13 @@ cifs_put_tcp_session(struct TCP_Server_Info *server) server->tcpStatus = CifsExiting; spin_unlock(&GlobalMid_Lock); + cifs_crypto_shash_release(server); cifs_fscache_release_client_cookie(server); + kfree(server->session_key.response); + server->session_key.response = NULL; + server->session_key.len = 0; + task = xchg(&server->tsk, NULL); if (task) force_sig(SIGKILL, task); @@ -1614,10 +1622,16 @@ cifs_get_tcp_session(struct smb_vol *volume_info) goto out_err; } + rc = cifs_crypto_shash_allocate(tcp_ses); + if (rc) { + cERROR(1, "could not setup hash structures rc %d", rc); + goto out_err; + } + tcp_ses->hostname = extract_hostname(volume_info->UNC); if (IS_ERR(tcp_ses->hostname)) { rc = PTR_ERR(tcp_ses->hostname); - goto out_err; + goto out_err_crypto_release; } tcp_ses->noblocksnd = volume_info->noblocksnd; @@ -1661,7 +1675,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) } if (rc < 0) { cERROR(1, "Error connecting to socket. Aborting operation"); - goto out_err; + goto out_err_crypto_release; } /* @@ -1675,7 +1689,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) rc = PTR_ERR(tcp_ses->tsk); cERROR(1, "error %d create cifsd thread", rc); module_put(THIS_MODULE); - goto out_err; + goto out_err_crypto_release; } /* thread spawned, put it on the list */ @@ -1687,6 +1701,9 @@ cifs_get_tcp_session(struct smb_vol *volume_info) return tcp_ses; +out_err_crypto_release: + cifs_crypto_shash_release(tcp_ses); + out_err: if (tcp_ses) { if (!IS_ERR(tcp_ses->hostname)) @@ -1801,8 +1818,6 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) if (ses == NULL) goto get_ses_fail; - ses->tilen = 0; - ses->tiblob = NULL; /* new SMB session uses our server ref */ ses->server = server; if (server->addr.sockAddr6.sin6_family == AF_INET6) @@ -1823,10 +1838,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) goto get_ses_fail; } if (volume_info->domainname) { - int len = strlen(volume_info->domainname); - ses->domainName = kmalloc(len + 1, GFP_KERNEL); - if (ses->domainName) - strcpy(ses->domainName, volume_info->domainname); + ses->domainName = kstrdup(volume_info->domainname, GFP_KERNEL); + if (!ses->domainName) + goto get_ses_fail; } ses->cred_uid = volume_info->cred_uid; ses->linux_uid = volume_info->linux_uid; @@ -2985,13 +2999,13 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, #ifdef CONFIG_CIFS_WEAK_PW_HASH if ((global_secflags & CIFSSEC_MAY_LANMAN) && (ses->server->secType == LANMAN)) - calc_lanman_hash(tcon->password, ses->cryptKey, + calc_lanman_hash(tcon->password, ses->server->cryptkey, ses->server->secMode & SECMODE_PW_ENCRYPT ? true : false, bcc_ptr); else #endif /* CIFS_WEAK_PW_HASH */ - SMBNTencrypt(tcon->password, ses->cryptKey, bcc_ptr); + SMBNTencrypt(tcon->password, ses->server->cryptkey, bcc_ptr); bcc_ptr += CIFS_SESS_KEY_SIZE; if (ses->capabilities & CAP_UNICODE) { @@ -3178,10 +3192,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses, } else { mutex_lock(&ses->server->srv_mutex); if (!server->session_estab) { - memcpy(&server->session_key.data, - &ses->auth_key.data, ses->auth_key.len); + server->session_key.response = ses->auth_key.response; server->session_key.len = ses->auth_key.len; - ses->server->session_estab = true; + server->sequence_number = 0x2; + server->session_estab = true; + ses->auth_key.response = NULL; } mutex_unlock(&server->srv_mutex); @@ -3192,6 +3207,12 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses, spin_unlock(&GlobalMid_Lock); } + kfree(ses->auth_key.response); + ses->auth_key.response = NULL; + ses->auth_key.len = 0; + kfree(ses->ntlmssp); + ses->ntlmssp = NULL; + return rc; } diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 45af003865d2..ae82159cf7fa 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -131,8 +131,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, /* BB no need to lock inode until after invalidate since namei code should already have it locked? */ rc = filemap_write_and_wait(inode->i_mapping); - if (rc != 0) - pCifsInode->write_behind_rc = rc; + mapping_set_error(inode->i_mapping, rc); } cFYI(1, "invalidating remote inode since open detected it " "changed"); @@ -232,6 +231,7 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file, if (pCifsFile == NULL) return pCifsFile; + pCifsFile->count = 1; pCifsFile->netfid = fileHandle; pCifsFile->pid = current->tgid; pCifsFile->uid = current_fsuid(); @@ -242,7 +242,6 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file, mutex_init(&pCifsFile->fh_mutex); mutex_init(&pCifsFile->lock_mutex); INIT_LIST_HEAD(&pCifsFile->llist); - atomic_set(&pCifsFile->count, 1); INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break); spin_lock(&cifs_file_list_lock); @@ -267,7 +266,8 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file, /* * Release a reference on the file private data. This may involve closing - * the filehandle out on the server. + * the filehandle out on the server. Must be called without holding + * cifs_file_list_lock. */ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) { @@ -276,7 +276,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) struct cifsLockInfo *li, *tmp; spin_lock(&cifs_file_list_lock); - if (!atomic_dec_and_test(&cifs_file->count)) { + if (--cifs_file->count > 0) { spin_unlock(&cifs_file_list_lock); return; } @@ -605,8 +605,7 @@ reopen_success: if (can_flush) { rc = filemap_write_and_wait(inode->i_mapping); - if (rc != 0) - CIFS_I(inode)->write_behind_rc = rc; + mapping_set_error(inode->i_mapping, rc); pCifsInode->clientCanCacheAll = false; pCifsInode->clientCanCacheRead = false; @@ -1353,6 +1352,7 @@ static int cifs_writepages(struct address_space *mapping, if (!experimEnabled && tcon->ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { cifsFileInfo_put(open_file); + kfree(iov); return generic_writepages(mapping, wbc); } cifsFileInfo_put(open_file); @@ -1478,12 +1478,7 @@ retry: if (rc || bytes_written < bytes_to_write) { cERROR(1, "Write2 ret %d, wrote %d", rc, bytes_written); - /* BB what if continued retry is - requested via mount flags? */ - if (rc == -ENOSPC) - set_bit(AS_ENOSPC, &mapping->flags); - else - set_bit(AS_EIO, &mapping->flags); + mapping_set_error(mapping, rc); } else { cifs_stats_bytes_written(tcon, bytes_written); } @@ -1628,11 +1623,10 @@ int cifs_fsync(struct file *file, int datasync) rc = filemap_write_and_wait(inode->i_mapping); if (rc == 0) { - rc = CIFS_I(inode)->write_behind_rc; - CIFS_I(inode)->write_behind_rc = 0; + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); + tcon = tlink_tcon(smbfile->tlink); - if (!rc && tcon && smbfile && - !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); } @@ -1677,21 +1671,8 @@ int cifs_flush(struct file *file, fl_owner_t id) struct inode *inode = file->f_path.dentry->d_inode; int rc = 0; - /* Rather than do the steps manually: - lock the inode for writing - loop through pages looking for write behind data (dirty pages) - coalesce into contiguous 16K (or smaller) chunks to write to server - send to server (prefer in parallel) - deal with writebehind errors - unlock inode for writing - filemapfdatawrite appears easier for the time being */ - - rc = filemap_fdatawrite(inode->i_mapping); - /* reset wb rc if we were able to write out dirty pages */ - if (!rc) { - rc = CIFS_I(inode)->write_behind_rc; - CIFS_I(inode)->write_behind_rc = 0; - } + if (file->f_mode & FMODE_WRITE) + rc = filemap_write_and_wait(inode->i_mapping); cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc); @@ -2270,7 +2251,7 @@ void cifs_oplock_break(struct work_struct *work) oplock_break); struct inode *inode = cfile->dentry->d_inode; struct cifsInodeInfo *cinode = CIFS_I(inode); - int rc, waitrc = 0; + int rc = 0; if (inode && S_ISREG(inode->i_mode)) { if (cinode->clientCanCacheRead) @@ -2279,13 +2260,10 @@ void cifs_oplock_break(struct work_struct *work) break_lease(inode, O_WRONLY); rc = filemap_fdatawrite(inode->i_mapping); if (cinode->clientCanCacheRead == 0) { - waitrc = filemap_fdatawait(inode->i_mapping); + rc = filemap_fdatawait(inode->i_mapping); + mapping_set_error(inode->i_mapping, rc); invalidate_remote_inode(inode); } - if (!rc) - rc = waitrc; - if (rc) - cinode->write_behind_rc = rc; cFYI(1, "Oplock flush inode %p rc %d", inode, rc); } @@ -2304,7 +2282,7 @@ void cifs_oplock_break(struct work_struct *work) /* * We might have kicked in before is_valid_oplock_break() * finished grabbing reference for us. Make sure it's done by - * waiting for GlobalSMSSeslock. + * waiting for cifs_file_list_lock. */ spin_lock(&cifs_file_list_lock); spin_unlock(&cifs_file_list_lock); @@ -2312,6 +2290,7 @@ void cifs_oplock_break(struct work_struct *work) cifs_oplock_break_put(cfile); } +/* must be called while holding cifs_file_list_lock */ void cifs_oplock_break_get(struct cifsFileInfo *cfile) { cifs_sb_active(cfile->dentry->d_sb); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 94979309698a..39869c3c3efb 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1682,8 +1682,7 @@ cifs_invalidate_mapping(struct inode *inode) /* write back any cached data */ if (inode->i_mapping && inode->i_mapping->nrpages != 0) { rc = filemap_write_and_wait(inode->i_mapping); - if (rc) - cifs_i->write_behind_rc = rc; + mapping_set_error(inode->i_mapping, rc); } invalidate_remote_inode(inode); cifs_fscache_reset_inode_cookie(inode); @@ -1943,10 +1942,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) * the flush returns error? */ rc = filemap_write_and_wait(inode->i_mapping); - if (rc != 0) { - cifsInode->write_behind_rc = rc; - rc = 0; - } + mapping_set_error(inode->i_mapping, rc); + rc = 0; if (attrs->ia_valid & ATTR_SIZE) { rc = cifs_set_file_size(inode, attrs, xid, full_path); @@ -2087,10 +2084,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) * the flush returns error? */ rc = filemap_write_and_wait(inode->i_mapping); - if (rc != 0) { - cifsInode->write_behind_rc = rc; - rc = 0; - } + mapping_set_error(inode->i_mapping, rc); + rc = 0; if (attrs->ia_valid & ATTR_SIZE) { rc = cifs_set_file_size(inode, attrs, xid, full_path); diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 1c681f6a6803..c4e296fe3518 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -577,7 +577,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) * cifs_oplock_break_put() can't be called * from here. Get reference after queueing * succeeded. cifs_oplock_break() will - * synchronize using GlobalSMSSeslock. + * synchronize using cifs_file_list_lock. */ if (queue_work(system_nrt_wq, &netfile->oplock_break)) diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 2a11efd96592..7b01d3f6eed6 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -32,9 +32,6 @@ #include <linux/slab.h> #include "cifs_spnego.h" -extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, - unsigned char *p24); - /* * Checks if this is the first smb session to be reconnected after * the socket has been reestablished (so we know whether to use vc 0). @@ -402,23 +399,22 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, return -EINVAL; } - memcpy(ses->cryptKey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE); + memcpy(ses->ntlmssp->cryptkey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE); /* BB we could decode pblob->NegotiateFlags; some may be useful */ /* In particular we can examine sign flags */ /* BB spec says that if AvId field of MsvAvTimestamp is populated then we must set the MIC field of the AUTHENTICATE_MESSAGE */ - + ses->ntlmssp->server_flags = le32_to_cpu(pblob->NegotiateFlags); tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset); tilen = cpu_to_le16(pblob->TargetInfoArray.Length); - ses->tilen = tilen; - if (ses->tilen) { - ses->tiblob = kmalloc(tilen, GFP_KERNEL); - if (!ses->tiblob) { + if (tilen) { + ses->auth_key.response = kmalloc(tilen, GFP_KERNEL); + if (!ses->auth_key.response) { cERROR(1, "Challenge target info allocation failure"); - ses->tilen = 0; return -ENOMEM; } - memcpy(ses->tiblob, bcc_ptr + tioffset, ses->tilen); + memcpy(ses->auth_key.response, bcc_ptr + tioffset, tilen); + ses->auth_key.len = tilen; } return 0; @@ -443,10 +439,12 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_NTLM; if (ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { flags |= NTLMSSP_NEGOTIATE_SIGN; - if (ses->server->secMode & SECMODE_SIGN_REQUIRED) - flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; + if (!ses->server->session_estab) + flags |= NTLMSSP_NEGOTIATE_KEY_XCH | + NTLMSSP_NEGOTIATE_EXTENDED_SEC; + } sec_blob->NegotiateFlags |= cpu_to_le32(flags); @@ -469,11 +467,9 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, const struct nls_table *nls_cp) { int rc; - unsigned int size; AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; __u32 flags; unsigned char *tmp; - struct ntlmv2_resp ntlmv2_response = {}; memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); sec_blob->MessageType = NtLmAuthenticate; @@ -497,25 +493,19 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, sec_blob->LmChallengeResponse.MaximumLength = 0; sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); - rc = setup_ntlmv2_rsp(ses, (char *)&ntlmv2_response, nls_cp); + rc = setup_ntlmv2_rsp(ses, nls_cp); if (rc) { cERROR(1, "Error %d during NTLMSSP authentication", rc); goto setup_ntlmv2_ret; } - size = sizeof(struct ntlmv2_resp); - memcpy(tmp, (char *)&ntlmv2_response, size); - tmp += size; - if (ses->tilen > 0) { - memcpy(tmp, ses->tiblob, ses->tilen); - tmp += ses->tilen; - } + memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE, + ses->auth_key.len - CIFS_SESS_KEY_SIZE); + tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE; - sec_blob->NtChallengeResponse.Length = cpu_to_le16(size + ses->tilen); + sec_blob->NtChallengeResponse.Length = + cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); sec_blob->NtChallengeResponse.MaximumLength = - cpu_to_le16(size + ses->tilen); - kfree(ses->tiblob); - ses->tiblob = NULL; - ses->tilen = 0; + cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); if (ses->domainName == NULL) { sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); @@ -554,9 +544,19 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, sec_blob->WorkstationName.MaximumLength = 0; tmp += 2; - sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); - sec_blob->SessionKey.Length = 0; - sec_blob->SessionKey.MaximumLength = 0; + if ((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) && + !calc_seckey(ses)) { + memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); + sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); + sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE); + sec_blob->SessionKey.MaximumLength = + cpu_to_le16(CIFS_CPHTXT_SIZE); + tmp += CIFS_CPHTXT_SIZE; + } else { + sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); + sec_blob->SessionKey.Length = 0; + sec_blob->SessionKey.MaximumLength = 0; + } setup_ntlmv2_ret: *buflen = tmp - pbuffer; @@ -600,8 +600,16 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, return -EINVAL; type = ses->server->secType; - cFYI(1, "sess setup type %d", type); + if (type == RawNTLMSSP) { + /* if memory allocation is successful, caller of this function + * frees it. + */ + ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL); + if (!ses->ntlmssp) + return -ENOMEM; + } + ssetup_ntlmssp_authenticate: if (phase == NtLmChallenge) phase = NtLmAuthenticate; /* if ntlmssp, now final phase */ @@ -666,10 +674,14 @@ ssetup_ntlmssp_authenticate: /* no capabilities flags in old lanman negotiation */ pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); - /* BB calculate hash with password */ - /* and copy into bcc */ - calc_lanman_hash(ses->password, ses->cryptKey, + /* Calculate hash with password and copy into bcc_ptr. + * Encryption Key (stored as in cryptkey) gets used if the + * security mode bit in Negottiate Protocol response states + * to use challenge/response method (i.e. Password bit is 1). + */ + + calc_lanman_hash(ses->password, ses->server->cryptkey, ses->server->secMode & SECMODE_PW_ENCRYPT ? true : false, lnm_session_key); @@ -687,24 +699,27 @@ ssetup_ntlmssp_authenticate: ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); #endif } else if (type == NTLM) { - char ntlm_session_key[CIFS_SESS_KEY_SIZE]; - pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); pSMB->req_no_secext.CaseInsensitivePasswordLength = - cpu_to_le16(CIFS_SESS_KEY_SIZE); + cpu_to_le16(CIFS_AUTH_RESP_SIZE); pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(CIFS_SESS_KEY_SIZE); + cpu_to_le16(CIFS_AUTH_RESP_SIZE); + + /* calculate ntlm response and session key */ + rc = setup_ntlm_response(ses); + if (rc) { + cERROR(1, "Error %d during NTLM authentication", rc); + goto ssetup_exit; + } - /* calculate session key */ - SMBNTencrypt(ses->password, ses->cryptKey, ntlm_session_key); + /* copy ntlm response */ + memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, + CIFS_AUTH_RESP_SIZE); + bcc_ptr += CIFS_AUTH_RESP_SIZE; + memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, + CIFS_AUTH_RESP_SIZE); + bcc_ptr += CIFS_AUTH_RESP_SIZE; - cifs_calculate_session_key(&ses->auth_key, - ntlm_session_key, ses->password); - /* copy session key */ - memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE); - bcc_ptr += CIFS_SESS_KEY_SIZE; - memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE); - bcc_ptr += CIFS_SESS_KEY_SIZE; if (ses->capabilities & CAP_UNICODE) { /* unicode strings must be word aligned */ if (iov[0].iov_len % 2) { @@ -715,47 +730,26 @@ ssetup_ntlmssp_authenticate: } else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); } else if (type == NTLMv2) { - char *v2_sess_key = - kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL); - - /* BB FIXME change all users of v2_sess_key to - struct ntlmv2_resp */ - - if (v2_sess_key == NULL) { - rc = -ENOMEM; - goto ssetup_exit; - } - pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); /* LM2 password would be here if we supported it */ pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; - /* cpu_to_le16(LM2_SESS_KEY_SIZE); */ - /* calculate session key */ - rc = setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); + /* calculate nlmv2 response and session key */ + rc = setup_ntlmv2_rsp(ses, nls_cp); if (rc) { cERROR(1, "Error %d during NTLMv2 authentication", rc); - kfree(v2_sess_key); goto ssetup_exit; } - memcpy(bcc_ptr, (char *)v2_sess_key, - sizeof(struct ntlmv2_resp)); - bcc_ptr += sizeof(struct ntlmv2_resp); - kfree(v2_sess_key); + memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, + ses->auth_key.len - CIFS_SESS_KEY_SIZE); + bcc_ptr += ses->auth_key.len - CIFS_SESS_KEY_SIZE; + /* set case sensitive password length after tilen may get * assigned, tilen is 0 otherwise. */ pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(sizeof(struct ntlmv2_resp) + ses->tilen); - if (ses->tilen > 0) { - memcpy(bcc_ptr, ses->tiblob, ses->tilen); - bcc_ptr += ses->tilen; - /* we never did allocate ses->domainName to free */ - kfree(ses->tiblob); - ses->tiblob = NULL; - ses->tilen = 0; - } + cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); if (ses->capabilities & CAP_UNICODE) { if (iov[0].iov_len % 2) { @@ -768,6 +762,7 @@ ssetup_ntlmssp_authenticate: } else if (type == Kerberos) { #ifdef CONFIG_CIFS_UPCALL struct cifs_spnego_msg *msg; + spnego_key = cifs_get_spnego_key(ses); if (IS_ERR(spnego_key)) { rc = PTR_ERR(spnego_key); @@ -785,16 +780,17 @@ ssetup_ntlmssp_authenticate: rc = -EKEYREJECTED; goto ssetup_exit; } - /* bail out if key is too long */ - if (msg->sesskey_len > - sizeof(ses->auth_key.data.krb5)) { - cERROR(1, "Kerberos signing key too long (%u bytes)", - msg->sesskey_len); - rc = -EOVERFLOW; + + ses->auth_key.response = kmalloc(msg->sesskey_len, GFP_KERNEL); + if (!ses->auth_key.response) { + cERROR(1, "Kerberos can't allocate (%u bytes) memory", + msg->sesskey_len); + rc = -ENOMEM; goto ssetup_exit; } + memcpy(ses->auth_key.response, msg->data, msg->sesskey_len); ses->auth_key.len = msg->sesskey_len; - memcpy(ses->auth_key.data.krb5, msg->data, msg->sesskey_len); + pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; capabilities |= CAP_EXTENDED_SECURITY; pSMB->req.Capabilities = cpu_to_le32(capabilities); @@ -897,8 +893,6 @@ ssetup_ntlmssp_authenticate: CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR); /* SMB request buf freed in SendReceive2 */ - cFYI(1, "ssetup rc from sendrecv2 is %d", rc); - pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; smb_buf = (struct smb_hdr *)iov[0].iov_base; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index a66c91eb6eb4..e0588cdf4cc5 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -543,7 +543,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(midQ->resp_buf, - &ses->server->session_key, + ses->server, midQ->sequence_number+1); if (rc) { cERROR(1, "Unexpected SMB signature"); @@ -731,7 +731,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(out_buf, - &ses->server->session_key, + ses->server, midQ->sequence_number+1); if (rc) { cERROR(1, "Unexpected SMB signature"); @@ -981,7 +981,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(out_buf, - &ses->server->session_key, + ses->server, midQ->sequence_number+1); if (rc) { cERROR(1, "Unexpected SMB signature"); diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 7993b96ca348..5ea57c8c7f97 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -306,16 +306,16 @@ static int coda_statfs(struct dentry *dentry, struct kstatfs *buf) /* init_coda: used by filesystems.c to register coda */ -static int coda_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *coda_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_nodev(fs_type, flags, data, coda_fill_super, mnt); + return mount_nodev(fs_type, flags, data, coda_fill_super); } struct file_system_type coda_fs_type = { .owner = THIS_MODULE, .name = "coda", - .get_sb = coda_get_sb, + .mount = coda_mount, .kill_sb = kill_anon_super, .fs_flags = FS_BINARY_MOUNTDATA, }; diff --git a/fs/compat.c b/fs/compat.c index 52cfeb61da77..ff66c0d7583d 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -606,14 +606,14 @@ ssize_t compat_rw_copy_check_uvector(int type, /* * Single unix specification: * We should -EINVAL if an element length is not >= 0 and fitting an - * ssize_t. The total length is fitting an ssize_t + * ssize_t. * - * Be careful here because iov_len is a size_t not an ssize_t + * In Linux, the total length is limited to MAX_RW_COUNT, there is + * no overflow possibility. */ tot_len = 0; ret = -EINVAL; for (seg = 0; seg < nr_segs; seg++) { - compat_ssize_t tmp = tot_len; compat_uptr_t buf; compat_ssize_t len; @@ -624,13 +624,13 @@ ssize_t compat_rw_copy_check_uvector(int type, } if (len < 0) /* size_t not fitting in compat_ssize_t .. */ goto out; - tot_len += len; - if (tot_len < tmp) /* maths overflow on the compat_ssize_t */ - goto out; if (!access_ok(vrfy_dir(type), compat_ptr(buf), len)) { ret = -EFAULT; goto out; } + if (len > MAX_RW_COUNT - tot_len) + len = MAX_RW_COUNT - tot_len; + tot_len += len; iov->iov_base = compat_ptr(buf); iov->iov_len = (compat_size_t) len; uvector++; diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index 8c8d64230c2d..7d3607febe1c 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c @@ -104,16 +104,16 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent) return 0; } -static int configfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *configfs_do_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_single(fs_type, flags, data, configfs_fill_super, mnt); + return mount_single(fs_type, flags, data, configfs_fill_super); } static struct file_system_type configfs_fs_type = { .owner = THIS_MODULE, .name = "configfs", - .get_sb = configfs_get_sb, + .mount = configfs_do_mount, .kill_sb = kill_litter_super, }; diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 1e7a33028d33..32fd5fe9ca0e 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -533,17 +533,16 @@ static const struct super_operations cramfs_ops = { .statfs = cramfs_statfs, }; -static int cramfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *cramfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, cramfs_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, cramfs_fill_super); } static struct file_system_type cramfs_fs_type = { .owner = THIS_MODULE, .name = "cramfs", - .get_sb = cramfs_get_sb, + .mount = cramfs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index a4ed8380e98a..37a8ca7c1222 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -135,17 +135,17 @@ static int debug_fill_super(struct super_block *sb, void *data, int silent) return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files); } -static int debug_get_sb(struct file_system_type *fs_type, +static struct dentry *debug_mount(struct file_system_type *fs_type, int flags, const char *dev_name, - void *data, struct vfsmount *mnt) + void *data) { - return get_sb_single(fs_type, flags, data, debug_fill_super, mnt); + return mount_single(fs_type, flags, data, debug_fill_super); } static struct file_system_type debug_fs_type = { .owner = THIS_MODULE, .name = "debugfs", - .get_sb = debug_get_sb, + .mount = debug_mount, .kill_sb = kill_litter_super, }; diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 8b3ffd5b5235..1bb547c9cad6 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -331,7 +331,7 @@ static int compare_init_pts_sb(struct super_block *s, void *p) } /* - * devpts_get_sb() + * devpts_mount() * * If the '-o newinstance' mount option was specified, mount a new * (private) instance of devpts. PTYs created in this instance are @@ -345,20 +345,20 @@ static int compare_init_pts_sb(struct super_block *s, void *p) * semantics in devpts while preserving backward compatibility of the * current 'single-namespace' semantics. i.e all mounts of devpts * without the 'newinstance' mount option should bind to the initial - * kernel mount, like get_sb_single(). + * kernel mount, like mount_single(). * * Mounts with 'newinstance' option create a new, private namespace. * * NOTE: * - * For single-mount semantics, devpts cannot use get_sb_single(), - * because get_sb_single()/sget() find and use the super-block from + * For single-mount semantics, devpts cannot use mount_single(), + * because mount_single()/sget() find and use the super-block from * the most recent mount of devpts. But that recent mount may be a - * 'newinstance' mount and get_sb_single() would pick the newinstance + * 'newinstance' mount and mount_single() would pick the newinstance * super-block instead of the initial super-block. */ -static int devpts_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *devpts_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { int error; struct pts_mount_opts opts; @@ -366,7 +366,7 @@ static int devpts_get_sb(struct file_system_type *fs_type, error = parse_mount_options(data, PARSE_MOUNT, &opts); if (error) - return error; + return ERR_PTR(error); if (opts.newinstance) s = sget(fs_type, NULL, set_anon_super, NULL); @@ -374,7 +374,7 @@ static int devpts_get_sb(struct file_system_type *fs_type, s = sget(fs_type, compare_init_pts_sb, set_anon_super, NULL); if (IS_ERR(s)) - return PTR_ERR(s); + return ERR_CAST(s); if (!s->s_root) { s->s_flags = flags; @@ -390,13 +390,11 @@ static int devpts_get_sb(struct file_system_type *fs_type, if (error) goto out_undo_sget; - simple_set_mnt(mnt, s); - - return 0; + return dget(s->s_root); out_undo_sget: deactivate_locked_super(s); - return error; + return ERR_PTR(error); } #else @@ -404,10 +402,10 @@ out_undo_sget: * This supports only the legacy single-instance semantics (no * multiple-instance semantics) */ -static int devpts_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *devpts_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) { - return get_sb_single(fs_type, flags, data, devpts_fill_super, mnt); + return mount_single(fs_type, flags, data, devpts_fill_super); } #endif @@ -421,7 +419,7 @@ static void devpts_kill_sb(struct super_block *sb) static struct file_system_type devpts_fs_type = { .name = "devpts", - .get_sb = devpts_get_sb, + .mount = devpts_mount, .kill_sb = devpts_kill_sb, }; diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index cbd4e18adb20..8585934712d4 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -540,9 +540,8 @@ out: * ecryptfs_interpose to perform most of the linking * ecryptfs_interpose(): links the lower filesystem into ecryptfs (inode.c) */ -static int ecryptfs_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *raw_data, - struct vfsmount *mnt) +static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *raw_data) { struct super_block *s; struct ecryptfs_sb_info *sbi; @@ -607,8 +606,7 @@ static int ecryptfs_get_sb(struct file_system_type *fs_type, int flags, err = "Reading sb failed"; goto out; } - simple_set_mnt(mnt, s); - return 0; + return dget(s->s_root); out: if (sbi) { @@ -616,7 +614,7 @@ out: kmem_cache_free(ecryptfs_sb_info_cache, sbi); } printk(KERN_ERR "%s; rc = [%d]\n", err, rc); - return rc; + return ERR_PTR(rc); } /** @@ -639,7 +637,7 @@ static void ecryptfs_kill_block_super(struct super_block *sb) static struct file_system_type ecryptfs_fs_type = { .owner = THIS_MODULE, .name = "ecryptfs", - .get_sb = ecryptfs_get_sb, + .mount = ecryptfs_mount, .kill_sb = ecryptfs_kill_block_super, .fs_flags = 0 }; diff --git a/fs/efs/super.c b/fs/efs/super.c index f04942810818..5073a07652cc 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -20,16 +20,16 @@ static int efs_statfs(struct dentry *dentry, struct kstatfs *buf); static int efs_fill_super(struct super_block *s, void *d, int silent); -static int efs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *efs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, efs_fill_super, mnt); + return mount_bdev(fs_type, flags, dev_name, data, efs_fill_super); } static struct file_system_type efs_fs_type = { .owner = THIS_MODULE, .name = "efs", - .get_sb = efs_get_sb, + .mount = efs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/exofs/super.c b/fs/exofs/super.c index 047e92fa3af8..79c3ae6e0456 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c @@ -659,19 +659,19 @@ free_bdi: /* * Set up the superblock (calls exofs_fill_super eventually) */ -static int exofs_get_sb(struct file_system_type *type, +static struct dentry *exofs_mount(struct file_system_type *type, int flags, const char *dev_name, - void *data, struct vfsmount *mnt) + void *data) { struct exofs_mountopt opts; int ret; ret = parse_options(data, &opts); if (ret) - return ret; + return ERR_PTR(ret); opts.dev_name = dev_name; - return get_sb_nodev(type, flags, &opts, exofs_fill_super, mnt); + return mount_nodev(type, flags, &opts, exofs_fill_super); } /* @@ -809,7 +809,7 @@ static const struct export_operations exofs_export_ops = { static struct file_system_type exofs_type = { .owner = THIS_MODULE, .name = "exofs", - .get_sb = exofs_get_sb, + .mount = exofs_mount, .kill_sb = generic_shutdown_super, }; diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 0901320671da..d89e0b6a2d78 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -1356,10 +1356,10 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf) return 0; } -static int ext2_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *ext2_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super, mnt); + return mount_bdev(fs_type, flags, dev_name, data, ext2_fill_super); } #ifdef CONFIG_QUOTA @@ -1473,7 +1473,7 @@ out: static struct file_system_type ext2_fs_type = { .owner = THIS_MODULE, .name = "ext2", - .get_sb = ext2_get_sb, + .mount = ext2_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index db87413d3479..2fedaf8b5012 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -3020,16 +3020,16 @@ out: #endif -static int ext3_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *ext3_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, ext3_fill_super, mnt); + return mount_bdev(fs_type, flags, dev_name, data, ext3_fill_super); } static struct file_system_type ext3_fs_type = { .owner = THIS_MODULE, .name = "ext3", - .get_sb = ext3_get_sb, + .mount = ext3_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 0348ce066592..40131b777af6 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -73,8 +73,8 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf); static int ext4_unfreeze(struct super_block *sb); static void ext4_write_super(struct super_block *sb); static int ext4_freeze(struct super_block *sb); -static int ext4_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct vfsmount *mnt); +static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data); static void ext4_destroy_lazyinit_thread(void); static void ext4_unregister_li_request(struct super_block *sb); @@ -82,7 +82,7 @@ static void ext4_unregister_li_request(struct super_block *sb); static struct file_system_type ext3_fs_type = { .owner = THIS_MODULE, .name = "ext3", - .get_sb = ext4_get_sb, + .mount = ext4_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; @@ -4667,17 +4667,17 @@ out: #endif -static int ext4_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super,mnt); + return mount_bdev(fs_type, flags, dev_name, data, ext4_fill_super); } #if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) static struct file_system_type ext2_fs_type = { .owner = THIS_MODULE, .name = "ext2", - .get_sb = ext4_get_sb, + .mount = ext4_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; @@ -4722,7 +4722,7 @@ static inline void unregister_as_ext3(void) { } static struct file_system_type ext4_fs_type = { .owner = THIS_MODULE, .name = "ext4", - .get_sb = ext4_get_sb, + .mount = ext4_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index bbca5c186ae7..3345aabd1dd7 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -675,18 +675,17 @@ static int msdos_fill_super(struct super_block *sb, void *data, int silent) return 0; } -static int msdos_get_sb(struct file_system_type *fs_type, +static struct dentry *msdos_mount(struct file_system_type *fs_type, int flags, const char *dev_name, - void *data, struct vfsmount *mnt) + void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, msdos_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, msdos_fill_super); } static struct file_system_type msdos_fs_type = { .owner = THIS_MODULE, .name = "msdos", - .get_sb = msdos_get_sb, + .mount = msdos_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index 6f0f6c9a0152..b936703b8924 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -1071,18 +1071,17 @@ static int vfat_fill_super(struct super_block *sb, void *data, int silent) return 0; } -static int vfat_get_sb(struct file_system_type *fs_type, +static struct dentry *vfat_mount(struct file_system_type *fs_type, int flags, const char *dev_name, - void *data, struct vfsmount *mnt) + void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, vfat_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, vfat_fill_super); } static struct file_system_type vfat_fs_type = { .owner = THIS_MODULE, .name = "vfat", - .get_sb = vfat_get_sb, + .mount = vfat_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index 71b0148b8784..9d1c99558389 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c @@ -246,17 +246,16 @@ out: /* * The usual module blurb. */ -static int vxfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *vxfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, vxfs_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, vxfs_fill_super); } static struct file_system_type vxfs_fs_type = { .owner = THIS_MODULE, .name = "vxfs", - .get_sb = vxfs_get_sb, + .mount = vxfs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 4eba07661e5c..85542a7daf40 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -322,12 +322,10 @@ static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent) return 0; } -static int fuse_ctl_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *raw_data, - struct vfsmount *mnt) +static struct dentry *fuse_ctl_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *raw_data) { - return get_sb_single(fs_type, flags, raw_data, - fuse_ctl_fill_super, mnt); + return mount_single(fs_type, flags, raw_data, fuse_ctl_fill_super); } static void fuse_ctl_kill_sb(struct super_block *sb) @@ -346,7 +344,7 @@ static void fuse_ctl_kill_sb(struct super_block *sb) static struct file_system_type fuse_ctl_fs_type = { .owner = THIS_MODULE, .name = "fusectl", - .get_sb = fuse_ctl_get_sb, + .mount = fuse_ctl_mount, .kill_sb = fuse_ctl_kill_sb, }; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index da9e6e11374c..cfce3ad86a92 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -1041,11 +1041,11 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) return err; } -static int fuse_get_sb(struct file_system_type *fs_type, +static struct dentry *fuse_mount(struct file_system_type *fs_type, int flags, const char *dev_name, - void *raw_data, struct vfsmount *mnt) + void *raw_data) { - return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt); + return mount_nodev(fs_type, flags, raw_data, fuse_fill_super); } static void fuse_kill_sb_anon(struct super_block *sb) @@ -1065,17 +1065,16 @@ static struct file_system_type fuse_fs_type = { .owner = THIS_MODULE, .name = "fuse", .fs_flags = FS_HAS_SUBTYPE, - .get_sb = fuse_get_sb, + .mount = fuse_mount, .kill_sb = fuse_kill_sb_anon, }; #ifdef CONFIG_BLOCK -static int fuse_get_sb_blk(struct file_system_type *fs_type, +static struct dentry *fuse_mount_blk(struct file_system_type *fs_type, int flags, const char *dev_name, - void *raw_data, struct vfsmount *mnt) + void *raw_data) { - return get_sb_bdev(fs_type, flags, dev_name, raw_data, fuse_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, raw_data, fuse_fill_super); } static void fuse_kill_sb_blk(struct super_block *sb) @@ -1094,7 +1093,7 @@ static void fuse_kill_sb_blk(struct super_block *sb) static struct file_system_type fuseblk_fs_type = { .owner = THIS_MODULE, .name = "fuseblk", - .get_sb = fuse_get_sb_blk, + .mount = fuse_mount_blk, .kill_sb = fuse_kill_sb_blk, .fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE, }; diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index cade1acbcea9..3eb1393f7b81 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -1250,12 +1250,11 @@ static int test_gfs2_super(struct super_block *s, void *ptr) } /** - * gfs2_get_sb - Get the GFS2 superblock + * gfs2_mount - Get the GFS2 superblock * @fs_type: The GFS2 filesystem type * @flags: Mount flags * @dev_name: The name of the device * @data: The mount arguments - * @mnt: The vfsmnt for this mount * * Q. Why not use get_sb_bdev() ? * A. We need to select one of two root directories to mount, independent @@ -1264,8 +1263,8 @@ static int test_gfs2_super(struct super_block *s, void *ptr) * Returns: 0 or -ve on error */ -static int gfs2_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) { struct block_device *bdev; struct super_block *s; @@ -1279,7 +1278,7 @@ static int gfs2_get_sb(struct file_system_type *fs_type, int flags, bdev = open_bdev_exclusive(dev_name, mode, fs_type); if (IS_ERR(bdev)) - return PTR_ERR(bdev); + return ERR_CAST(bdev); /* * once the super is inserted into the list by sget, s_umount @@ -1298,6 +1297,9 @@ static int gfs2_get_sb(struct file_system_type *fs_type, int flags, if (IS_ERR(s)) goto error_bdev; + if (s->s_root) + close_bdev_exclusive(bdev, mode); + memset(&args, 0, sizeof(args)); args.ar_quota = GFS2_QUOTA_DEFAULT; args.ar_data = GFS2_DATA_DEFAULT; @@ -1309,17 +1311,13 @@ static int gfs2_get_sb(struct file_system_type *fs_type, int flags, error = gfs2_mount_args(&args, data); if (error) { printk(KERN_WARNING "GFS2: can't parse mount arguments\n"); - if (s->s_root) - goto error_super; - deactivate_locked_super(s); - return error; + goto error_super; } if (s->s_root) { error = -EBUSY; if ((flags ^ s->s_flags) & MS_RDONLY) goto error_super; - close_bdev_exclusive(bdev, mode); } else { char b[BDEVNAME_SIZE]; @@ -1328,27 +1326,24 @@ static int gfs2_get_sb(struct file_system_type *fs_type, int flags, strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id)); sb_set_blocksize(s, block_size(bdev)); error = fill_super(s, &args, flags & MS_SILENT ? 1 : 0); - if (error) { - deactivate_locked_super(s); - return error; - } + if (error) + goto error_super; s->s_flags |= MS_ACTIVE; bdev->bd_super = s; } sdp = s->s_fs_info; - mnt->mnt_sb = s; if (args.ar_meta) - mnt->mnt_root = dget(sdp->sd_master_dir); + return dget(sdp->sd_master_dir); else - mnt->mnt_root = dget(sdp->sd_root_dir); - return 0; + return dget(sdp->sd_root_dir); error_super: deactivate_locked_super(s); + return ERR_PTR(error); error_bdev: close_bdev_exclusive(bdev, mode); - return error; + return ERR_PTR(error); } static int set_meta_super(struct super_block *s, void *ptr) @@ -1356,8 +1351,8 @@ static int set_meta_super(struct super_block *s, void *ptr) return -EINVAL; } -static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *gfs2_mount_meta(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { struct super_block *s; struct gfs2_sbd *sdp; @@ -1368,23 +1363,21 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags, if (error) { printk(KERN_WARNING "GFS2: path_lookup on %s returned error %d\n", dev_name, error); - return error; + return ERR_PTR(error); } s = sget(&gfs2_fs_type, test_gfs2_super, set_meta_super, path.dentry->d_inode->i_sb->s_bdev); path_put(&path); if (IS_ERR(s)) { printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n"); - return PTR_ERR(s); + return ERR_CAST(s); } if ((flags ^ s->s_flags) & MS_RDONLY) { deactivate_locked_super(s); - return -EBUSY; + return ERR_PTR(-EBUSY); } sdp = s->s_fs_info; - mnt->mnt_sb = s; - mnt->mnt_root = dget(sdp->sd_master_dir); - return 0; + return dget(sdp->sd_master_dir); } static void gfs2_kill_sb(struct super_block *sb) @@ -1410,7 +1403,7 @@ static void gfs2_kill_sb(struct super_block *sb) struct file_system_type gfs2_fs_type = { .name = "gfs2", .fs_flags = FS_REQUIRES_DEV, - .get_sb = gfs2_get_sb, + .mount = gfs2_mount, .kill_sb = gfs2_kill_sb, .owner = THIS_MODULE, }; @@ -1418,7 +1411,7 @@ struct file_system_type gfs2_fs_type = { struct file_system_type gfs2meta_fs_type = { .name = "gfs2meta", .fs_flags = FS_REQUIRES_DEV, - .get_sb = gfs2_get_sb_meta, + .mount = gfs2_mount_meta, .owner = THIS_MODULE, }; diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 6ee1586f2334..4824c27cebb8 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -441,17 +441,16 @@ bail: return res; } -static int hfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - struct vfsmount *mnt) +static struct dentry *hfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, hfs_fill_super, mnt); + return mount_bdev(fs_type, flags, dev_name, data, hfs_fill_super); } static struct file_system_type hfs_fs_type = { .owner = THIS_MODULE, .name = "hfs", - .get_sb = hfs_get_sb, + .mount = hfs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 9a88d7536103..52cc746d3ba3 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -495,18 +495,16 @@ static void hfsplus_destroy_inode(struct inode *inode) #define HFSPLUS_INODE_SIZE sizeof(struct hfsplus_inode_info) -static int hfsplus_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - struct vfsmount *mnt) +static struct dentry *hfsplus_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, hfsplus_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, hfsplus_fill_super); } static struct file_system_type hfsplus_fs_type = { .owner = THIS_MODULE, .name = "hfsplus", - .get_sb = hfsplus_get_sb, + .mount = hfsplus_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index cd7c93917cc7..2c0f148a49e6 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -962,11 +962,11 @@ out: return err; } -static int hostfs_read_sb(struct file_system_type *type, +static struct dentry *hostfs_read_sb(struct file_system_type *type, int flags, const char *dev_name, - void *data, struct vfsmount *mnt) + void *data) { - return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt); + return mount_nodev(type, flags, data, hostfs_fill_sb_common); } static void hostfs_kill_sb(struct super_block *s) @@ -978,7 +978,7 @@ static void hostfs_kill_sb(struct super_block *s) static struct file_system_type hostfs_type = { .owner = THIS_MODULE, .name = "hostfs", - .get_sb = hostfs_read_sb, + .mount = hostfs_read_sb, .kill_sb = hostfs_kill_sb, .fs_flags = 0, }; diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index c969a1aa163a..bb69389972eb 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -686,17 +686,16 @@ bail0: return -EINVAL; } -static int hpfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *hpfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, hpfs_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, hpfs_fill_super); } static struct file_system_type hpfs_fs_type = { .owner = THIS_MODULE, .name = "hpfs", - .get_sb = hpfs_get_sb, + .mount = hpfs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c index 4e2a45ea6140..f702b5f713fc 100644 --- a/fs/hppfs/hppfs.c +++ b/fs/hppfs/hppfs.c @@ -748,17 +748,17 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent) return(err); } -static int hppfs_read_super(struct file_system_type *type, +static struct dentry *hppfs_read_super(struct file_system_type *type, int flags, const char *dev_name, - void *data, struct vfsmount *mnt) + void *data) { - return get_sb_nodev(type, flags, data, hppfs_fill_super, mnt); + return mount_nodev(type, flags, data, hppfs_fill_super); } static struct file_system_type hppfs_type = { .owner = THIS_MODULE, .name = "hppfs", - .get_sb = hppfs_read_super, + .mount = hppfs_read_super, .kill_sb = kill_anon_super, .fs_flags = 0, }; diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index b14be3f781c7..d6cfac1f0a40 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -896,15 +896,15 @@ void hugetlb_put_quota(struct address_space *mapping, long delta) } } -static int hugetlbfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *hugetlbfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_nodev(fs_type, flags, data, hugetlbfs_fill_super, mnt); + return mount_nodev(fs_type, flags, data, hugetlbfs_fill_super); } static struct file_system_type hugetlbfs_fs_type = { .name = "hugetlbfs", - .get_sb = hugetlbfs_get_sb, + .mount = hugetlbfs_mount, .kill_sb = kill_litter_super, }; diff --git a/fs/internal.h b/fs/internal.h index ebad3b90752d..e43b9a4dbf4e 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -106,5 +106,5 @@ extern void release_open_intent(struct nameidata *); * inode.c */ extern int get_nr_dirty_inodes(void); -extern int evict_inodes(struct super_block *); +extern void evict_inodes(struct super_block *); extern int invalidate_inodes(struct super_block *); diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 79cf7f616bbe..bfdeb82a53be 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -1507,17 +1507,16 @@ struct inode *isofs_iget(struct super_block *sb, return inode; } -static int isofs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *isofs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, isofs_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, isofs_fill_super); } static struct file_system_type iso9660_fs_type = { .owner = THIS_MODULE, .name = "iso9660", - .get_sb = isofs_get_sb, + .mount = isofs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index d1ae5dfc22b9..c86041b866a4 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -179,12 +179,11 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent) return ret; } -static int jffs2_get_sb(struct file_system_type *fs_type, +static struct dentry *jffs2_mount(struct file_system_type *fs_type, int flags, const char *dev_name, - void *data, struct vfsmount *mnt) + void *data) { - return get_sb_mtd(fs_type, flags, dev_name, data, jffs2_fill_super, - mnt); + return mount_mtd(fs_type, flags, dev_name, data, jffs2_fill_super); } static void jffs2_put_super (struct super_block *sb) @@ -229,7 +228,7 @@ static void jffs2_kill_sb(struct super_block *sb) static struct file_system_type jffs2_fs_type = { .owner = THIS_MODULE, .name = "jffs2", - .get_sb = jffs2_get_sb, + .mount = jffs2_mount, .kill_sb = jffs2_kill_sb, }; diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 68eee2bf629e..0669fc1cc3bf 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -583,11 +583,10 @@ static int jfs_unfreeze(struct super_block *sb) return 0; } -static int jfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *jfs_do_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, jfs_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, jfs_fill_super); } static int jfs_sync_fs(struct super_block *sb, int wait) @@ -770,7 +769,7 @@ static const struct export_operations jfs_export_operations = { static struct file_system_type jfs_fs_type = { .owner = THIS_MODULE, .name = "jfs", - .get_sb = jfs_get_sb, + .mount = jfs_do_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/libfs.c b/fs/libfs.c index 304a5132ca27..a3accdf528ad 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -201,9 +201,8 @@ static const struct super_operations simple_super_operations = { * Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that * will never be mountable) */ -int get_sb_pseudo(struct file_system_type *fs_type, char *name, - const struct super_operations *ops, unsigned long magic, - struct vfsmount *mnt) +struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name, + const struct super_operations *ops, unsigned long magic) { struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL); struct dentry *dentry; @@ -211,7 +210,7 @@ int get_sb_pseudo(struct file_system_type *fs_type, char *name, struct qstr d_name = {.name = name, .len = strlen(name)}; if (IS_ERR(s)) - return PTR_ERR(s); + return ERR_CAST(s); s->s_flags = MS_NOUSER; s->s_maxbytes = MAX_LFS_FILESIZE; @@ -241,12 +240,11 @@ int get_sb_pseudo(struct file_system_type *fs_type, char *name, d_instantiate(dentry, root); s->s_root = dentry; s->s_flags |= MS_ACTIVE; - simple_set_mnt(mnt, s); - return 0; + return dget(s->s_root); Enomem: deactivate_locked_super(s); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) @@ -951,7 +949,7 @@ EXPORT_SYMBOL(dcache_dir_lseek); EXPORT_SYMBOL(dcache_dir_open); EXPORT_SYMBOL(dcache_readdir); EXPORT_SYMBOL(generic_read_dir); -EXPORT_SYMBOL(get_sb_pseudo); +EXPORT_SYMBOL(mount_pseudo); EXPORT_SYMBOL(simple_write_begin); EXPORT_SYMBOL(simple_write_end); EXPORT_SYMBOL(simple_dir_inode_operations); diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c index 9bd2ce2a3040..92ca6fbe09bd 100644 --- a/fs/logfs/dev_bdev.c +++ b/fs/logfs/dev_bdev.c @@ -298,9 +298,9 @@ static int bdev_write_sb(struct super_block *sb, struct page *page) return sync_request(page, bdev, WRITE); } -static void bdev_put_device(struct super_block *sb) +static void bdev_put_device(struct logfs_super *s) { - close_bdev_exclusive(logfs_super(sb)->s_bdev, FMODE_READ|FMODE_WRITE); + close_bdev_exclusive(s->s_bdev, FMODE_READ|FMODE_WRITE); } static int bdev_can_write_buf(struct super_block *sb, u64 ofs) @@ -320,8 +320,8 @@ static const struct logfs_device_ops bd_devops = { .put_device = bdev_put_device, }; -int logfs_get_sb_bdev(struct file_system_type *type, int flags, - const char *devname, struct vfsmount *mnt) +int logfs_get_sb_bdev(struct logfs_super *p, struct file_system_type *type, + const char *devname) { struct block_device *bdev; @@ -332,8 +332,11 @@ int logfs_get_sb_bdev(struct file_system_type *type, int flags, if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) { int mtdnr = MINOR(bdev->bd_dev); close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE); - return logfs_get_sb_mtd(type, flags, mtdnr, mnt); + return logfs_get_sb_mtd(p, mtdnr); } - return logfs_get_sb_device(type, flags, NULL, bdev, &bd_devops, mnt); + p->s_bdev = bdev; + p->s_mtd = NULL; + p->s_devops = &bd_devops; + return 0; } diff --git a/fs/logfs/dev_mtd.c b/fs/logfs/dev_mtd.c index a85d47d13e4b..7466e9dcc8c5 100644 --- a/fs/logfs/dev_mtd.c +++ b/fs/logfs/dev_mtd.c @@ -230,9 +230,9 @@ static void mtd_writeseg(struct super_block *sb, u64 ofs, size_t len) __mtd_writeseg(sb, ofs, ofs >> PAGE_SHIFT, len >> PAGE_SHIFT); } -static void mtd_put_device(struct super_block *sb) +static void mtd_put_device(struct logfs_super *s) { - put_mtd_device(logfs_super(sb)->s_mtd); + put_mtd_device(s->s_mtd); } static int mtd_can_write_buf(struct super_block *sb, u64 ofs) @@ -265,14 +265,14 @@ static const struct logfs_device_ops mtd_devops = { .put_device = mtd_put_device, }; -int logfs_get_sb_mtd(struct file_system_type *type, int flags, - int mtdnr, struct vfsmount *mnt) +int logfs_get_sb_mtd(struct logfs_super *s, int mtdnr) { - struct mtd_info *mtd; - const struct logfs_device_ops *devops = &mtd_devops; - - mtd = get_mtd_device(NULL, mtdnr); + struct mtd_info *mtd = get_mtd_device(NULL, mtdnr); if (IS_ERR(mtd)) return PTR_ERR(mtd); - return logfs_get_sb_device(type, flags, mtd, NULL, devops, mnt); + + s->s_bdev = NULL; + s->s_mtd = mtd; + s->s_devops = &mtd_devops; + return 0; } diff --git a/fs/logfs/logfs.h b/fs/logfs/logfs.h index b8786264d243..cd51a36b37f0 100644 --- a/fs/logfs/logfs.h +++ b/fs/logfs/logfs.h @@ -136,6 +136,7 @@ struct logfs_area_ops { int (*erase_segment)(struct logfs_area *area); }; +struct logfs_super; /* forward */ /** * struct logfs_device_ops - device access operations * @@ -156,7 +157,7 @@ struct logfs_device_ops { int ensure_write); int (*can_write_buf)(struct super_block *sb, u64 ofs); void (*sync)(struct super_block *sb); - void (*put_device)(struct super_block *sb); + void (*put_device)(struct logfs_super *s); }; /** @@ -471,11 +472,13 @@ void logfs_compr_exit(void); /* dev_bdev.c */ #ifdef CONFIG_BLOCK -int logfs_get_sb_bdev(struct file_system_type *type, int flags, - const char *devname, struct vfsmount *mnt); +int logfs_get_sb_bdev(struct logfs_super *s, + struct file_system_type *type, + const char *devname); #else -static inline int logfs_get_sb_bdev(struct file_system_type *type, int flags, - const char *devname, struct vfsmount *mnt) +static inline int logfs_get_sb_bdev(struct logfs_super *s, + struct file_system_type *type, + const char *devname) { return -ENODEV; } @@ -483,11 +486,9 @@ static inline int logfs_get_sb_bdev(struct file_system_type *type, int flags, /* dev_mtd.c */ #ifdef CONFIG_MTD -int logfs_get_sb_mtd(struct file_system_type *type, int flags, - int mtdnr, struct vfsmount *mnt); +int logfs_get_sb_mtd(struct logfs_super *s, int mtdnr) #else -static inline int logfs_get_sb_mtd(struct file_system_type *type, int flags, - int mtdnr, struct vfsmount *mnt) +static inline int logfs_get_sb_mtd(struct logfs_super *s, int mtdnr) { return -ENODEV; } @@ -619,9 +620,6 @@ void emergency_read_end(struct page *page); void logfs_crash_dump(struct super_block *sb); void *memchr_inv(const void *s, int c, size_t n); int logfs_statfs(struct dentry *dentry, struct kstatfs *stats); -int logfs_get_sb_device(struct file_system_type *type, int flags, - struct mtd_info *mtd, struct block_device *bdev, - const struct logfs_device_ops *devops, struct vfsmount *mnt); int logfs_check_ds(struct logfs_disk_super *ds); int logfs_write_sb(struct super_block *sb); diff --git a/fs/logfs/super.c b/fs/logfs/super.c index 5336155c5d81..33435e4b14d2 100644 --- a/fs/logfs/super.c +++ b/fs/logfs/super.c @@ -325,7 +325,7 @@ static int logfs_make_writeable(struct super_block *sb) return 0; } -static int logfs_get_sb_final(struct super_block *sb, struct vfsmount *mnt) +static int logfs_get_sb_final(struct super_block *sb) { struct logfs_super *super = logfs_super(sb); struct inode *rootdir; @@ -356,7 +356,6 @@ static int logfs_get_sb_final(struct super_block *sb, struct vfsmount *mnt) } log_super("LogFS: Finished mounting\n"); - simple_set_mnt(mnt, sb); return 0; fail: @@ -529,43 +528,37 @@ static void logfs_kill_sb(struct super_block *sb) logfs_cleanup_rw(sb); if (super->s_erase_page) __free_page(super->s_erase_page); - super->s_devops->put_device(sb); + super->s_devops->put_device(super); logfs_mempool_destroy(super->s_btree_pool); logfs_mempool_destroy(super->s_alias_pool); kfree(super); log_super("LogFS: Finished unmounting\n"); } -int logfs_get_sb_device(struct file_system_type *type, int flags, - struct mtd_info *mtd, struct block_device *bdev, - const struct logfs_device_ops *devops, struct vfsmount *mnt) +static struct dentry *logfs_get_sb_device(struct logfs_super *super, + struct file_system_type *type, int flags) { - struct logfs_super *super; struct super_block *sb; int err = -ENOMEM; static int mount_count; log_super("LogFS: Start mount %x\n", mount_count++); - super = kzalloc(sizeof(*super), GFP_KERNEL); - if (!super) - goto err0; - super->s_mtd = mtd; - super->s_bdev = bdev; err = -EINVAL; sb = sget(type, logfs_sb_test, logfs_sb_set, super); - if (IS_ERR(sb)) - goto err0; + if (IS_ERR(sb)) { + super->s_devops->put_device(super); + kfree(super); + return ERR_CAST(sb); + } if (sb->s_root) { /* Device is already in use */ - err = 0; - simple_set_mnt(mnt, sb); - goto err0; + super->s_devops->put_device(super); + kfree(super); + return dget(sb->s_root); } - super->s_devops = devops; - /* * sb->s_maxbytes is limited to 8TB. On 32bit systems, the page cache * only covers 16TB and the upper 8TB are used for indirect blocks. @@ -581,10 +574,12 @@ int logfs_get_sb_device(struct file_system_type *type, int flags, goto err1; sb->s_flags |= MS_ACTIVE; - err = logfs_get_sb_final(sb, mnt); - if (err) + err = logfs_get_sb_final(sb); + if (err) { deactivate_locked_super(sb); - return err; + return ERR_PTR(err); + } + return dget(sb->s_root); err1: /* no ->s_root, no ->put_super() */ @@ -592,37 +587,45 @@ err1: iput(super->s_segfile_inode); iput(super->s_mapping_inode); deactivate_locked_super(sb); - return err; -err0: - kfree(super); - //devops->put_device(sb); - return err; + return ERR_PTR(err); } -static int logfs_get_sb(struct file_system_type *type, int flags, - const char *devname, void *data, struct vfsmount *mnt) +static struct dentry *logfs_mount(struct file_system_type *type, int flags, + const char *devname, void *data) { ulong mtdnr; + struct logfs_super *super; + int err; - if (!devname) - return logfs_get_sb_bdev(type, flags, devname, mnt); - if (strncmp(devname, "mtd", 3)) - return logfs_get_sb_bdev(type, flags, devname, mnt); + super = kzalloc(sizeof(*super), GFP_KERNEL); + if (!super) + return ERR_PTR(-ENOMEM); - { + if (!devname) + err = logfs_get_sb_bdev(super, type, devname); + else if (strncmp(devname, "mtd", 3)) + err = logfs_get_sb_bdev(super, type, devname); + else { char *garbage; mtdnr = simple_strtoul(devname+3, &garbage, 0); if (*garbage) - return -EINVAL; + err = -EINVAL; + else + err = logfs_get_sb_mtd(super, mtdnr); + } + + if (err) { + kfree(super); + return ERR_PTR(err); } - return logfs_get_sb_mtd(type, flags, mtdnr, mnt); + return logfs_get_sb_device(super, type, flags); } static struct file_system_type logfs_fs_type = { .owner = THIS_MODULE, .name = "logfs", - .get_sb = logfs_get_sb, + .mount = logfs_mount, .kill_sb = logfs_kill_sb, .fs_flags = FS_REQUIRES_DEV, diff --git a/fs/minix/inode.c b/fs/minix/inode.c index e39d6bf2e8fb..fb2020858a34 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -614,17 +614,16 @@ void minix_truncate(struct inode * inode) V2_minix_truncate(inode); } -static int minix_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *minix_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, minix_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, minix_fill_super); } static struct file_system_type minix_fs_type = { .owner = THIS_MODULE, .name = "minix", - .get_sb = minix_get_sb, + .mount = minix_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/namei.c b/fs/namei.c index f7dbc06857ab..5362af9b7372 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1574,6 +1574,7 @@ static struct file *finish_open(struct nameidata *nd, */ if (will_truncate) mnt_drop_write(nd->path.mnt); + path_put(&nd->path); return filp; exit: @@ -1675,6 +1676,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path, } filp = nameidata_to_filp(nd); mnt_drop_write(nd->path.mnt); + path_put(&nd->path); if (!IS_ERR(filp)) { error = ima_file_check(filp, acc_mode); if (error) { diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 985fabb26aca..d290545aa0c4 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -1020,16 +1020,16 @@ out: return result; } -static int ncp_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *ncp_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_nodev(fs_type, flags, data, ncp_fill_super, mnt); + return mount_nodev(fs_type, flags, data, ncp_fill_super); } static struct file_system_type ncp_fs_type = { .owner = THIS_MODULE, .name = "ncpfs", - .get_sb = ncp_get_sb, + .mount = ncp_mount, .kill_sb = kill_anon_super, .fs_flags = FS_BINARY_MOUNTDATA, }; diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 3600ec700d58..0a42e8f4adcb 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -260,8 +260,8 @@ static int nfs_statfs(struct dentry *, struct kstatfs *); static int nfs_show_options(struct seq_file *, struct vfsmount *); static int nfs_show_stats(struct seq_file *, struct vfsmount *); static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *); -static int nfs_xdev_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); +static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *raw_data); static void nfs_put_super(struct super_block *); static void nfs_kill_super(struct super_block *); static int nfs_remount(struct super_block *sb, int *flags, char *raw_data); @@ -277,7 +277,7 @@ static struct file_system_type nfs_fs_type = { struct file_system_type nfs_xdev_fs_type = { .owner = THIS_MODULE, .name = "nfs", - .get_sb = nfs_xdev_get_sb, + .mount = nfs_xdev_mount, .kill_sb = nfs_kill_super, .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, }; @@ -302,14 +302,14 @@ static int nfs4_try_mount(int flags, const char *dev_name, struct nfs_parsed_mount_data *data, struct vfsmount *mnt); static int nfs4_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); -static int nfs4_remote_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); -static int nfs4_xdev_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); +static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *raw_data); +static struct dentry *nfs4_xdev_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *raw_data); static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); -static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); +static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *raw_data); static void nfs4_kill_super(struct super_block *sb); static struct file_system_type nfs4_fs_type = { @@ -323,7 +323,7 @@ static struct file_system_type nfs4_fs_type = { static struct file_system_type nfs4_remote_fs_type = { .owner = THIS_MODULE, .name = "nfs4", - .get_sb = nfs4_remote_get_sb, + .mount = nfs4_remote_mount, .kill_sb = nfs4_kill_super, .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, }; @@ -331,7 +331,7 @@ static struct file_system_type nfs4_remote_fs_type = { struct file_system_type nfs4_xdev_fs_type = { .owner = THIS_MODULE, .name = "nfs4", - .get_sb = nfs4_xdev_get_sb, + .mount = nfs4_xdev_mount, .kill_sb = nfs4_kill_super, .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, }; @@ -339,7 +339,7 @@ struct file_system_type nfs4_xdev_fs_type = { static struct file_system_type nfs4_remote_referral_fs_type = { .owner = THIS_MODULE, .name = "nfs4", - .get_sb = nfs4_remote_referral_get_sb, + .mount = nfs4_remote_referral_mount, .kill_sb = nfs4_kill_super, .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, }; @@ -2397,9 +2397,9 @@ static void nfs_kill_super(struct super_block *s) /* * Clone an NFS2/3 server record on xdev traversal (FSID-change) */ -static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *raw_data, - struct vfsmount *mnt) +static struct dentry * +nfs_xdev_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *raw_data) { struct nfs_clone_mount *data = raw_data; struct super_block *s; @@ -2411,7 +2411,7 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, }; int error; - dprintk("--> nfs_xdev_get_sb()\n"); + dprintk("--> nfs_xdev_mount()\n"); /* create a new volume representation */ server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr); @@ -2458,28 +2458,26 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, } s->s_flags |= MS_ACTIVE; - mnt->mnt_sb = s; - mnt->mnt_root = mntroot; /* clone any lsm security options from the parent to the new sb */ security_sb_clone_mnt_opts(data->sb, s); - dprintk("<-- nfs_xdev_get_sb() = 0\n"); - return 0; + dprintk("<-- nfs_xdev_mount() = 0\n"); + return mntroot; out_err_nosb: nfs_free_server(server); out_err_noserver: - dprintk("<-- nfs_xdev_get_sb() = %d [error]\n", error); - return error; + dprintk("<-- nfs_xdev_mount() = %d [error]\n", error); + return ERR_PTR(error); error_splat_super: if (server && !s->s_root) bdi_unregister(&server->backing_dev_info); error_splat_bdi: deactivate_locked_super(s); - dprintk("<-- nfs_xdev_get_sb() = %d [splat]\n", error); - return error; + dprintk("<-- nfs_xdev_mount() = %d [splat]\n", error); + return ERR_PTR(error); } #ifdef CONFIG_NFS_V4 @@ -2649,8 +2647,9 @@ out_no_address: /* * Get the superblock for the NFS4 root partition */ -static int nfs4_remote_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) +static struct dentry * +nfs4_remote_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *raw_data) { struct nfs_parsed_mount_data *data = raw_data; struct super_block *s; @@ -2714,15 +2713,16 @@ static int nfs4_remote_get_sb(struct file_system_type *fs_type, goto error_splat_root; s->s_flags |= MS_ACTIVE; - mnt->mnt_sb = s; - mnt->mnt_root = mntroot; - error = 0; + + security_free_mnt_opts(&data->lsm_opts); + nfs_free_fhandle(mntfh); + return mntroot; out: security_free_mnt_opts(&data->lsm_opts); out_free_fh: nfs_free_fhandle(mntfh); - return error; + return ERR_PTR(error); out_free: nfs_free_server(server); @@ -2968,9 +2968,9 @@ static void nfs4_kill_super(struct super_block *sb) /* * Clone an NFS4 server record on xdev traversal (FSID-change) */ -static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *raw_data, - struct vfsmount *mnt) +static struct dentry * +nfs4_xdev_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *raw_data) { struct nfs_clone_mount *data = raw_data; struct super_block *s; @@ -2982,7 +2982,7 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags, }; int error; - dprintk("--> nfs4_xdev_get_sb()\n"); + dprintk("--> nfs4_xdev_mount()\n"); /* create a new volume representation */ server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr); @@ -3029,32 +3029,30 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags, } s->s_flags |= MS_ACTIVE; - mnt->mnt_sb = s; - mnt->mnt_root = mntroot; security_sb_clone_mnt_opts(data->sb, s); - dprintk("<-- nfs4_xdev_get_sb() = 0\n"); - return 0; + dprintk("<-- nfs4_xdev_mount() = 0\n"); + return mntroot; out_err_nosb: nfs_free_server(server); out_err_noserver: - dprintk("<-- nfs4_xdev_get_sb() = %d [error]\n", error); - return error; + dprintk("<-- nfs4_xdev_mount() = %d [error]\n", error); + return ERR_PTR(error); error_splat_super: if (server && !s->s_root) bdi_unregister(&server->backing_dev_info); error_splat_bdi: deactivate_locked_super(s); - dprintk("<-- nfs4_xdev_get_sb() = %d [splat]\n", error); - return error; + dprintk("<-- nfs4_xdev_mount() = %d [splat]\n", error); + return ERR_PTR(error); } -static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *raw_data, - struct vfsmount *mnt) +static struct dentry * +nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *raw_data) { struct nfs_clone_mount *data = raw_data; struct super_block *s; @@ -3118,14 +3116,12 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, } s->s_flags |= MS_ACTIVE; - mnt->mnt_sb = s; - mnt->mnt_root = mntroot; security_sb_clone_mnt_opts(data->sb, s); nfs_free_fhandle(mntfh); dprintk("<-- nfs4_referral_get_sb() = 0\n"); - return 0; + return mntroot; out_err_nosb: nfs_free_server(server); @@ -3133,7 +3129,7 @@ out_err_noserver: nfs_free_fhandle(mntfh); out_err_nofh: dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error); - return error; + return ERR_PTR(error); error_splat_super: if (server && !s->s_root) @@ -3142,7 +3138,7 @@ error_splat_bdi: deactivate_locked_super(s); nfs_free_fhandle(mntfh); dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error); - return error; + return ERR_PTR(error); } /* diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 9a16bad5d2ea..7bdec8531400 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -444,9 +444,9 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir, /* set up nfs_renamedata */ data->old_dir = old_dir; - atomic_inc(&old_dir->i_count); + ihold(old_dir); data->new_dir = new_dir; - atomic_inc(&new_dir->i_count); + ihold(new_dir); data->old_dentry = dget(old_dentry); data->new_dentry = dget(new_dentry); nfs_fattr_init(&data->old_fattr); diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index d6dc3f61f8ba..4514ebbee4d6 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1405,16 +1405,16 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) return simple_fill_super(sb, 0x6e667364, nfsd_files); } -static int nfsd_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *nfsd_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_single(fs_type, flags, data, nfsd_fill_super, mnt); + return mount_single(fs_type, flags, data, nfsd_fill_super); } static struct file_system_type nfsd_fs_type = { .owner = THIS_MODULE, .name = "nfsd", - .get_sb = nfsd_get_sb, + .mount = nfsd_mount, .kill_sb = kill_litter_super, }; diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 35ae03c0db86..f804d41ec9d3 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -1141,9 +1141,9 @@ static int nilfs_test_bdev_super(struct super_block *s, void *data) return (void *)s->s_bdev == data; } -static int -nilfs_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry * +nilfs_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) { struct nilfs_super_data sd; struct super_block *s; @@ -1156,7 +1156,7 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, sd.bdev = open_bdev_exclusive(dev_name, mode, fs_type); if (IS_ERR(sd.bdev)) - return PTR_ERR(sd.bdev); + return ERR_CAST(sd.bdev); sd.cno = 0; sd.flags = flags; @@ -1235,9 +1235,7 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, if (!s_new) close_bdev_exclusive(sd.bdev, mode); - mnt->mnt_sb = s; - mnt->mnt_root = root_dentry; - return 0; + return root_dentry; failed_super: deactivate_locked_super(s); @@ -1245,13 +1243,13 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, failed: if (!s_new) close_bdev_exclusive(sd.bdev, mode); - return err; + return ERR_PTR(err); } struct file_system_type nilfs_fs_type = { .owner = THIS_MODULE, .name = "nilfs2", - .get_sb = nilfs_get_sb, + .mount = nilfs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index d3fbe5730bfc..a30ecacc01f2 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -3059,17 +3059,16 @@ struct kmem_cache *ntfs_index_ctx_cache; /* Driver wide mutex. */ DEFINE_MUTEX(ntfs_lock); -static int ntfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *ntfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, ntfs_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, ntfs_fill_super); } static struct file_system_type ntfs_fs_type = { .owner = THIS_MODULE, .name = "ntfs", - .get_sb = ntfs_get_sb, + .mount = ntfs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c index 75e115f1bd73..b2df490a19ed 100644 --- a/fs/ocfs2/dlmfs/dlmfs.c +++ b/fs/ocfs2/dlmfs/dlmfs.c @@ -643,16 +643,16 @@ static const struct inode_operations dlmfs_file_inode_operations = { .setattr = dlmfs_file_setattr, }; -static int dlmfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *dlmfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_nodev(fs_type, flags, data, dlmfs_fill_super, mnt); + return mount_nodev(fs_type, flags, data, dlmfs_fill_super); } static struct file_system_type dlmfs_fs_type = { .owner = THIS_MODULE, .name = "ocfs2_dlmfs", - .get_sb = dlmfs_get_sb, + .mount = dlmfs_mount, .kill_sb = kill_litter_super, }; diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 56f0cb395820..f02c0ef31578 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -1236,14 +1236,12 @@ read_super_error: return status; } -static int ocfs2_get_sb(struct file_system_type *fs_type, +static struct dentry *ocfs2_mount(struct file_system_type *fs_type, int flags, const char *dev_name, - void *data, - struct vfsmount *mnt) + void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, ocfs2_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, ocfs2_fill_super); } static void ocfs2_kill_sb(struct super_block *sb) @@ -1267,8 +1265,7 @@ out: static struct file_system_type ocfs2_fs_type = { .owner = THIS_MODULE, .name = "ocfs2", - .get_sb = ocfs2_get_sb, /* is this called when we mount - * the fs? */ + .mount = ocfs2_mount, .kill_sb = ocfs2_kill_sb, .fs_flags = FS_REQUIRES_DEV|FS_RENAME_DOES_D_MOVE, diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index 14a22863291a..e043c4cb9a97 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c @@ -557,17 +557,16 @@ end: return ret; } -static int omfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data, struct vfsmount *m) +static struct dentry *omfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, omfs_fill_super, m); + return mount_bdev(fs_type, flags, dev_name, data, omfs_fill_super); } static struct file_system_type omfs_fs_type = { .owner = THIS_MODULE, .name = "omfs", - .get_sb = omfs_get_sb, + .mount = omfs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/open.c b/fs/open.c index d74e1983e8dc..4197b9ed023d 100644 --- a/fs/open.c +++ b/fs/open.c @@ -786,11 +786,11 @@ struct file *nameidata_to_filp(struct nameidata *nd) /* Pick up the filp from the open intent */ filp = nd->intent.open.file; /* Has the filesystem initialised the file for us? */ - if (filp->f_path.dentry == NULL) + if (filp->f_path.dentry == NULL) { + path_get(&nd->path); filp = __dentry_open(nd->path.dentry, nd->path.mnt, filp, NULL, cred); - else - path_put(&nd->path); + } return filp; } diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index ffcd04f0012c..ddb1f41376e5 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -415,16 +415,16 @@ out_no_root: return ret; } -static int openprom_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *openprom_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_single(fs_type, flags, data, openprom_fill_super, mnt); + return mount_single(fs_type, flags, data, openprom_fill_super) } static struct file_system_type openprom_fs_type = { .owner = THIS_MODULE, .name = "openpromfs", - .get_sb = openprom_get_sb, + .mount = openprom_mount, .kill_sb = kill_anon_super, }; diff --git a/fs/pipe.c b/fs/pipe.c index d2d7566ce68e..a8012a955720 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -1247,16 +1247,15 @@ out: * any operations on the root directory. However, we need a non-trivial * d_name - pipe: will go nicely and kill the special-casing in procfs. */ -static int pipefs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - struct vfsmount *mnt) +static struct dentry *pipefs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_pseudo(fs_type, "pipe:", NULL, PIPEFS_MAGIC, mnt); + return mount_pseudo(fs_type, "pipe:", NULL, PIPEFS_MAGIC); } static struct file_system_type pipe_fs_type = { .name = "pipefs", - .get_sb = pipefs_get_sb, + .mount = pipefs_mount, .kill_sb = kill_anon_super, }; diff --git a/fs/proc/root.c b/fs/proc/root.c index 93d99b316325..ef9fa8e24ad6 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -35,8 +35,8 @@ static int proc_set_super(struct super_block *sb, void *data) return set_anon_super(sb, NULL); } -static int proc_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *proc_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { int err; struct super_block *sb; @@ -61,14 +61,14 @@ static int proc_get_sb(struct file_system_type *fs_type, sb = sget(fs_type, proc_test_super, proc_set_super, ns); if (IS_ERR(sb)) - return PTR_ERR(sb); + return ERR_CAST(sb); if (!sb->s_root) { sb->s_flags = flags; err = proc_fill_super(sb); if (err) { deactivate_locked_super(sb); - return err; + return ERR_PTR(err); } ei = PROC_I(sb->s_root->d_inode); @@ -79,11 +79,9 @@ static int proc_get_sb(struct file_system_type *fs_type, } sb->s_flags |= MS_ACTIVE; - ns->proc_mnt = mnt; } - simple_set_mnt(mnt, sb); - return 0; + return dget(sb->s_root); } static void proc_kill_sb(struct super_block *sb) @@ -97,7 +95,7 @@ static void proc_kill_sb(struct super_block *sb) static struct file_system_type proc_fs_type = { .name = "proc", - .get_sb = proc_get_sb, + .mount = proc_mount, .kill_sb = proc_kill_sb, }; @@ -115,6 +113,7 @@ void __init proc_root_init(void) return; } + init_pid_ns.proc_mnt = proc_mnt; proc_symlink("mounts", NULL, "self/mounts"); proc_net_init(); @@ -213,6 +212,7 @@ int pid_ns_prepare_proc(struct pid_namespace *ns) if (IS_ERR(mnt)) return PTR_ERR(mnt); + ns->proc_mnt = mnt; return 0; } diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 01bad30026fc..fcada42f1aa3 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -454,17 +454,16 @@ static void destroy_inodecache(void) kmem_cache_destroy(qnx4_inode_cachep); } -static int qnx4_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *qnx4_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, qnx4_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, qnx4_fill_super); } static struct file_system_type qnx4_fs_type = { .owner = THIS_MODULE, .name = "qnx4", - .get_sb = qnx4_get_sb, + .mount = qnx4_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 67fadb1ad2c1..eacb166fb259 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -255,17 +255,16 @@ fail: return err; } -int ramfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +struct dentry *ramfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_nodev(fs_type, flags, data, ramfs_fill_super, mnt); + return mount_nodev(fs_type, flags, data, ramfs_fill_super); } -static int rootfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *rootfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super, - mnt); + return mount_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super); } static void ramfs_kill_sb(struct super_block *sb) @@ -276,12 +275,12 @@ static void ramfs_kill_sb(struct super_block *sb) static struct file_system_type ramfs_fs_type = { .name = "ramfs", - .get_sb = ramfs_get_sb, + .mount = ramfs_mount, .kill_sb = ramfs_kill_sb, }; static struct file_system_type rootfs_fs_type = { .name = "rootfs", - .get_sb = rootfs_get_sb, + .mount = rootfs_mount, .kill_sb = kill_litter_super, }; diff --git a/fs/read_write.c b/fs/read_write.c index 9cd9d148105d..431a0ed610c8 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -243,8 +243,6 @@ bad: * them to something that fits in "int" so that others * won't have to do range checks all the time. */ -#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK) - int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count) { struct inode *inode; @@ -584,65 +582,71 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, unsigned long nr_segs, unsigned long fast_segs, struct iovec *fast_pointer, struct iovec **ret_pointer) - { +{ unsigned long seg; - ssize_t ret; + ssize_t ret; struct iovec *iov = fast_pointer; - /* - * SuS says "The readv() function *may* fail if the iovcnt argument - * was less than or equal to 0, or greater than {IOV_MAX}. Linux has - * traditionally returned zero for zero segments, so... - */ + /* + * SuS says "The readv() function *may* fail if the iovcnt argument + * was less than or equal to 0, or greater than {IOV_MAX}. Linux has + * traditionally returned zero for zero segments, so... + */ if (nr_segs == 0) { ret = 0; - goto out; + goto out; } - /* - * First get the "struct iovec" from user memory and - * verify all the pointers - */ + /* + * First get the "struct iovec" from user memory and + * verify all the pointers + */ if (nr_segs > UIO_MAXIOV) { ret = -EINVAL; - goto out; + goto out; } if (nr_segs > fast_segs) { - iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL); + iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL); if (iov == NULL) { ret = -ENOMEM; - goto out; + goto out; } - } + } if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) { ret = -EFAULT; - goto out; + goto out; } - /* + /* * According to the Single Unix Specification we should return EINVAL * if an element length is < 0 when cast to ssize_t or if the * total length would overflow the ssize_t return value of the * system call. - */ + * + * Linux caps all read/write calls to MAX_RW_COUNT, and avoids the + * overflow case. + */ ret = 0; - for (seg = 0; seg < nr_segs; seg++) { - void __user *buf = iov[seg].iov_base; - ssize_t len = (ssize_t)iov[seg].iov_len; + for (seg = 0; seg < nr_segs; seg++) { + void __user *buf = iov[seg].iov_base; + ssize_t len = (ssize_t)iov[seg].iov_len; /* see if we we're about to use an invalid len or if * it's about to overflow ssize_t */ - if (len < 0 || (ret + len < ret)) { + if (len < 0) { ret = -EINVAL; - goto out; + goto out; } if (unlikely(!access_ok(vrfy_dir(type), buf, len))) { ret = -EFAULT; - goto out; + goto out; + } + if (len > MAX_RW_COUNT - ret) { + len = MAX_RW_COUNT - ret; + iov[seg].iov_len = len; } - ret += len; - } + } out: *ret_pointer = iov; return ret; diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index e15ff612002d..3bf7a6457f4d 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -2213,12 +2213,11 @@ out: #endif -static int get_super_block(struct file_system_type *fs_type, +static struct dentry *get_super_block(struct file_system_type *fs_type, int flags, const char *dev_name, - void *data, struct vfsmount *mnt) + void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, reiserfs_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, reiserfs_fill_super); } static int __init init_reiserfs_fs(void) @@ -2253,7 +2252,7 @@ static void __exit exit_reiserfs_fs(void) struct file_system_type reiserfs_fs_type = { .owner = THIS_MODULE, .name = "reiserfs", - .get_sb = get_super_block, + .mount = get_super_block, .kill_sb = reiserfs_kill_sb, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/romfs/super.c b/fs/romfs/super.c index 268580535c92..6647f90e55cd 100644 --- a/fs/romfs/super.c +++ b/fs/romfs/super.c @@ -552,20 +552,19 @@ error_rsb: /* * get a superblock for mounting */ -static int romfs_get_sb(struct file_system_type *fs_type, +static struct dentry *romfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, - void *data, struct vfsmount *mnt) + void *data) { - int ret = -EINVAL; + struct dentry *ret = ERR_PTR(-EINVAL); #ifdef CONFIG_ROMFS_ON_MTD - ret = get_sb_mtd(fs_type, flags, dev_name, data, romfs_fill_super, - mnt); + ret = mount_mtd(fs_type, flags, dev_name, data, romfs_fill_super); #endif #ifdef CONFIG_ROMFS_ON_BLOCK - if (ret == -EINVAL) - ret = get_sb_bdev(fs_type, flags, dev_name, data, - romfs_fill_super, mnt); + if (ret == ERR_PTR(-EINVAL)) + ret = mount_bdev(fs_type, flags, dev_name, data, + romfs_fill_super); #endif return ret; } @@ -592,7 +591,7 @@ static void romfs_kill_sb(struct super_block *sb) static struct file_system_type romfs_fs_type = { .owner = THIS_MODULE, .name = "romfs", - .get_sb = romfs_get_sb, + .mount = romfs_mount, .kill_sb = romfs_kill_sb, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 07a4f1156048..24de30ba34c1 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -370,12 +370,10 @@ static void squashfs_put_super(struct super_block *sb) } -static int squashfs_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, - struct vfsmount *mnt) +static struct dentry *squashfs_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, squashfs_fill_super); } @@ -451,7 +449,7 @@ static void squashfs_destroy_inode(struct inode *inode) static struct file_system_type squashfs_fs_type = { .owner = THIS_MODULE, .name = "squashfs", - .get_sb = squashfs_get_sb, + .mount = squashfs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV }; diff --git a/fs/squashfs/xattr.c b/fs/squashfs/xattr.c index 652b8541f9c6..3876c36699a1 100644 --- a/fs/squashfs/xattr.c +++ b/fs/squashfs/xattr.c @@ -158,17 +158,18 @@ static int squashfs_xattr_get(struct inode *inode, int name_index, strncmp(target, name, name_size) == 0) { /* found xattr */ if (type & SQUASHFS_XATTR_VALUE_OOL) { - __le64 xattr; + __le64 xattr_val; + u64 xattr; /* val is a reference to the real location */ err = squashfs_read_metadata(sb, &val, &start, &offset, sizeof(val)); if (err < 0) goto failed; - err = squashfs_read_metadata(sb, &xattr, &start, - &offset, sizeof(xattr)); + err = squashfs_read_metadata(sb, &xattr_val, + &start, &offset, sizeof(xattr_val)); if (err < 0) goto failed; - xattr = le64_to_cpu(xattr); + xattr = le64_to_cpu(xattr_val); start = SQUASHFS_XATTR_BLK(xattr) + msblk->xattr_table; offset = SQUASHFS_XATTR_OFFSET(xattr); diff --git a/fs/squashfs/xattr.h b/fs/squashfs/xattr.h index 49fe0d719fbf..b634efce4bde 100644 --- a/fs/squashfs/xattr.h +++ b/fs/squashfs/xattr.h @@ -25,7 +25,7 @@ extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64, u64 *, int *); extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *, - int *, unsigned long long *); + unsigned int *, unsigned long long *); #else static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start, u64 *xattr_table_start, int *xattr_ids) @@ -35,7 +35,7 @@ static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb, } static inline int squashfs_xattr_lookup(struct super_block *sb, - unsigned int index, int *count, int *size, + unsigned int index, int *count, unsigned int *size, unsigned long long *xattr) { return 0; diff --git a/fs/squashfs/xattr_id.c b/fs/squashfs/xattr_id.c index cfb41106098f..d33be5dd6c32 100644 --- a/fs/squashfs/xattr_id.c +++ b/fs/squashfs/xattr_id.c @@ -34,6 +34,7 @@ #include "squashfs_fs_sb.h" #include "squashfs_fs_i.h" #include "squashfs.h" +#include "xattr.h" /* * Map xattr id using the xattr id look up table diff --git a/fs/super.c b/fs/super.c index b9c9869165db..ca696155cd9a 100644 --- a/fs/super.c +++ b/fs/super.c @@ -715,15 +715,14 @@ static int ns_set_super(struct super_block *sb, void *data) return set_anon_super(sb, NULL); } -int get_sb_ns(struct file_system_type *fs_type, int flags, void *data, - int (*fill_super)(struct super_block *, void *, int), - struct vfsmount *mnt) +struct dentry *mount_ns(struct file_system_type *fs_type, int flags, + void *data, int (*fill_super)(struct super_block *, void *, int)) { struct super_block *sb; sb = sget(fs_type, ns_test_super, ns_set_super, data); if (IS_ERR(sb)) - return PTR_ERR(sb); + return ERR_CAST(sb); if (!sb->s_root) { int err; @@ -731,17 +730,16 @@ int get_sb_ns(struct file_system_type *fs_type, int flags, void *data, err = fill_super(sb, data, flags & MS_SILENT ? 1 : 0); if (err) { deactivate_locked_super(sb); - return err; + return ERR_PTR(err); } sb->s_flags |= MS_ACTIVE; } - simple_set_mnt(mnt, sb); - return 0; + return dget(sb->s_root); } -EXPORT_SYMBOL(get_sb_ns); +EXPORT_SYMBOL(mount_ns); #ifdef CONFIG_BLOCK static int set_bdev_super(struct super_block *s, void *data) @@ -762,10 +760,9 @@ static int test_bdev_super(struct super_block *s, void *data) return (void *)s->s_bdev == data; } -int get_sb_bdev(struct file_system_type *fs_type, +struct dentry *mount_bdev(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, - int (*fill_super)(struct super_block *, void *, int), - struct vfsmount *mnt) + int (*fill_super)(struct super_block *, void *, int)) { struct block_device *bdev; struct super_block *s; @@ -777,7 +774,7 @@ int get_sb_bdev(struct file_system_type *fs_type, bdev = open_bdev_exclusive(dev_name, mode, fs_type); if (IS_ERR(bdev)) - return PTR_ERR(bdev); + return ERR_CAST(bdev); /* * once the super is inserted into the list by sget, s_umount @@ -829,15 +826,30 @@ int get_sb_bdev(struct file_system_type *fs_type, bdev->bd_super = s; } - simple_set_mnt(mnt, s); - return 0; + return dget(s->s_root); error_s: error = PTR_ERR(s); error_bdev: close_bdev_exclusive(bdev, mode); error: - return error; + return ERR_PTR(error); +} +EXPORT_SYMBOL(mount_bdev); + +int get_sb_bdev(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, + int (*fill_super)(struct super_block *, void *, int), + struct vfsmount *mnt) +{ + struct dentry *root; + + root = mount_bdev(fs_type, flags, dev_name, data, fill_super); + if (IS_ERR(root)) + return PTR_ERR(root); + mnt->mnt_root = root; + mnt->mnt_sb = root->d_sb; + return 0; } EXPORT_SYMBOL(get_sb_bdev); @@ -856,29 +868,42 @@ void kill_block_super(struct super_block *sb) EXPORT_SYMBOL(kill_block_super); #endif -int get_sb_nodev(struct file_system_type *fs_type, +struct dentry *mount_nodev(struct file_system_type *fs_type, int flags, void *data, - int (*fill_super)(struct super_block *, void *, int), - struct vfsmount *mnt) + int (*fill_super)(struct super_block *, void *, int)) { int error; struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL); if (IS_ERR(s)) - return PTR_ERR(s); + return ERR_CAST(s); s->s_flags = flags; error = fill_super(s, data, flags & MS_SILENT ? 1 : 0); if (error) { deactivate_locked_super(s); - return error; + return ERR_PTR(error); } s->s_flags |= MS_ACTIVE; - simple_set_mnt(mnt, s); - return 0; + return dget(s->s_root); } +EXPORT_SYMBOL(mount_nodev); +int get_sb_nodev(struct file_system_type *fs_type, + int flags, void *data, + int (*fill_super)(struct super_block *, void *, int), + struct vfsmount *mnt) +{ + struct dentry *root; + + root = mount_nodev(fs_type, flags, data, fill_super); + if (IS_ERR(root)) + return PTR_ERR(root); + mnt->mnt_root = root; + mnt->mnt_sb = root->d_sb; + return 0; +} EXPORT_SYMBOL(get_sb_nodev); static int compare_single(struct super_block *s, void *p) @@ -886,29 +911,42 @@ static int compare_single(struct super_block *s, void *p) return 1; } -int get_sb_single(struct file_system_type *fs_type, +struct dentry *mount_single(struct file_system_type *fs_type, int flags, void *data, - int (*fill_super)(struct super_block *, void *, int), - struct vfsmount *mnt) + int (*fill_super)(struct super_block *, void *, int)) { struct super_block *s; int error; s = sget(fs_type, compare_single, set_anon_super, NULL); if (IS_ERR(s)) - return PTR_ERR(s); + return ERR_CAST(s); if (!s->s_root) { s->s_flags = flags; error = fill_super(s, data, flags & MS_SILENT ? 1 : 0); if (error) { deactivate_locked_super(s); - return error; + return ERR_PTR(error); } s->s_flags |= MS_ACTIVE; } else { do_remount_sb(s, flags, data, 0); } - simple_set_mnt(mnt, s); + return dget(s->s_root); +} +EXPORT_SYMBOL(mount_single); + +int get_sb_single(struct file_system_type *fs_type, + int flags, void *data, + int (*fill_super)(struct super_block *, void *, int), + struct vfsmount *mnt) +{ + struct dentry *root; + root = mount_single(fs_type, flags, data, fill_super); + if (IS_ERR(root)) + return PTR_ERR(root); + mnt->mnt_root = root; + mnt->mnt_sb = root->d_sb; return 0; } @@ -918,6 +956,7 @@ struct vfsmount * vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) { struct vfsmount *mnt; + struct dentry *root; char *secdata = NULL; int error; @@ -942,9 +981,19 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void goto out_free_secdata; } - error = type->get_sb(type, flags, name, data, mnt); - if (error < 0) - goto out_free_secdata; + if (type->mount) { + root = type->mount(type, flags, name, data); + if (IS_ERR(root)) { + error = PTR_ERR(root); + goto out_free_secdata; + } + mnt->mnt_root = root; + mnt->mnt_sb = root->d_sb; + } else { + error = type->get_sb(type, flags, name, data, mnt); + if (error < 0) + goto out_free_secdata; + } BUG_ON(!mnt->mnt_sb); WARN_ON(!mnt->mnt_sb->s_bdi); mnt->mnt_sb->s_flags |= MS_BORN; diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index f2af22574c50..266895783b47 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -23,7 +23,7 @@ #include "sysfs.h" -static struct vfsmount *sysfs_mount; +static struct vfsmount *sysfs_mnt; struct kmem_cache *sysfs_dir_cachep; static const struct super_operations sysfs_ops = { @@ -95,18 +95,17 @@ static int sysfs_set_super(struct super_block *sb, void *data) return error; } -static int sysfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *sysfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { struct sysfs_super_info *info; enum kobj_ns_type type; struct super_block *sb; int error; - error = -ENOMEM; info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) - goto out; + return ERR_PTR(-ENOMEM); for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) info->ns[type] = kobj_ns_current(type); @@ -114,24 +113,19 @@ static int sysfs_get_sb(struct file_system_type *fs_type, sb = sget(fs_type, sysfs_test_super, sysfs_set_super, info); if (IS_ERR(sb) || sb->s_fs_info != info) kfree(info); - if (IS_ERR(sb)) { - error = PTR_ERR(sb); - goto out; - } + if (IS_ERR(sb)) + return ERR_CAST(sb); if (!sb->s_root) { sb->s_flags = flags; error = sysfs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); if (error) { deactivate_locked_super(sb); - goto out; + return ERR_PTR(error); } sb->s_flags |= MS_ACTIVE; } - simple_set_mnt(mnt, sb); - error = 0; -out: - return error; + return dget(sb->s_root); } static void sysfs_kill_sb(struct super_block *sb) @@ -147,7 +141,7 @@ static void sysfs_kill_sb(struct super_block *sb) static struct file_system_type sysfs_fs_type = { .name = "sysfs", - .get_sb = sysfs_get_sb, + .mount = sysfs_mount, .kill_sb = sysfs_kill_sb, }; @@ -189,11 +183,11 @@ int __init sysfs_init(void) err = register_filesystem(&sysfs_fs_type); if (!err) { - sysfs_mount = kern_mount(&sysfs_fs_type); - if (IS_ERR(sysfs_mount)) { + sysfs_mnt = kern_mount(&sysfs_fs_type); + if (IS_ERR(sysfs_mnt)) { printk(KERN_ERR "sysfs: could not mount!\n"); - err = PTR_ERR(sysfs_mount); - sysfs_mount = NULL; + err = PTR_ERR(sysfs_mnt); + sysfs_mnt = NULL; unregister_filesystem(&sysfs_fs_type); goto out_err; } diff --git a/fs/sysv/super.c b/fs/sysv/super.c index a0b0cda6927e..3d9c62be0c10 100644 --- a/fs/sysv/super.c +++ b/fs/sysv/super.c @@ -526,23 +526,22 @@ failed: /* Every kernel module contains stuff like this. */ -static int sysv_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *sysv_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, sysv_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, sysv_fill_super); } -static int v7_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *v7_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, v7_fill_super, mnt); + return mount_bdev(fs_type, flags, dev_name, data, v7_fill_super); } static struct file_system_type sysv_fs_type = { .owner = THIS_MODULE, .name = "sysv", - .get_sb = sysv_get_sb, + .mount = sysv_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; @@ -550,7 +549,7 @@ static struct file_system_type sysv_fs_type = { static struct file_system_type v7_fs_type = { .owner = THIS_MODULE, .name = "v7", - .get_sb = v7_get_sb, + .mount = v7_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 9a47c9f0ad07..91fac54c70e3 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -2038,8 +2038,8 @@ static int sb_test(struct super_block *sb, void *data) return c->vi.cdev == *dev; } -static int ubifs_get_sb(struct file_system_type *fs_type, int flags, - const char *name, void *data, struct vfsmount *mnt) +static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags, + const char *name, void *data) { struct ubi_volume_desc *ubi; struct ubi_volume_info vi; @@ -2057,7 +2057,7 @@ static int ubifs_get_sb(struct file_system_type *fs_type, int flags, if (IS_ERR(ubi)) { dbg_err("cannot open \"%s\", error %d", name, (int)PTR_ERR(ubi)); - return PTR_ERR(ubi); + return ERR_CAST(ubi); } ubi_get_volume_info(ubi, &vi); @@ -2095,20 +2095,19 @@ static int ubifs_get_sb(struct file_system_type *fs_type, int flags, /* 'fill_super()' opens ubi again so we must close it here */ ubi_close_volume(ubi); - simple_set_mnt(mnt, sb); - return 0; + return dget(sb->s_root); out_deact: deactivate_locked_super(sb); out_close: ubi_close_volume(ubi); - return err; + return ERR_PTR(err); } static struct file_system_type ubifs_fs_type = { .name = "ubifs", .owner = THIS_MODULE, - .get_sb = ubifs_get_sb, + .mount = ubifs_mount, .kill_sb = kill_anon_super, }; diff --git a/fs/udf/super.c b/fs/udf/super.c index 76f3d6d97b40..4a5c7c61836a 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -107,17 +107,16 @@ struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi) } /* UDF filesystem type */ -static int udf_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - struct vfsmount *mnt) +static struct dentry *udf_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, udf_fill_super, mnt); + return mount_bdev(fs_type, flags, dev_name, data, udf_fill_super); } static struct file_system_type udf_fstype = { .owner = THIS_MODULE, .name = "udf", - .get_sb = udf_get_sb, + .mount = udf_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 6b9be90dae7d..2c47daed56da 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1454,16 +1454,16 @@ static const struct super_operations ufs_super_ops = { .show_options = ufs_show_options, }; -static int ufs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *ufs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, ufs_fill_super, mnt); + return mount_bdev(fs_type, flags, dev_name, data, ufs_fill_super); } static struct file_system_type ufs_fs_type = { .owner = THIS_MODULE, .name = "ufs", - .get_sb = ufs_get_sb, + .mount = ufs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index cf808782c065..9f3a78fe6ae4 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -1609,16 +1609,14 @@ xfs_fs_fill_super( goto out_free_sb; } -STATIC int -xfs_fs_get_sb( +STATIC struct dentry * +xfs_fs_mount( struct file_system_type *fs_type, int flags, const char *dev_name, - void *data, - struct vfsmount *mnt) + void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super, - mnt); + return mount_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super); } static const struct super_operations xfs_super_operations = { @@ -1639,7 +1637,7 @@ static const struct super_operations xfs_super_operations = { static struct file_system_type xfs_fs_type = { .owner = THIS_MODULE, .name = "xfs", - .get_sb = xfs_fs_get_sb, + .mount = xfs_fs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; diff --git a/include/linux/fs.h b/include/linux/fs.h index 1c73b50e81ff..7b7b507ffa1c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1772,6 +1772,8 @@ struct file_system_type { int fs_flags; int (*get_sb) (struct file_system_type *, int, const char *, void *, struct vfsmount *); + struct dentry *(*mount) (struct file_system_type *, int, + const char *, void *); void (*kill_sb) (struct super_block *); struct module *owner; struct file_system_type * next; @@ -1787,17 +1789,25 @@ struct file_system_type { struct lock_class_key i_alloc_sem_key; }; -extern int get_sb_ns(struct file_system_type *fs_type, int flags, void *data, - int (*fill_super)(struct super_block *, void *, int), - struct vfsmount *mnt); +extern struct dentry *mount_ns(struct file_system_type *fs_type, int flags, + void *data, int (*fill_super)(struct super_block *, void *, int)); +extern struct dentry *mount_bdev(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, + int (*fill_super)(struct super_block *, void *, int)); extern int get_sb_bdev(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, int (*fill_super)(struct super_block *, void *, int), struct vfsmount *mnt); +extern struct dentry *mount_single(struct file_system_type *fs_type, + int flags, void *data, + int (*fill_super)(struct super_block *, void *, int)); extern int get_sb_single(struct file_system_type *fs_type, int flags, void *data, int (*fill_super)(struct super_block *, void *, int), struct vfsmount *mnt); +extern struct dentry *mount_nodev(struct file_system_type *fs_type, + int flags, void *data, + int (*fill_super)(struct super_block *, void *, int)); extern int get_sb_nodev(struct file_system_type *fs_type, int flags, void *data, int (*fill_super)(struct super_block *, void *, int), @@ -1813,9 +1823,8 @@ struct super_block *sget(struct file_system_type *type, int (*test)(struct super_block *,void *), int (*set)(struct super_block *,void *), void *data); -extern int get_sb_pseudo(struct file_system_type *, char *, - const struct super_operations *ops, unsigned long, - struct vfsmount *mnt); +extern struct dentry *mount_pseudo(struct file_system_type *, char *, + const struct super_operations *ops, unsigned long); extern void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb); static inline void sb_mark_dirty(struct super_block *sb) @@ -1858,6 +1867,7 @@ extern int current_umask(void); /* /sys/fs */ extern struct kobject *fs_kobj; +#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK) extern int rw_verify_area(int, struct file *, loff_t *, size_t); #define FLOCK_VERIFY_READ 1 diff --git a/include/linux/mtd/super.h b/include/linux/mtd/super.h index 4016dd6fe336..f456230f9330 100644 --- a/include/linux/mtd/super.h +++ b/include/linux/mtd/super.h @@ -18,10 +18,9 @@ #include <linux/fs.h> #include <linux/mount.h> -extern int get_sb_mtd(struct file_system_type *fs_type, int flags, +extern struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, - int (*fill_super)(struct super_block *, void *, int), - struct vfsmount *mnt); + int (*fill_super)(struct super_block *, void *, int)); extern void kill_mtd_super(struct super_block *sb); diff --git a/include/linux/ramfs.h b/include/linux/ramfs.h index e7320b5e82fb..3a8f0c9b2933 100644 --- a/include/linux/ramfs.h +++ b/include/linux/ramfs.h @@ -3,8 +3,8 @@ struct inode *ramfs_get_inode(struct super_block *sb, const struct inode *dir, int mode, dev_t dev); -extern int ramfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt); +extern struct dentry *ramfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data); #ifndef CONFIG_MMU extern int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize); diff --git a/include/linux/sched.h b/include/linux/sched.h index be7adb7588e5..f53cdf216cef 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1080,7 +1080,7 @@ struct sched_class { struct task_struct *task); #ifdef CONFIG_FAIR_GROUP_SCHED - void (*moved_group) (struct task_struct *p, int on_rq); + void (*task_move_group) (struct task_struct *p, int on_rq); #endif }; diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 3a61ffefe884..035f4399edbc 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -211,13 +211,13 @@ out: return error; } -static int mqueue_get_sb(struct file_system_type *fs_type, +static struct dentry *mqueue_mount(struct file_system_type *fs_type, int flags, const char *dev_name, - void *data, struct vfsmount *mnt) + void *data) { if (!(flags & MS_KERNMOUNT)) data = current->nsproxy->ipc_ns; - return get_sb_ns(fs_type, flags, data, mqueue_fill_super, mnt); + return mount_ns(fs_type, flags, data, mqueue_fill_super); } static void init_once(void *foo) @@ -1232,7 +1232,7 @@ static const struct super_operations mqueue_super_ops = { static struct file_system_type mqueue_fs_type = { .name = "mqueue", - .get_sb = mqueue_get_sb, + .mount = mqueue_mount, .kill_sb = kill_litter_super, }; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 5cf366965d0c..66a416b42c18 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -1460,9 +1460,9 @@ static int cgroup_get_rootdir(struct super_block *sb) return 0; } -static int cgroup_get_sb(struct file_system_type *fs_type, +static struct dentry *cgroup_mount(struct file_system_type *fs_type, int flags, const char *unused_dev_name, - void *data, struct vfsmount *mnt) + void *data) { struct cgroup_sb_opts opts; struct cgroupfs_root *root; @@ -1596,10 +1596,9 @@ static int cgroup_get_sb(struct file_system_type *fs_type, drop_parsed_module_refcounts(opts.subsys_bits); } - simple_set_mnt(mnt, sb); kfree(opts.release_agent); kfree(opts.name); - return 0; + return dget(sb->s_root); drop_new_super: deactivate_locked_super(sb); @@ -1608,7 +1607,7 @@ static int cgroup_get_sb(struct file_system_type *fs_type, out_err: kfree(opts.release_agent); kfree(opts.name); - return ret; + return ERR_PTR(ret); } static void cgroup_kill_sb(struct super_block *sb) { @@ -1658,7 +1657,7 @@ static void cgroup_kill_sb(struct super_block *sb) { static struct file_system_type cgroup_fs_type = { .name = "cgroup", - .get_sb = cgroup_get_sb, + .mount = cgroup_mount, .kill_sb = cgroup_kill_sb, }; diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 51b143e2a07a..4349935c2ad8 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -231,18 +231,17 @@ static DEFINE_SPINLOCK(cpuset_buffer_lock); * users. If someone tries to mount the "cpuset" filesystem, we * silently switch it to mount "cgroup" instead */ -static int cpuset_get_sb(struct file_system_type *fs_type, - int flags, const char *unused_dev_name, - void *data, struct vfsmount *mnt) +static struct dentry *cpuset_mount(struct file_system_type *fs_type, + int flags, const char *unused_dev_name, void *data) { struct file_system_type *cgroup_fs = get_fs_type("cgroup"); - int ret = -ENODEV; + struct dentry *ret = ERR_PTR(-ENODEV); if (cgroup_fs) { char mountopts[] = "cpuset,noprefix," "release_agent=/sbin/cpuset_release_agent"; - ret = cgroup_fs->get_sb(cgroup_fs, flags, - unused_dev_name, mountopts, mnt); + ret = cgroup_fs->mount(cgroup_fs, flags, + unused_dev_name, mountopts); put_filesystem(cgroup_fs); } return ret; @@ -250,7 +249,7 @@ static int cpuset_get_sb(struct file_system_type *fs_type, static struct file_system_type cpuset_fs_type = { .name = "cpuset", - .get_sb = cpuset_get_sb, + .mount = cpuset_mount, }; /* diff --git a/kernel/sched.c b/kernel/sched.c index d42992bccdfa..aa14a56f9d03 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -8510,12 +8510,12 @@ void sched_move_task(struct task_struct *tsk) if (unlikely(running)) tsk->sched_class->put_prev_task(rq, tsk); - set_task_rq(tsk, task_cpu(tsk)); - #ifdef CONFIG_FAIR_GROUP_SCHED - if (tsk->sched_class->moved_group) - tsk->sched_class->moved_group(tsk, on_rq); + if (tsk->sched_class->task_move_group) + tsk->sched_class->task_move_group(tsk, on_rq); + else #endif + set_task_rq(tsk, task_cpu(tsk)); if (unlikely(running)) tsk->sched_class->set_curr_task(rq); diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 933f3d1b62ea..f4f6a8326dd0 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -3869,13 +3869,26 @@ static void set_curr_task_fair(struct rq *rq) } #ifdef CONFIG_FAIR_GROUP_SCHED -static void moved_group_fair(struct task_struct *p, int on_rq) +static void task_move_group_fair(struct task_struct *p, int on_rq) { - struct cfs_rq *cfs_rq = task_cfs_rq(p); - - update_curr(cfs_rq); + /* + * If the task was not on the rq at the time of this cgroup movement + * it must have been asleep, sleeping tasks keep their ->vruntime + * absolute on their old rq until wakeup (needed for the fair sleeper + * bonus in place_entity()). + * + * If it was on the rq, we've just 'preempted' it, which does convert + * ->vruntime to a relative base. + * + * Make sure both cases convert their relative position when migrating + * to another cgroup's rq. This does somewhat interfere with the + * fair sleeper stuff for the first placement, but who cares. + */ + if (!on_rq) + p->se.vruntime -= cfs_rq_of(&p->se)->min_vruntime; + set_task_rq(p, task_cpu(p)); if (!on_rq) - place_entity(cfs_rq, &p->se, 1); + p->se.vruntime += cfs_rq_of(&p->se)->min_vruntime; } #endif @@ -3927,7 +3940,7 @@ static const struct sched_class fair_sched_class = { .get_rr_interval = get_rr_interval_fair, #ifdef CONFIG_FAIR_GROUP_SCHED - .moved_group = moved_group_fair, + .task_move_group = task_move_group_fair, #endif }; diff --git a/kernel/sched_stats.h b/kernel/sched_stats.h index 25c2f962f6fc..48ddf431db0e 100644 --- a/kernel/sched_stats.h +++ b/kernel/sched_stats.h @@ -157,15 +157,7 @@ static inline void sched_info_reset_dequeued(struct task_struct *t) } /* - * Called when a process is dequeued from the active array and given - * the cpu. We should note that with the exception of interactive - * tasks, the expired queue will become the active queue after the active - * queue is empty, without explicitly dequeuing and requeuing tasks in the - * expired queue. (Interactive tasks may be requeued directly to the - * active queue, thus delaying tasks in the expired queue from running; - * see scheduler_tick()). - * - * Though we are interested in knowing how long it was from the *first* time a + * We are interested in knowing how long it was from the *first* time a * task was queued to the time that it finally hit a cpu, we call this routine * from dequeue_task() to account for possible rq->clock skew across cpus. The * delta taken on each cpu would annul the skew. @@ -203,16 +195,6 @@ static void sched_info_arrive(struct task_struct *t) } /* - * Called when a process is queued into either the active or expired - * array. The time is noted and later used to determine how long we - * had to wait for us to reach the cpu. Since the expired queue will - * become the active queue after active queue is empty, without dequeuing - * and requeuing any tasks, we are interested in queuing to either. It - * is unusual but not impossible for tasks to be dequeued and immediately - * requeued in the same or another array: this can happen in sched_yield(), - * set_user_nice(), and even load_balance() as it moves tasks from runqueue - * to runqueue. - * * This function is only called from enqueue_task(), but also only updates * the timestamp if it is already not set. It's assumed that * sched_info_dequeued() will clear that stamp when appropriate. diff --git a/mm/shmem.c b/mm/shmem.c index f6d350e8adc5..47fdeeb9d636 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2538,16 +2538,16 @@ static const struct vm_operations_struct shmem_vm_ops = { }; -static int shmem_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry *shmem_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_nodev(fs_type, flags, data, shmem_fill_super, mnt); + return mount_nodev(fs_type, flags, data, shmem_fill_super); } static struct file_system_type tmpfs_fs_type = { .owner = THIS_MODULE, .name = "tmpfs", - .get_sb = shmem_get_sb, + .mount = shmem_mount, .kill_sb = kill_litter_super, }; @@ -2643,7 +2643,7 @@ out: static struct file_system_type tmpfs_fs_type = { .name = "tmpfs", - .get_sb = ramfs_get_sb, + .mount = ramfs_mount, .kill_sb = kill_litter_super, }; diff --git a/net/socket.c b/net/socket.c index ee3cd280c76e..5247ae10f374 100644 --- a/net/socket.c +++ b/net/socket.c @@ -305,19 +305,17 @@ static const struct super_operations sockfs_ops = { .statfs = simple_statfs, }; -static int sockfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - struct vfsmount *mnt) +static struct dentry *sockfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC, - mnt); + return mount_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC); } static struct vfsmount *sock_mnt __read_mostly; static struct file_system_type sock_fs_type = { .name = "sockfs", - .get_sb = sockfs_get_sb, + .mount = sockfs_mount, .kill_sb = kill_anon_super, }; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 7df92d237cb8..10a17a37ec4e 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -28,7 +28,7 @@ #include <linux/sunrpc/rpc_pipe_fs.h> #include <linux/sunrpc/cache.h> -static struct vfsmount *rpc_mount __read_mostly; +static struct vfsmount *rpc_mnt __read_mostly; static int rpc_mount_count; static struct file_system_type rpc_pipe_fs_type; @@ -417,16 +417,16 @@ struct vfsmount *rpc_get_mount(void) { int err; - err = simple_pin_fs(&rpc_pipe_fs_type, &rpc_mount, &rpc_mount_count); + err = simple_pin_fs(&rpc_pipe_fs_type, &rpc_mnt, &rpc_mount_count); if (err != 0) return ERR_PTR(err); - return rpc_mount; + return rpc_mnt; } EXPORT_SYMBOL_GPL(rpc_get_mount); void rpc_put_mount(void) { - simple_release_fs(&rpc_mount, &rpc_mount_count); + simple_release_fs(&rpc_mnt, &rpc_mount_count); } EXPORT_SYMBOL_GPL(rpc_put_mount); @@ -1018,17 +1018,17 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) return 0; } -static int -rpc_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, struct vfsmount *mnt) +static struct dentry * +rpc_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_single(fs_type, flags, data, rpc_fill_super, mnt); + return mount_single(fs_type, flags, data, rpc_fill_super); } static struct file_system_type rpc_pipe_fs_type = { .owner = THIS_MODULE, .name = "rpc_pipefs", - .get_sb = rpc_get_sb, + .mount = rpc_mount, .kill_sb = kill_litter_super, }; diff --git a/security/inode.c b/security/inode.c index cb8f47c66a58..c4df2fbebe6b 100644 --- a/security/inode.c +++ b/security/inode.c @@ -131,17 +131,17 @@ static int fill_super(struct super_block *sb, void *data, int silent) return simple_fill_super(sb, SECURITYFS_MAGIC, files); } -static int get_sb(struct file_system_type *fs_type, +static struct dentry *get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, - void *data, struct vfsmount *mnt) + void *data) { - return get_sb_single(fs_type, flags, data, fill_super, mnt); + return mount_single(fs_type, flags, data, fill_super); } static struct file_system_type fs_type = { .owner = THIS_MODULE, .name = "securityfs", - .get_sb = get_sb, + .mount = get_sb, .kill_sb = kill_litter_super, }; diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 55a755c1a1bd..073fd5b0a53a 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -1909,16 +1909,15 @@ err: goto out; } -static int sel_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - struct vfsmount *mnt) +static struct dentry *sel_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_single(fs_type, flags, data, sel_fill_super, mnt); + return mount_single(fs_type, flags, data, sel_fill_super); } static struct file_system_type sel_fs_type = { .name = "selinuxfs", - .get_sb = sel_get_sb, + .mount = sel_mount, .kill_sb = kill_litter_super, }; diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 7512502d0162..dc1fd6239f24 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -1310,27 +1310,25 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) } /** - * smk_get_sb - get the smackfs superblock + * smk_mount - get the smackfs superblock * @fs_type: passed along without comment * @flags: passed along without comment * @dev_name: passed along without comment * @data: passed along without comment - * @mnt: passed along without comment * * Just passes everything along. * * Returns what the lower level code does. */ -static int smk_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - struct vfsmount *mnt) +static struct dentry *smk_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_single(fs_type, flags, data, smk_fill_super, mnt); + return mount_single(fs_type, flags, data, smk_fill_super); } static struct file_system_type smk_fs_type = { .name = "smackfs", - .get_sb = smk_get_sb, + .mount = smk_mount, .kill_sb = kill_litter_super, }; |