diff options
59 files changed, 595 insertions, 307 deletions
diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt index 614de3124901..251168587899 100644 --- a/Documentation/filesystems/ntfs.txt +++ b/Documentation/filesystems/ntfs.txt @@ -457,6 +457,12 @@ ChangeLog Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog. +2.1.26: + - Implement support for sector sizes above 512 bytes (up to the maximum + supported by NTFS which is 4096 bytes). + - Enhance support for NTFS volumes which were supported by Windows but + not by Linux due to invalid attribute list attribute flags. + - A few minor updates and bug fixes. 2.1.25: - Write support is now extended with write(2) being able to both overwrite existing file data and to extend files. Also, if a write diff --git a/Documentation/filesystems/tmpfs.txt b/Documentation/filesystems/tmpfs.txt index 8a155418c705..1773106976a2 100644 --- a/Documentation/filesystems/tmpfs.txt +++ b/Documentation/filesystems/tmpfs.txt @@ -92,6 +92,15 @@ NodeList format is a comma-separated list of decimal numbers and ranges, a range being two hyphen-separated decimal numbers, the smallest and largest node numbers in the range. For example, mpol=bind:0-3,5,7,9-15 +Note that trying to mount a tmpfs with an mpol option will fail if the +running kernel does not support NUMA; and will fail if its nodelist +specifies a node >= MAX_NUMNODES. If your system relies on that tmpfs +being mounted, but from time to time runs a kernel built without NUMA +capability (perhaps a safe recovery kernel), or configured to support +fewer nodes, then it is advisable to omit the mpol option from automatic +mount options. It can be added later, when the tmpfs is already mounted +on MountPoint, by 'mount -o remount,mpol=Policy:NodeList MountPoint'. + To specify the initial root directory you can use the following mount options: diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 60c3f76dfca4..53bb9a79e274 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -7,7 +7,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \ pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \ - quirks.o i8237.o + quirks.o i8237.o topology.o obj-y += cpu/ obj-y += timers/ diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 7eb9213734a3..4ecd4b326ded 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -4,6 +4,7 @@ #include <linux/smp.h> #include <linux/module.h> #include <linux/percpu.h> +#include <linux/bootmem.h> #include <asm/semaphore.h> #include <asm/processor.h> #include <asm/i387.h> @@ -18,6 +19,9 @@ #include "cpu.h" +DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr); +EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr); + DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]); EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack); @@ -571,8 +575,9 @@ void __devinit cpu_init(void) int cpu = smp_processor_id(); struct tss_struct * t = &per_cpu(init_tss, cpu); struct thread_struct *thread = ¤t->thread; - struct desc_struct *gdt = get_cpu_gdt_table(cpu); + struct desc_struct *gdt; __u32 stk16_off = (__u32)&per_cpu(cpu_16bit_stack, cpu); + struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); if (cpu_test_and_set(cpu, cpu_initialized)) { printk(KERN_WARNING "CPU#%d already initialized!\n", cpu); @@ -590,6 +595,25 @@ void __devinit cpu_init(void) } /* + * This is a horrible hack to allocate the GDT. The problem + * is that cpu_init() is called really early for the boot CPU + * (and hence needs bootmem) but much later for the secondary + * CPUs, when bootmem will have gone away + */ + if (NODE_DATA(0)->bdata->node_bootmem_map) { + gdt = (struct desc_struct *)alloc_bootmem_pages(PAGE_SIZE); + /* alloc_bootmem_pages panics on failure, so no check */ + memset(gdt, 0, PAGE_SIZE); + } else { + gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL); + if (unlikely(!gdt)) { + printk(KERN_CRIT "CPU%d failed to allocate GDT\n", cpu); + for (;;) + local_irq_enable(); + } + } + + /* * Initialize the per-CPU GDT with the boot GDT, * and set up the GDT descriptor: */ @@ -601,10 +625,10 @@ void __devinit cpu_init(void) ((((__u64)stk16_off) << 32) & 0xff00000000000000ULL) | (CPU_16BIT_STACK_SIZE - 1); - cpu_gdt_descr[cpu].size = GDT_SIZE - 1; - cpu_gdt_descr[cpu].address = (unsigned long)gdt; + cpu_gdt_descr->size = GDT_SIZE - 1; + cpu_gdt_descr->address = (unsigned long)gdt; - load_gdt(&cpu_gdt_descr[cpu]); + load_gdt(cpu_gdt_descr); load_idt(&idt_descr); /* diff --git a/arch/i386/kernel/efi.c b/arch/i386/kernel/efi.c index ecad519fd395..e3e42fd62401 100644 --- a/arch/i386/kernel/efi.c +++ b/arch/i386/kernel/efi.c @@ -103,17 +103,19 @@ static void efi_call_phys_prelog(void) */ local_flush_tlb(); - cpu_gdt_descr[0].address = __pa(cpu_gdt_descr[0].address); - load_gdt((struct Xgt_desc_struct *) __pa(&cpu_gdt_descr[0])); + per_cpu(cpu_gdt_descr, 0).address = + __pa(per_cpu(cpu_gdt_descr, 0).address); + load_gdt((struct Xgt_desc_struct *)__pa(&per_cpu(cpu_gdt_descr, 0))); } static void efi_call_phys_epilog(void) { unsigned long cr4; - cpu_gdt_descr[0].address = - (unsigned long) __va(cpu_gdt_descr[0].address); - load_gdt(&cpu_gdt_descr[0]); + per_cpu(cpu_gdt_descr, 0).address = + (unsigned long)__va(per_cpu(cpu_gdt_descr, 0).address); + load_gdt((struct Xgt_desc_struct *)__va(&per_cpu(cpu_gdt_descr, 0))); + cr4 = read_cr4(); if (cr4 & X86_CR4_PSE) { diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index 2bee6499edd9..e0b7c632efbc 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -534,5 +534,3 @@ ENTRY(cpu_gdt_table) .quad 0x0000000000000000 /* 0xf0 - unused */ .quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */ - /* Be sure this is zeroed to avoid false validations in Xen */ - .fill PAGE_SIZE_asm / 8 - GDT_ENTRIES,8,0 diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index 3999bec50c33..055325056a74 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -3,8 +3,6 @@ #include <asm/checksum.h> #include <asm/desc.h> -EXPORT_SYMBOL_GPL(cpu_gdt_descr); - EXPORT_SYMBOL(__down_failed); EXPORT_SYMBOL(__down_failed_interruptible); EXPORT_SYMBOL(__down_failed_trylock); diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c index 6483eeb1a4e8..694a13997637 100644 --- a/arch/i386/kernel/kprobes.c +++ b/arch/i386/kernel/kprobes.c @@ -58,6 +58,11 @@ static inline int is_IF_modifier(kprobe_opcode_t opcode) int __kprobes arch_prepare_kprobe(struct kprobe *p) { + /* insn: must be on special executable page on i386. */ + p->ainsn.insn = get_insn_slot(); + if (!p->ainsn.insn) + return -ENOMEM; + memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); p->opcode = *p->addr; return 0; @@ -77,6 +82,13 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p) (unsigned long) p->addr + sizeof(kprobe_opcode_t)); } +void __kprobes arch_remove_kprobe(struct kprobe *p) +{ + down(&kprobe_mutex); + free_insn_slot(p->ainsn.insn); + up(&kprobe_mutex); +} + static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb) { kcb->prev_kprobe.kp = kprobe_running(); @@ -111,7 +123,7 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) if (p->opcode == BREAKPOINT_INSTRUCTION) regs->eip = (unsigned long)p->addr; else - regs->eip = (unsigned long)&p->ainsn.insn; + regs->eip = (unsigned long)p->ainsn.insn; } /* Called with kretprobe_lock held */ @@ -351,7 +363,7 @@ static void __kprobes resume_execution(struct kprobe *p, { unsigned long *tos = (unsigned long *)®s->esp; unsigned long next_eip = 0; - unsigned long copy_eip = (unsigned long)&p->ainsn.insn; + unsigned long copy_eip = (unsigned long)p->ainsn.insn; unsigned long orig_eip = (unsigned long)p->addr; switch (p->ainsn.insn[0]) { diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index fb00ab7b7612..eba7f53f8b4a 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -898,12 +898,6 @@ static int __devinit do_boot_cpu(int apicid, int cpu) unsigned long start_eip; unsigned short nmi_high = 0, nmi_low = 0; - if (!cpu_gdt_descr[cpu].address && - !(cpu_gdt_descr[cpu].address = get_zeroed_page(GFP_KERNEL))) { - printk("Failed to allocate GDT for CPU %d\n", cpu); - return 1; - } - ++cpucount; /* diff --git a/arch/i386/mach-default/topology.c b/arch/i386/kernel/topology.c index b64314069e78..67a0e1baa28b 100644 --- a/arch/i386/mach-default/topology.c +++ b/arch/i386/kernel/topology.c @@ -1,12 +1,12 @@ /* - * arch/i386/mach-generic/topology.c - Populate driverfs with topology information + * arch/i386/kernel/topology.c - Populate driverfs with topology information * * Written by: Matthew Dobson, IBM Corporation * Original Code: Paul Dorwin, IBM Corporation, Patrick Mochel, OSDL * * Copyright (C) 2002, IBM Corp. * - * All rights reserved. + * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,7 +34,7 @@ static struct i386_cpu cpu_devices[NR_CPUS]; int arch_register_cpu(int num){ struct node *parent = NULL; - + #ifdef CONFIG_NUMA int node = cpu_to_node(num); if (node_online(node)) diff --git a/arch/i386/mach-default/Makefile b/arch/i386/mach-default/Makefile index e95bb0237921..012fe34459e6 100644 --- a/arch/i386/mach-default/Makefile +++ b/arch/i386/mach-default/Makefile @@ -2,4 +2,4 @@ # Makefile for the linux kernel. # -obj-y := setup.o topology.o +obj-y := setup.o diff --git a/arch/i386/mach-voyager/voyager_basic.c b/arch/i386/mach-voyager/voyager_basic.c index aa49a33a572c..6761d294f260 100644 --- a/arch/i386/mach-voyager/voyager_basic.c +++ b/arch/i386/mach-voyager/voyager_basic.c @@ -23,6 +23,9 @@ #include <linux/delay.h> #include <linux/reboot.h> #include <linux/sysrq.h> +#include <linux/smp.h> +#include <linux/nodemask.h> +#include <asm/cpu.h> #include <asm/io.h> #include <asm/voyager.h> #include <asm/vic.h> @@ -329,3 +332,15 @@ void machine_power_off(void) pm_power_off(); } +static struct i386_cpu cpu_devices[NR_CPUS]; + +static int __init topology_init(void) +{ + int i; + + for_each_present_cpu(i) + register_cpu(&cpu_devices[i].cpu, i, NULL); + return 0; +} + +subsys_initcall(topology_init); diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c index 6e4c3baef6cc..8165626a5c30 100644 --- a/arch/i386/mach-voyager/voyager_smp.c +++ b/arch/i386/mach-voyager/voyager_smp.c @@ -402,6 +402,7 @@ find_smp_config(void) cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 1) << 8; cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 2) << 16; cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 3) << 24; + cpu_possible_map = phys_cpu_present_map; printk("VOYAGER SMP: phys_cpu_present_map = 0x%lx\n", cpus_addr(phys_cpu_present_map)[0]); /* Here we set up the VIC to enable SMP */ /* enable the CPIs by writing the base vector to their register */ diff --git a/arch/m32r/Makefile b/arch/m32r/Makefile index 983d438b14b6..4b3c90ba926c 100644 --- a/arch/m32r/Makefile +++ b/arch/m32r/Makefile @@ -12,14 +12,14 @@ CFLAGS_MODULE += -mmodel=large ifdef CONFIG_CHIP_VDEC2 cflags-$(CONFIG_ISA_M32R2) += -DNO_FPU -Wa,-bitinst -aflags-$(CONFIG_ISA_M32R2) += -DNO_FPU -Wa,-bitinst +aflags-$(CONFIG_ISA_M32R2) += -DNO_FPU -O2 -Wa,-bitinst -Wa,-no-parallel else cflags-$(CONFIG_ISA_M32R2) += -DNO_FPU -m32r2 -aflags-$(CONFIG_ISA_M32R2) += -DNO_FPU -m32r2 +aflags-$(CONFIG_ISA_M32R2) += -DNO_FPU -m32r2 -O2 endif cflags-$(CONFIG_ISA_M32R) += -DNO_FPU -aflags-$(CONFIG_ISA_M32R) += -DNO_FPU -Wa,-no-bitinst +aflags-$(CONFIG_ISA_M32R) += -DNO_FPU -O2 -Wa,-no-bitinst CFLAGS += $(cflags-y) AFLAGS += $(aflags-y) diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index 71763f7a1d19..cb33097fefc4 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c @@ -36,7 +36,7 @@ int do_signal(struct pt_regs *, sigset_t *); asmlinkage int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, unsigned long r2, unsigned long r3, unsigned long r4, - unsigned long r5, unsigned long r6, struct pt_regs regs) + unsigned long r5, unsigned long r6, struct pt_regs *regs) { sigset_t saveset, newset; @@ -54,21 +54,21 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - regs.r0 = -EINTR; + regs->r0 = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(®s, &saveset)) - return regs.r0; + if (do_signal(regs, &saveset)) + return regs->r0; } } asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r2, unsigned long r3, unsigned long r4, - unsigned long r5, unsigned long r6, struct pt_regs regs) + unsigned long r5, unsigned long r6, struct pt_regs *regs) { - return do_sigaltstack(uss, uoss, regs.spu); + return do_sigaltstack(uss, uoss, regs->spu); } @@ -140,11 +140,10 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, asmlinkage int sys_rt_sigreturn(unsigned long r0, unsigned long r1, unsigned long r2, unsigned long r3, unsigned long r4, - unsigned long r5, unsigned long r6, struct pt_regs regs) + unsigned long r5, unsigned long r6, struct pt_regs *regs) { - struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs.spu; + struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs->spu; sigset_t set; - stack_t st; int result; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) @@ -158,14 +157,11 @@ sys_rt_sigreturn(unsigned long r0, unsigned long r1, recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(®s, &frame->uc.uc_mcontext, &result)) + if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &result)) goto badframe; - if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->spu) == -EFAULT) goto badframe; - /* It is more difficult to avoid calling this function than to - call it and ignore errors. */ - do_sigaltstack(&st, NULL, regs.spu); return result; diff --git a/arch/m32r/lib/usercopy.c b/arch/m32r/lib/usercopy.c index ce16bbe26a52..2d1dd2106c4d 100644 --- a/arch/m32r/lib/usercopy.c +++ b/arch/m32r/lib/usercopy.c @@ -64,7 +64,7 @@ do { \ " .balign 4\n" \ " .long 0b,3b\n" \ ".previous" \ - : "=r"(res), "=r"(count), "=&r" (__d0), "=&r" (__d1), \ + : "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1), \ "=&r" (__d2) \ : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \ "4"(dst) \ @@ -101,7 +101,7 @@ do { \ " .balign 4\n" \ " .long 0b,3b\n" \ ".previous" \ - : "=r"(res), "=r"(count), "=&r" (__d0), "=&r" (__d1), \ + : "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1), \ "=&r" (__d2) \ : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \ "4"(dst) \ diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index d83e033dbc87..2f2dc54b2e26 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -626,7 +626,7 @@ einval: li v0, -EINVAL sys sys_fstatat64 4 sys sys_unlinkat 3 sys sys_renameat 4 /* 4295 */ - sys sys_linkat 4 + sys sys_linkat 5 sys sys_symlinkat 3 sys sys_readlinkat 4 sys sys_fchmodat 3 diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 294832a7e0a6..6dbd21726770 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -816,8 +816,6 @@ void __init unflatten_device_tree(void) { unsigned long start, mem, size; struct device_node **allnextp = &allnodes; - char *p = NULL; - int l = 0; DBG(" -> unflatten_device_tree()\n"); @@ -857,19 +855,6 @@ void __init unflatten_device_tree(void) if (of_chosen == NULL) of_chosen = of_find_node_by_path("/chosen@0"); - /* Retreive command line */ - if (of_chosen != NULL) { - p = (char *)get_property(of_chosen, "bootargs", &l); - if (p != NULL && l > 0) - strlcpy(cmd_line, p, min(l, COMMAND_LINE_SIZE)); - } -#ifdef CONFIG_CMDLINE - if (l == 0 || (l == 1 && (*p) == 0)) - strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); -#endif /* CONFIG_CMDLINE */ - - DBG("Command line is: %s\n", cmd_line); - DBG(" <- unflatten_device_tree()\n"); } @@ -940,6 +925,8 @@ static int __init early_init_dt_scan_chosen(unsigned long node, { u32 *prop; unsigned long *lprop; + unsigned long l; + char *p; DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname); @@ -1004,6 +991,41 @@ static int __init early_init_dt_scan_chosen(unsigned long node, crashk_res.end = crashk_res.start + *lprop - 1; #endif + /* Retreive command line */ + p = of_get_flat_dt_prop(node, "bootargs", &l); + if (p != NULL && l > 0) + strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE)); + +#ifdef CONFIG_CMDLINE + if (l == 0 || (l == 1 && (*p) == 0)) + strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); +#endif /* CONFIG_CMDLINE */ + + DBG("Command line is: %s\n", cmd_line); + + if (strstr(cmd_line, "mem=")) { + char *p, *q; + unsigned long maxmem = 0; + + for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) { + q = p + 4; + if (p > cmd_line && p[-1] != ' ') + continue; + maxmem = simple_strtoul(q, &q, 0); + if (*q == 'k' || *q == 'K') { + maxmem <<= 10; + ++q; + } else if (*q == 'm' || *q == 'M') { + maxmem <<= 20; + ++q; + } else if (*q == 'g' || *q == 'G') { + maxmem <<= 30; + ++q; + } + } + memory_limit = maxmem; + } + /* break now */ return 1; } @@ -1124,7 +1146,7 @@ static void __init early_reserve_mem(void) size_32 = *(reserve_map_32++); if (size_32 == 0) break; - DBG("reserving: %lx -> %lx\n", base_32, size_32); + DBG("reserving: %x -> %x\n", base_32, size_32); lmb_reserve(base_32, size_32); } return; diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 615964cca15f..50e80138e7ad 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -1552,6 +1552,7 @@ sys_linkat_wrapper: llgtr %r3,%r3 # const char * lgfr %r4,%r4 # int llgtr %r5,%r5 # const char * + lgfr %r6,%r6 # int jg sys_linkat .globl sys_symlinkat_wrapper diff --git a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h index dc36b222100b..04e3958266e0 100644 --- a/arch/um/drivers/cow.h +++ b/arch/um/drivers/cow.h @@ -46,7 +46,7 @@ extern int file_reader(__u64 offset, char *buf, int len, void *arg); extern int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, __u32 *version_out, char **backing_file_out, time_t *mtime_out, - unsigned long long *size_out, int *sectorsize_out, + __u64 *size_out, int *sectorsize_out, __u32 *align_out, int *bitmap_offset_out); extern int write_cow_header(char *cow_file, int fd, char *backing_file, diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h index c83fc5d68936..94de4ead4f7a 100644 --- a/arch/um/drivers/cow_sys.h +++ b/arch/um/drivers/cow_sys.h @@ -23,17 +23,17 @@ static inline char *cow_strdup(char *str) return(uml_strdup(str)); } -static inline int cow_seek_file(int fd, unsigned long long offset) +static inline int cow_seek_file(int fd, __u64 offset) { return(os_seek_file(fd, offset)); } -static inline int cow_file_size(char *file, unsigned long long *size_out) +static inline int cow_file_size(char *file, __u64 *size_out) { return(os_file_size(file, size_out)); } -static inline int cow_write_file(int fd, char *buf, int size) +static inline int cow_write_file(int fd, void *buf, int size) { return(os_write_file(fd, buf, size)); } diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c index fbe2217db5dd..61951b721268 100644 --- a/arch/um/drivers/cow_user.c +++ b/arch/um/drivers/cow_user.c @@ -176,7 +176,7 @@ int write_cow_header(char *cow_file, int fd, char *backing_file, err = -ENOMEM; header = cow_malloc(sizeof(*header)); if(header == NULL){ - cow_printf("Failed to allocate COW V3 header\n"); + cow_printf("write_cow_header - failed to allocate COW V3 header\n"); goto out; } header->magic = htonl(COW_MAGIC); @@ -196,15 +196,17 @@ int write_cow_header(char *cow_file, int fd, char *backing_file, err = os_file_modtime(header->backing_file, &modtime); if(err < 0){ - cow_printf("Backing file '%s' mtime request failed, " - "err = %d\n", header->backing_file, -err); + cow_printf("write_cow_header - backing file '%s' mtime " + "request failed, err = %d\n", header->backing_file, + -err); goto out_free; } err = cow_file_size(header->backing_file, size); if(err < 0){ - cow_printf("Couldn't get size of backing file '%s', " - "err = %d\n", header->backing_file, -err); + cow_printf("write_cow_header - couldn't get size of " + "backing file '%s', err = %d\n", + header->backing_file, -err); goto out_free; } @@ -214,10 +216,11 @@ int write_cow_header(char *cow_file, int fd, char *backing_file, header->alignment = htonl(alignment); header->cow_format = COW_BITMAP; - err = os_write_file(fd, header, sizeof(*header)); + err = cow_write_file(fd, header, sizeof(*header)); if(err != sizeof(*header)){ - cow_printf("Write of header to new COW file '%s' failed, " - "err = %d\n", cow_file, -err); + cow_printf("write_cow_header - write of header to " + "new COW file '%s' failed, err = %d\n", cow_file, + -err); goto out_free; } err = 0; @@ -299,7 +302,7 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, } else if(version == 3){ if(n < sizeof(header->v3)){ - cow_printf("read_cow_header - failed to read V2 " + cow_printf("read_cow_header - failed to read V3 " "header\n"); goto out; } @@ -359,7 +362,8 @@ int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, if(err != sizeof(zero)){ cow_printf("Write of bitmap to new COW file '%s' failed, " "err = %d\n", cow_file, -err); - err = -EINVAL; + if (err >= 0) + err = -EINVAL; goto out; } diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c index 098fa65981ab..0e2f06187ea7 100644 --- a/arch/um/drivers/net_user.c +++ b/arch/um/drivers/net_user.c @@ -47,10 +47,12 @@ void tap_check_ips(char *gate_addr, unsigned char *eth_addr) } } +/* Do reliable error handling as this fails frequently enough. */ void read_output(int fd, char *output, int len) { - int remain, n, actual; + int remain, ret, expected; char c; + char *str; if(output == NULL){ output = &c; @@ -58,23 +60,31 @@ void read_output(int fd, char *output, int len) } *output = '\0'; - n = os_read_file(fd, &remain, sizeof(remain)); - if(n != sizeof(remain)){ - printk("read_output - read of length failed, err = %d\n", -n); - return; + ret = os_read_file(fd, &remain, sizeof(remain)); + + if (ret != sizeof(remain)) { + expected = sizeof(remain); + str = "length"; + goto err; } while(remain != 0){ - n = (remain < len) ? remain : len; - actual = os_read_file(fd, output, n); - if(actual != n){ - printk("read_output - read of data failed, " - "err = %d\n", -actual); - return; + expected = (remain < len) ? remain : len; + ret = os_read_file(fd, output, expected); + if (ret != expected) { + str = "data"; + goto err; } - remain -= actual; + remain -= ret; } + return; + +err: + if (ret < 0) + printk("read_output - read of %s failed, errno = %d\n", str, -ret); + else + printk("read_output - read of %s failed, read only %d of %d bytes\n", str, ret, expected); } int net_read(int fd, void *buf, int len) diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 101efd26d467..fa617e0719ab 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -1135,7 +1135,7 @@ static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow) static int backing_file_mismatch(char *file, __u64 size, time_t mtime) { unsigned long modtime; - long long actual; + unsigned long long actual; int err; err = os_file_modtime(file, &modtime); diff --git a/arch/um/include/init.h b/arch/um/include/init.h index cbd79a8d213d..d4de7c0120ce 100644 --- a/arch/um/include/init.h +++ b/arch/um/include/init.h @@ -122,7 +122,7 @@ extern struct uml_param __uml_setup_start, __uml_setup_end; #define __exitcall(fn) static exitcall_t __exitcall_##fn __exit_call = fn -#define __init_call __attribute__ ((unused,__section__ (".initcall.init"))) +#define __init_call __attribute_used__ __attribute__ ((__section__ (".initcall.init"))) #endif diff --git a/arch/um/include/os.h b/arch/um/include/os.h index eb1710b81255..2a1c64d8d0bf 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -179,8 +179,11 @@ extern void os_stop_process(int pid); extern void os_kill_process(int pid, int reap_child); extern void os_kill_ptraced_process(int pid, int reap_child); extern void os_usr1_process(int pid); +extern long os_ptrace_ldt(long pid, long addr, long data); + extern int os_getpid(void); extern int os_getpgrp(void); + extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)); extern void init_new_thread_signals(int altstack); extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr); diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index f55773c819e6..3bd10deea280 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -272,14 +272,23 @@ int os_connect_socket(char *name) snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name); fd = socket(AF_UNIX, SOCK_STREAM, 0); - if(fd < 0) - return(fd); + if(fd < 0) { + err = -errno; + goto out; + } err = connect(fd, (struct sockaddr *) &sock, sizeof(sock)); - if(err) - return(-errno); + if(err) { + err = -errno; + goto out_close; + } - return(fd); + return fd; + +out_close: + close(fd); +out: + return err; } void os_close_file(int fd) diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index 7f5e2dac2a35..d261888f39c4 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -19,6 +19,7 @@ #include "irq_user.h" #include "kern_util.h" #include "longjmp.h" +#include "skas_ptrace.h" #define ARBITRARY_ADDR -1 #define FAILURE_PID -1 @@ -100,6 +101,21 @@ void os_kill_process(int pid, int reap_child) } +/* This is here uniquely to have access to the userspace errno, i.e. the one + * used by ptrace in case of error. + */ + +long os_ptrace_ldt(long pid, long addr, long data) +{ + int ret; + + ret = ptrace(PTRACE_LDT, pid, addr, data); + + if (ret < 0) + return -errno; + return ret; +} + /* Kill off a ptraced child by all means available. kill it normally first, * then PTRACE_KILL it, then PTRACE_CONT it in case it's in a run state from * which it can't exit directly. diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c index 1fa09a79a10b..fe0877b3509c 100644 --- a/arch/um/sys-i386/ldt.c +++ b/arch/um/sys-i386/ldt.c @@ -107,7 +107,7 @@ long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc, * So we need to switch child's mm into our userspace, then * later switch back. * - * Note: I'm unshure: should interrupts be disabled here? + * Note: I'm unsure: should interrupts be disabled here? */ if(!current->active_mm || current->active_mm == &init_mm || mm_idp != ¤t->active_mm->context.skas.id) @@ -129,9 +129,7 @@ long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc, pid = userspace_pid[cpu]; } - res = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op); - if(res) - res = errno; + res = os_ptrace_ldt(pid, 0, (unsigned long) &ldt_op); if(proc_mm) put_cpu(); @@ -181,8 +179,7 @@ static long read_ldt_from_host(void __user * ptr, unsigned long bytecount) */ cpu = get_cpu(); - res = ptrace(PTRACE_LDT, userspace_pid[cpu], 0, - (unsigned long) &ptrace_ldt); + res = os_ptrace_ldt(userspace_pid[cpu], 0, (unsigned long) &ptrace_ldt); put_cpu(); if(res < 0) goto out; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index e9adeb9d172f..745ca1f67b14 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -849,10 +849,16 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent) static void free_dev(struct mapped_device *md) { - free_minor(md->disk->first_minor); + unsigned int minor = md->disk->first_minor; + + if (md->suspended_bdev) { + thaw_bdev(md->suspended_bdev, NULL); + bdput(md->suspended_bdev); + } mempool_destroy(md->tio_pool); mempool_destroy(md->io_pool); del_gendisk(md->disk); + free_minor(minor); put_disk(md->disk); blk_put_queue(md->queue); kfree(md); diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index ded2c33f5b85..1c074d63ff3a 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -408,6 +408,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; cfi->chips[i].ref_point_counter = 0; + init_waitqueue_head(&(cfi->chips[i].wq)); } map->fldrv = &cfi_intelext_chipdrv; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index e64ed16bd42f..f5079c78ba4e 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -520,7 +520,7 @@ config FB_GBE config FB_GBE_MEM int "Video memory size in MB" depends on FB_GBE - default 8 + default 4 help This is the amount of memory reserved for the framebuffer, which can be any value between 1MB and 8MB. diff --git a/drivers/video/asiliantfb.c b/drivers/video/asiliantfb.c index 69f75547865d..c924d81f7978 100644 --- a/drivers/video/asiliantfb.c +++ b/drivers/video/asiliantfb.c @@ -322,32 +322,29 @@ static int asiliantfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, writeb(green, mmio_base + 0x791); writeb(blue, mmio_base + 0x791); - switch(p->var.bits_per_pixel) { - case 15: - if (regno < 16) { + if (regno < 16) { + switch(p->var.red.offset) { + case 10: /* RGB 555 */ ((u32 *)(p->pseudo_palette))[regno] = ((red & 0xf8) << 7) | ((green & 0xf8) << 2) | ((blue & 0xf8) >> 3); - } - break; - case 16: - if (regno < 16) { + break; + case 11: /* RGB 565 */ ((u32 *)(p->pseudo_palette))[regno] = ((red & 0xf8) << 8) | ((green & 0xfc) << 3) | ((blue & 0xf8) >> 3); - } - break; - case 24: - if (regno < 24) { + break; + case 16: /* RGB 888 */ ((u32 *)(p->pseudo_palette))[regno] = (red << 16) | (green << 8) | (blue); + break; } - break; } + return 0; } diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c index 2406899f1207..3d04b2def0f1 100644 --- a/drivers/video/au1100fb.c +++ b/drivers/video/au1100fb.c @@ -49,6 +49,7 @@ #include <linux/interrupt.h> #include <linux/ctype.h> #include <linux/dma-mapping.h> +#include <linux/platform_device.h> #include <asm/mach-au1x00/au1000.h> @@ -406,7 +407,7 @@ int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) vma->vm_flags |= VM_IO; - if (io_remap_page_range(vma, vma->vm_start, off, + if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) { return -EAGAIN; diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 12d9329d1408..5a86978537d2 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -509,57 +509,60 @@ static int vgacon_doresize(struct vc_data *c, { unsigned long flags; unsigned int scanlines = height * c->vc_font.height; - u8 scanlines_lo, r7, vsync_end, mode, max_scan; + u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan; spin_lock_irqsave(&vga_lock, flags); - outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg); - max_scan = inb_p(vga_video_port_val); - - if (max_scan & 0x80) - scanlines <<= 1; - vgacon_xres = width * VGA_FONTWIDTH; vgacon_yres = height * c->vc_font.height; - outb_p(VGA_CRTC_MODE, vga_video_port_reg); - mode = inb_p(vga_video_port_val); + if (vga_video_type >= VIDEO_TYPE_VGAC) { + outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg); + max_scan = inb_p(vga_video_port_val); - if (mode & 0x04) - scanlines >>= 1; + if (max_scan & 0x80) + scanlines <<= 1; - scanlines -= 1; - scanlines_lo = scanlines & 0xff; + outb_p(VGA_CRTC_MODE, vga_video_port_reg); + mode = inb_p(vga_video_port_val); - outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg); - r7 = inb_p(vga_video_port_val) & ~0x42; + if (mode & 0x04) + scanlines >>= 1; - if (scanlines & 0x100) - r7 |= 0x02; - if (scanlines & 0x200) - r7 |= 0x40; + scanlines -= 1; + scanlines_lo = scanlines & 0xff; - /* deprotect registers */ - outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg); - vsync_end = inb_p(vga_video_port_val); - outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg); - outb_p(vsync_end & ~0x80, vga_video_port_val); + outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg); + r7 = inb_p(vga_video_port_val) & ~0x42; + + if (scanlines & 0x100) + r7 |= 0x02; + if (scanlines & 0x200) + r7 |= 0x40; + + /* deprotect registers */ + outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg); + vsync_end = inb_p(vga_video_port_val); + outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg); + outb_p(vsync_end & ~0x80, vga_video_port_val); + } outb_p(VGA_CRTC_H_DISP, vga_video_port_reg); outb_p(width - 1, vga_video_port_val); outb_p(VGA_CRTC_OFFSET, vga_video_port_reg); outb_p(width >> 1, vga_video_port_val); - outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg); - outb_p(scanlines_lo, vga_video_port_val); - outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg); - outb_p(r7,vga_video_port_val); + if (vga_video_type >= VIDEO_TYPE_VGAC) { + outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg); + outb_p(scanlines_lo, vga_video_port_val); + outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg); + outb_p(r7,vga_video_port_val); - /* reprotect registers */ - outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg); - outb_p(vsync_end, vga_video_port_val); + /* reprotect registers */ + outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg); + outb_p(vsync_end, vga_video_port_val); + } spin_unlock_irqrestore(&vga_lock, flags); - return 0; } diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index c9a7cdf6d543..5e25b9860196 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -656,12 +656,15 @@ static int gbefb_set_par(struct fb_info *info) switch (bytesPerPixel) { case 1: SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_I8); + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; break; case 2: SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_ARGB5); + info->fix.visual = FB_VISUAL_TRUECOLOR; break; case 4: SET_GBE_FIELD(WID, TYP, val, GBE_CMODE_RGB8); + info->fix.visual = FB_VISUAL_TRUECOLOR; break; } SET_GBE_FIELD(WID, BUF, val, GBE_BMODE_BOTH); diff --git a/fs/namei.c b/fs/namei.c index e28de846c591..557dcf395ca1 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2224,13 +2224,17 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de * and other special files. --ADM */ asmlinkage long sys_linkat(int olddfd, const char __user *oldname, - int newdfd, const char __user *newname) + int newdfd, const char __user *newname, + int flags) { struct dentry *new_dentry; struct nameidata nd, old_nd; int error; char * to; + if (flags != 0) + return -EINVAL; + to = getname(newname); if (IS_ERR(to)) return PTR_ERR(to); @@ -2263,7 +2267,7 @@ exit: asmlinkage long sys_link(const char __user *oldname, const char __user *newname) { - return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname); + return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname, 0); } /* diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 02f44094bda9..9d8ffa89e2c2 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -1,9 +1,9 @@ ToDo/Notes: - Find and fix bugs. - The only places in the kernel where a file is resized are - ntfs_file_write*() and ntfs_truncate() for both of which i_sem is + ntfs_file_write*() and ntfs_truncate() for both of which i_mutex is held. Just have to be careful in read-/writepage and other helpers - not running under i_sem that we play nice... Also need to be careful + not running under i_mutex that we play nice. Also need to be careful with initialized_size extension in ntfs_file_write*() and writepage. UPDATE: The only things that need to be checked are the compressed write and the other attribute resize/write cases like index @@ -19,6 +19,24 @@ ToDo/Notes: - Enable the code for setting the NT4 compatibility flag when we start making NTFS 1.2 specific modifications. +2.1.26 - Minor bug fixes and updates. + + - Fix a potential overflow in file.c where a cast to s64 was missing in + a left shift of a page index. + - The struct inode has had its i_sem semaphore changed to a mutex named + i_mutex. + - We have struct kmem_cache now so use it instead of the typedef + kmem_cache_t. (Pekka Enberg) + - Implement support for sector sizes above 512 bytes (up to the maximum + supported by NTFS which is 4096 bytes). + - Do more detailed reporting of why we cannot mount read-write by + special casing the VOLUME_MODIFIED_BY_CHKDSK flag. + - Miscellaneous updates to layout.h. + - Cope with attribute list attribute having invalid flags. Windows + copes with this and even chkdsk does not detect or fix this so we + have to cope with it, too. Thanks to Pawel Kot for reporting the + problem. + 2.1.25 - (Almost) fully implement write(2) and truncate(2). - Change ntfs_map_runlist_nolock(), ntfs_attr_find_vcn_nolock() and @@ -373,7 +391,7 @@ ToDo/Notes: single one of them had an mst error. (Thanks to Ken MacFerrin for the bug report.) - Fix error handling in fs/ntfs/quota.c::ntfs_mark_quotas_out_of_date() - where we failed to release i_sem on the $Quota/$Q attribute inode. + where we failed to release i_mutex on the $Quota/$Q attribute inode. - Fix bug in handling of bad inodes in fs/ntfs/namei.c::ntfs_lookup(). - Add mapping of unmapped buffers to all remaining code paths, i.e. fs/ntfs/aops.c::ntfs_write_mst_block(), mft.c::ntfs_sync_mft_mirror(), @@ -874,7 +892,7 @@ ToDo/Notes: clusters. (Philipp Thomas) - attrib.c::load_attribute_list(): Fix bug when initialized_size is a multiple of the block_size but not the cluster size. (Szabolcs - Szakacsits <szaka@sienet.hu>) + Szakacsits) 2.1.2 - Important bug fixes aleviating the hangs in statfs. @@ -884,7 +902,7 @@ ToDo/Notes: - Add handling for initialized_size != data_size in compressed files. - Reduce function local stack usage from 0x3d4 bytes to just noise in - fs/ntfs/upcase.c. (Randy Dunlap <rdunlap@xenotime.net>) + fs/ntfs/upcase.c. (Randy Dunlap) - Remove compiler warnings for newer gcc. - Pages are no longer kmapped by mm/filemap.c::generic_file_write() around calls to ->{prepare,commit}_write. Adapt NTFS appropriately @@ -1201,11 +1219,11 @@ ToDo/Notes: the kernel. We probably want a kernel generic init_address_space() function... - Drop BKL from ntfs_readdir() after consultation with Al Viro. The - only caller of ->readdir() is vfs_readdir() which holds i_sem during - the call, and i_sem is sufficient protection against changes in the - directory inode (including ->i_size). + only caller of ->readdir() is vfs_readdir() which holds i_mutex + during the call, and i_mutex is sufficient protection against changes + in the directory inode (including ->i_size). - Use generic_file_llseek() for directories (as opposed to - default_llseek()) as this downs i_sem instead of the BKL which is + default_llseek()) as this downs i_mutex instead of the BKL which is what we now need for exclusion against ->f_pos changes considering we no longer take the BKL in ntfs_readdir(). diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile index d0d45d1c853a..d95fac7fdeb6 100644 --- a/fs/ntfs/Makefile +++ b/fs/ntfs/Makefile @@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \ index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ unistr.o upcase.o -EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.25\" +EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.26\" ifeq ($(CONFIG_NTFS_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 1c0a4315876a..7e361da770b3 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -2,7 +2,7 @@ * aops.c - NTFS kernel address space operations and page cache handling. * Part of the Linux-NTFS project. * - * Copyright (c) 2001-2005 Anton Altaparmakov + * Copyright (c) 2001-2006 Anton Altaparmakov * Copyright (c) 2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -200,8 +200,8 @@ static int ntfs_read_block(struct page *page) /* $MFT/$DATA must have its complete runlist in memory at all times. */ BUG_ON(!ni->runlist.rl && !ni->mft_no && !NInoAttr(ni)); - blocksize_bits = VFS_I(ni)->i_blkbits; - blocksize = 1 << blocksize_bits; + blocksize = vol->sb->s_blocksize; + blocksize_bits = vol->sb->s_blocksize_bits; if (!page_has_buffers(page)) { create_empty_buffers(page, blocksize, 0); @@ -569,10 +569,8 @@ static int ntfs_write_block(struct page *page, struct writeback_control *wbc) BUG_ON(!NInoNonResident(ni)); BUG_ON(NInoMstProtected(ni)); - - blocksize_bits = vi->i_blkbits; - blocksize = 1 << blocksize_bits; - + blocksize = vol->sb->s_blocksize; + blocksize_bits = vol->sb->s_blocksize_bits; if (!page_has_buffers(page)) { BUG_ON(!PageUptodate(page)); create_empty_buffers(page, blocksize, @@ -949,8 +947,8 @@ static int ntfs_write_mst_block(struct page *page, */ BUG_ON(!(is_mft || S_ISDIR(vi->i_mode) || (NInoAttr(ni) && ni->type == AT_INDEX_ALLOCATION))); - bh_size_bits = vi->i_blkbits; - bh_size = 1 << bh_size_bits; + bh_size = vol->sb->s_blocksize; + bh_size_bits = vol->sb->s_blocksize_bits; max_bhs = PAGE_CACHE_SIZE / bh_size; BUG_ON(!max_bhs); BUG_ON(max_bhs > MAX_BUF_PER_PAGE); @@ -1596,7 +1594,7 @@ void mark_ntfs_record_dirty(struct page *page, const unsigned int ofs) { BUG_ON(!PageUptodate(page)); end = ofs + ni->itype.index.block_size; - bh_size = 1 << VFS_I(ni)->i_blkbits; + bh_size = VFS_I(ni)->i_sb->s_blocksize; spin_lock(&mapping->private_lock); if (unlikely(!page_has_buffers(page))) { spin_unlock(&mapping->private_lock); diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index fb413d3d8618..5027d3d1b3fe 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -1,7 +1,7 @@ /* * file.c - NTFS kernel file operations. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2005 Anton Altaparmakov + * Copyright (c) 2001-2006 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -248,7 +248,7 @@ do_non_resident_extend: * enough to make ntfs_writepage() work. */ write_lock_irqsave(&ni->size_lock, flags); - ni->initialized_size = (index + 1) << PAGE_CACHE_SHIFT; + ni->initialized_size = (s64)(index + 1) << PAGE_CACHE_SHIFT; if (ni->initialized_size > new_init_size) ni->initialized_size = new_init_size; write_unlock_irqrestore(&ni->size_lock, flags); @@ -529,8 +529,8 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages, "index 0x%lx, nr_pages 0x%x, pos 0x%llx, bytes 0x%zx.", vi->i_ino, ni->type, pages[0]->index, nr_pages, (long long)pos, bytes); - blocksize_bits = vi->i_blkbits; - blocksize = 1 << blocksize_bits; + blocksize = vol->sb->s_blocksize; + blocksize_bits = vol->sb->s_blocksize_bits; u = 0; do { struct page *page = pages[u]; @@ -1525,7 +1525,7 @@ static inline int ntfs_commit_pages_after_non_resident_write( vi = pages[0]->mapping->host; ni = NTFS_I(vi); - blocksize = 1 << vi->i_blkbits; + blocksize = vi->i_sb->s_blocksize; end = pos + bytes; u = 0; do { diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index ea1bd3feea1b..55263b7de9c0 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -677,13 +677,28 @@ static int ntfs_read_locked_inode(struct inode *vi) ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino); NInoSetAttrList(ni); a = ctx->attr; - if (a->flags & ATTR_IS_ENCRYPTED || - a->flags & ATTR_COMPRESSION_MASK || - a->flags & ATTR_IS_SPARSE) { + if (a->flags & ATTR_COMPRESSION_MASK) { ntfs_error(vi->i_sb, "Attribute list attribute is " - "compressed/encrypted/sparse."); + "compressed."); goto unm_err_out; } + if (a->flags & ATTR_IS_ENCRYPTED || + a->flags & ATTR_IS_SPARSE) { + if (a->non_resident) { + ntfs_error(vi->i_sb, "Non-resident attribute " + "list attribute is encrypted/" + "sparse."); + goto unm_err_out; + } + ntfs_warning(vi->i_sb, "Resident attribute list " + "attribute in inode 0x%lx is marked " + "encrypted/sparse which is not true. " + "However, Windows allows this and " + "chkdsk does not detect or correct it " + "so we will just ignore the invalid " + "flags and pretend they are not set.", + vi->i_ino); + } /* Now allocate memory for the attribute list. */ ni->attr_list_size = (u32)ntfs_attr_size(a); ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size); @@ -1809,19 +1824,33 @@ int ntfs_read_inode_mount(struct inode *vi) } else /* if (!err) */ { ATTR_LIST_ENTRY *al_entry, *next_al_entry; u8 *al_end; + static const char *es = " Not allowed. $MFT is corrupt. " + "You should run chkdsk."; ntfs_debug("Attribute list attribute found in $MFT."); NInoSetAttrList(ni); a = ctx->attr; - if (a->flags & ATTR_IS_ENCRYPTED || - a->flags & ATTR_COMPRESSION_MASK || - a->flags & ATTR_IS_SPARSE) { + if (a->flags & ATTR_COMPRESSION_MASK) { ntfs_error(sb, "Attribute list attribute is " - "compressed/encrypted/sparse. Not " - "allowed. $MFT is corrupt. You should " - "run chkdsk."); + "compressed.%s", es); goto put_err_out; } + if (a->flags & ATTR_IS_ENCRYPTED || + a->flags & ATTR_IS_SPARSE) { + if (a->non_resident) { + ntfs_error(sb, "Non-resident attribute list " + "attribute is encrypted/" + "sparse.%s", es); + goto put_err_out; + } + ntfs_warning(sb, "Resident attribute list attribute " + "in $MFT system file is marked " + "encrypted/sparse which is not true. " + "However, Windows allows this and " + "chkdsk does not detect or correct it " + "so we will just ignore the invalid " + "flags and pretend they are not set."); + } /* Now allocate memory for the attribute list. */ ni->attr_list_size = (u32)ntfs_attr_size(a); ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size); diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h index f5678d5d7919..bb408d4dcbb0 100644 --- a/fs/ntfs/layout.h +++ b/fs/ntfs/layout.h @@ -838,15 +838,19 @@ enum { F_A_DEVICE, F_A_DIRECTORY, F_A_SPARSE_FILE, F_A_REPARSE_POINT, F_A_COMPRESSED, and F_A_ENCRYPTED and preserves the rest. This mask is used to to obtain all flags that are valid for setting. */ - /* - * The following flags are only present in the FILE_NAME attribute (in + * The following flag is only present in the FILE_NAME attribute (in * the field file_attributes). */ FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT = const_cpu_to_le32(0x10000000), /* Note, this is a copy of the corresponding bit from the mft record, telling us whether this is a directory or not, i.e. whether it has an index root attribute or not. */ + /* + * The following flag is present both in the STANDARD_INFORMATION + * attribute and in the FILE_NAME attribute (in the field + * file_attributes). + */ FILE_ATTR_DUP_VIEW_INDEX_PRESENT = const_cpu_to_le32(0x20000000), /* Note, this is a copy of the corresponding bit from the mft record, telling us whether this file has a view index present (eg. object id @@ -1071,9 +1075,15 @@ typedef struct { modified. */ /* 20*/ sle64 last_access_time; /* Time this mft record was last accessed. */ -/* 28*/ sle64 allocated_size; /* Byte size of allocated space for the - data attribute. NOTE: Is a multiple - of the cluster size. */ +/* 28*/ sle64 allocated_size; /* Byte size of on-disk allocated space + for the data attribute. So for + normal $DATA, this is the + allocated_size from the unnamed + $DATA attribute and for compressed + and/or sparse $DATA, this is the + compressed_size from the unnamed + $DATA attribute. NOTE: This is a + multiple of the cluster size. */ /* 30*/ sle64 data_size; /* Byte size of actual data in data attribute. */ /* 38*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */ @@ -1904,12 +1914,13 @@ enum { VOLUME_DELETE_USN_UNDERWAY = const_cpu_to_le16(0x0010), VOLUME_REPAIR_OBJECT_ID = const_cpu_to_le16(0x0020), + VOLUME_CHKDSK_UNDERWAY = const_cpu_to_le16(0x4000), VOLUME_MODIFIED_BY_CHKDSK = const_cpu_to_le16(0x8000), - VOLUME_FLAGS_MASK = const_cpu_to_le16(0x803f), + VOLUME_FLAGS_MASK = const_cpu_to_le16(0xc03f), /* To make our life easier when checking if we must mount read-only. */ - VOLUME_MUST_MOUNT_RO_MASK = const_cpu_to_le16(0x8027), + VOLUME_MUST_MOUNT_RO_MASK = const_cpu_to_le16(0xc027), } __attribute__ ((__packed__)); typedef le16 VOLUME_FLAGS; diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 0c65cbb8c5cf..6499aafc2258 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -1,7 +1,7 @@ /** * mft.c - NTFS kernel mft record operations. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2005 Anton Altaparmakov + * Copyright (c) 2001-2006 Anton Altaparmakov * Copyright (c) 2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -473,7 +473,7 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no, runlist_element *rl; unsigned int block_start, block_end, m_start, m_end, page_ofs; int i_bhs, nr_bhs, err = 0; - unsigned char blocksize_bits = vol->mftmirr_ino->i_blkbits; + unsigned char blocksize_bits = vol->sb->s_blocksize_bits; ntfs_debug("Entering for inode 0x%lx.", mft_no); BUG_ON(!max_bhs); @@ -672,8 +672,8 @@ int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync) { ntfs_volume *vol = ni->vol; struct page *page = ni->page; - unsigned char blocksize_bits = vol->mft_ino->i_blkbits; - unsigned int blocksize = 1 << blocksize_bits; + unsigned int blocksize = vol->sb->s_blocksize; + unsigned char blocksize_bits = vol->sb->s_blocksize_bits; int max_bhs = vol->mft_record_size / blocksize; struct buffer_head *bhs[max_bhs]; struct buffer_head *bh, *head; diff --git a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h index 446b5014115c..653d2a5c4899 100644 --- a/fs/ntfs/ntfs.h +++ b/fs/ntfs/ntfs.h @@ -50,11 +50,11 @@ typedef enum { /* Global variables. */ /* Slab caches (from super.c). */ -extern kmem_cache_t *ntfs_name_cache; -extern kmem_cache_t *ntfs_inode_cache; -extern kmem_cache_t *ntfs_big_inode_cache; -extern kmem_cache_t *ntfs_attr_ctx_cache; -extern kmem_cache_t *ntfs_index_ctx_cache; +extern struct kmem_cache *ntfs_name_cache; +extern struct kmem_cache *ntfs_inode_cache; +extern struct kmem_cache *ntfs_big_inode_cache; +extern struct kmem_cache *ntfs_attr_ctx_cache; +extern struct kmem_cache *ntfs_index_ctx_cache; /* The various operations structs defined throughout the driver files. */ extern struct address_space_operations ntfs_aops; diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index c3a3f1a8310b..368a8ec10668 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -1,7 +1,7 @@ /* * super.c - NTFS kernel super block handling. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2005 Anton Altaparmakov + * Copyright (c) 2001-2006 Anton Altaparmakov * Copyright (c) 2001,2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -22,6 +22,7 @@ #include <linux/stddef.h> #include <linux/init.h> +#include <linux/slab.h> #include <linux/string.h> #include <linux/spinlock.h> #include <linux/blkdev.h> /* For bdev_hardsect_size(). */ @@ -471,9 +472,16 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) ntfs_error(sb, "Volume is dirty and read-only%s", es); return -EROFS; } + if (vol->vol_flags & VOLUME_MODIFIED_BY_CHKDSK) { + ntfs_error(sb, "Volume has been modified by chkdsk " + "and is read-only%s", es); + return -EROFS; + } if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) { - ntfs_error(sb, "Volume has unsupported flags set and " - "is read-only%s", es); + ntfs_error(sb, "Volume has unsupported flags set " + "(0x%x) and is read-only%s", + (unsigned)le16_to_cpu(vol->vol_flags), + es); return -EROFS; } if (ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) { @@ -641,7 +649,7 @@ static struct buffer_head *read_ntfs_boot_sector(struct super_block *sb, { const char *read_err_str = "Unable to read %s boot sector."; struct buffer_head *bh_primary, *bh_backup; - long nr_blocks = NTFS_SB(sb)->nr_blocks; + sector_t nr_blocks = NTFS_SB(sb)->nr_blocks; /* Try to read primary boot sector. */ if ((bh_primary = sb_bread(sb, 0))) { @@ -688,13 +696,18 @@ hotfix_primary_boot_sector: /* * If we managed to read sector zero and the volume is not * read-only, copy the found, valid backup boot sector to the - * primary boot sector. + * primary boot sector. Note we only copy the actual boot + * sector structure, not the actual whole device sector as that + * may be bigger and would potentially damage the $Boot system + * file (FIXME: Would be nice to know if the backup boot sector + * on a large sector device contains the whole boot loader or + * just the first 512 bytes). */ if (!(sb->s_flags & MS_RDONLY)) { ntfs_warning(sb, "Hot-fix: Recovering invalid primary " "boot sector from backup copy."); memcpy(bh_primary->b_data, bh_backup->b_data, - sb->s_blocksize); + NTFS_BLOCK_SIZE); mark_buffer_dirty(bh_primary); sync_dirty_buffer(bh_primary); if (buffer_uptodate(bh_primary)) { @@ -733,9 +746,13 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) vol->sector_size); ntfs_debug("vol->sector_size_bits = %i (0x%x)", vol->sector_size_bits, vol->sector_size_bits); - if (vol->sector_size != vol->sb->s_blocksize) - ntfs_warning(vol->sb, "The boot sector indicates a sector size " - "different from the device sector size."); + if (vol->sector_size < vol->sb->s_blocksize) { + ntfs_error(vol->sb, "Sector size (%i) is smaller than the " + "device block size (%lu). This is not " + "supported. Sorry.", vol->sector_size, + vol->sb->s_blocksize); + return FALSE; + } ntfs_debug("sectors_per_cluster = 0x%x", b->bpb.sectors_per_cluster); sectors_per_cluster_bits = ffs(b->bpb.sectors_per_cluster) - 1; ntfs_debug("sectors_per_cluster_bits = 0x%x", @@ -748,16 +765,11 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) ntfs_debug("vol->cluster_size = %i (0x%x)", vol->cluster_size, vol->cluster_size); ntfs_debug("vol->cluster_size_mask = 0x%x", vol->cluster_size_mask); - ntfs_debug("vol->cluster_size_bits = %i (0x%x)", - vol->cluster_size_bits, vol->cluster_size_bits); - if (vol->sector_size > vol->cluster_size) { - ntfs_error(vol->sb, "Sector sizes above the cluster size are " - "not supported. Sorry."); - return FALSE; - } - if (vol->sb->s_blocksize > vol->cluster_size) { - ntfs_error(vol->sb, "Cluster sizes smaller than the device " - "sector size are not supported. Sorry."); + ntfs_debug("vol->cluster_size_bits = %i", vol->cluster_size_bits); + if (vol->cluster_size < vol->sector_size) { + ntfs_error(vol->sb, "Cluster size (%i) is smaller than the " + "sector size (%i). This is not supported. " + "Sorry.", vol->cluster_size, vol->sector_size); return FALSE; } clusters_per_mft_record = b->clusters_per_mft_record; @@ -786,11 +798,18 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) * we store $MFT/$DATA, the table of mft records in the page cache. */ if (vol->mft_record_size > PAGE_CACHE_SIZE) { - ntfs_error(vol->sb, "Mft record size %i (0x%x) exceeds the " - "page cache size on your system %lu (0x%lx). " + ntfs_error(vol->sb, "Mft record size (%i) exceeds the " + "PAGE_CACHE_SIZE on your system (%lu). " "This is not supported. Sorry.", - vol->mft_record_size, vol->mft_record_size, - PAGE_CACHE_SIZE, PAGE_CACHE_SIZE); + vol->mft_record_size, PAGE_CACHE_SIZE); + return FALSE; + } + /* We cannot support mft record sizes below the sector size. */ + if (vol->mft_record_size < vol->sector_size) { + ntfs_error(vol->sb, "Mft record size (%i) is smaller than the " + "sector size (%i). This is not supported. " + "Sorry.", vol->mft_record_size, + vol->sector_size); return FALSE; } clusters_per_index_record = b->clusters_per_index_record; @@ -816,6 +835,14 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) ntfs_debug("vol->index_record_size_bits = %i (0x%x)", vol->index_record_size_bits, vol->index_record_size_bits); + /* We cannot support index record sizes below the sector size. */ + if (vol->index_record_size < vol->sector_size) { + ntfs_error(vol->sb, "Index record size (%i) is smaller than " + "the sector size (%i). This is not " + "supported. Sorry.", vol->index_record_size, + vol->sector_size); + return FALSE; + } /* * Get the size of the volume in clusters and check for 64-bit-ness. * Windows currently only uses 32 bits to save the clusters so we do @@ -845,15 +872,18 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) } ll = sle64_to_cpu(b->mft_lcn); if (ll >= vol->nr_clusters) { - ntfs_error(vol->sb, "MFT LCN is beyond end of volume. Weird."); + ntfs_error(vol->sb, "MFT LCN (%lli, 0x%llx) is beyond end of " + "volume. Weird.", (unsigned long long)ll, + (unsigned long long)ll); return FALSE; } vol->mft_lcn = ll; ntfs_debug("vol->mft_lcn = 0x%llx", (long long)vol->mft_lcn); ll = sle64_to_cpu(b->mftmirr_lcn); if (ll >= vol->nr_clusters) { - ntfs_error(vol->sb, "MFTMirr LCN is beyond end of volume. " - "Weird."); + ntfs_error(vol->sb, "MFTMirr LCN (%lli, 0x%llx) is beyond end " + "of volume. Weird.", (unsigned long long)ll, + (unsigned long long)ll); return FALSE; } vol->mftmirr_lcn = ll; @@ -1822,11 +1852,24 @@ get_ctx_vol_failed: /* Make sure that no unsupported volume flags are set. */ if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) { static const char *es1a = "Volume is dirty"; - static const char *es1b = "Volume has unsupported flags set"; - static const char *es2 = ". Run chkdsk and mount in Windows."; - const char *es1; - - es1 = vol->vol_flags & VOLUME_IS_DIRTY ? es1a : es1b; + static const char *es1b = "Volume has been modified by chkdsk"; + static const char *es1c = "Volume has unsupported flags set"; + static const char *es2a = ". Run chkdsk and mount in Windows."; + static const char *es2b = ". Mount in Windows."; + const char *es1, *es2; + + es2 = es2a; + if (vol->vol_flags & VOLUME_IS_DIRTY) + es1 = es1a; + else if (vol->vol_flags & VOLUME_MODIFIED_BY_CHKDSK) { + es1 = es1b; + es2 = es2b; + } else { + es1 = es1c; + ntfs_warning(sb, "Unsupported volume flags 0x%x " + "encountered.", + (unsigned)le16_to_cpu(vol->vol_flags)); + } /* If a read-write mount, convert it to a read-only mount. */ if (!(sb->s_flags & MS_RDONLY)) { if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO | @@ -2685,7 +2728,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) ntfs_volume *vol; struct buffer_head *bh; struct inode *tmp_ino; - int result; + int blocksize, result; ntfs_debug("Entering."); #ifndef NTFS_RW @@ -2724,60 +2767,85 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) if (!parse_options(vol, (char*)opt)) goto err_out_now; + /* We support sector sizes up to the PAGE_CACHE_SIZE. */ + if (bdev_hardsect_size(sb->s_bdev) > PAGE_CACHE_SIZE) { + if (!silent) + ntfs_error(sb, "Device has unsupported sector size " + "(%i). The maximum supported sector " + "size on this architecture is %lu " + "bytes.", + bdev_hardsect_size(sb->s_bdev), + PAGE_CACHE_SIZE); + goto err_out_now; + } /* - * TODO: Fail safety check. In the future we should really be able to - * cope with this being the case, but for now just bail out. + * Setup the device access block size to NTFS_BLOCK_SIZE or the hard + * sector size, whichever is bigger. */ - if (bdev_hardsect_size(sb->s_bdev) > NTFS_BLOCK_SIZE) { + blocksize = sb_min_blocksize(sb, NTFS_BLOCK_SIZE); + if (blocksize < NTFS_BLOCK_SIZE) { if (!silent) - ntfs_error(sb, "Device has unsupported hardsect_size."); + ntfs_error(sb, "Unable to set device block size."); goto err_out_now; } - - /* Setup the device access block size to NTFS_BLOCK_SIZE. */ - if (sb_set_blocksize(sb, NTFS_BLOCK_SIZE) != NTFS_BLOCK_SIZE) { + BUG_ON(blocksize != sb->s_blocksize); + ntfs_debug("Set device block size to %i bytes (block size bits %i).", + blocksize, sb->s_blocksize_bits); + /* Determine the size of the device in units of block_size bytes. */ + if (!i_size_read(sb->s_bdev->bd_inode)) { if (!silent) - ntfs_error(sb, "Unable to set block size."); + ntfs_error(sb, "Unable to determine device size."); goto err_out_now; } - - /* Get the size of the device in units of NTFS_BLOCK_SIZE bytes. */ vol->nr_blocks = i_size_read(sb->s_bdev->bd_inode) >> - NTFS_BLOCK_SIZE_BITS; - + sb->s_blocksize_bits; /* Read the boot sector and return unlocked buffer head to it. */ if (!(bh = read_ntfs_boot_sector(sb, silent))) { if (!silent) ntfs_error(sb, "Not an NTFS volume."); goto err_out_now; } - /* - * Extract the data from the boot sector and setup the ntfs super block + * Extract the data from the boot sector and setup the ntfs volume * using it. */ result = parse_ntfs_boot_sector(vol, (NTFS_BOOT_SECTOR*)bh->b_data); - - /* Initialize the cluster and mft allocators. */ - ntfs_setup_allocators(vol); - brelse(bh); - if (!result) { if (!silent) ntfs_error(sb, "Unsupported NTFS filesystem."); goto err_out_now; } - /* - * TODO: When we start coping with sector sizes different from - * NTFS_BLOCK_SIZE, we now probably need to set the blocksize of the - * device (probably to NTFS_BLOCK_SIZE). + * If the boot sector indicates a sector size bigger than the current + * device block size, switch the device block size to the sector size. + * TODO: It may be possible to support this case even when the set + * below fails, we would just be breaking up the i/o for each sector + * into multiple blocks for i/o purposes but otherwise it should just + * work. However it is safer to leave disabled until someone hits this + * error message and then we can get them to try it without the setting + * so we know for sure that it works. */ - + if (vol->sector_size > blocksize) { + blocksize = sb_set_blocksize(sb, vol->sector_size); + if (blocksize != vol->sector_size) { + if (!silent) + ntfs_error(sb, "Unable to set device block " + "size to sector size (%i).", + vol->sector_size); + goto err_out_now; + } + BUG_ON(blocksize != sb->s_blocksize); + vol->nr_blocks = i_size_read(sb->s_bdev->bd_inode) >> + sb->s_blocksize_bits; + ntfs_debug("Changed device block size to %i bytes (block size " + "bits %i) to match volume sector size.", + blocksize, sb->s_blocksize_bits); + } + /* Initialize the cluster and mft allocators. */ + ntfs_setup_allocators(vol); /* Setup remaining fields in the super block. */ sb->s_magic = NTFS_SB_MAGIC; - /* * Ntfs allows 63 bits for the file size, i.e. correct would be: * sb->s_maxbytes = ~0ULL >> 1; @@ -2787,9 +2855,8 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) * without overflowing the index or to 2^63 - 1, whichever is smaller. */ sb->s_maxbytes = MAX_LFS_FILESIZE; - + /* Ntfs measures time in 100ns intervals. */ sb->s_time_gran = 100; - /* * Now load the metadata required for the page cache and our address * space operations to function. We do this by setting up a specialised @@ -2987,14 +3054,14 @@ err_out_now: * strings of the maximum length allowed by NTFS, which is NTFS_MAX_NAME_LEN * (255) Unicode characters + a terminating NULL Unicode character. */ -kmem_cache_t *ntfs_name_cache; +struct kmem_cache *ntfs_name_cache; /* Slab caches for efficient allocation/deallocation of inodes. */ -kmem_cache_t *ntfs_inode_cache; -kmem_cache_t *ntfs_big_inode_cache; +struct kmem_cache *ntfs_inode_cache; +struct kmem_cache *ntfs_big_inode_cache; /* Init once constructor for the inode slab cache. */ -static void ntfs_big_inode_init_once(void *foo, kmem_cache_t *cachep, +static void ntfs_big_inode_init_once(void *foo, struct kmem_cache *cachep, unsigned long flags) { ntfs_inode *ni = (ntfs_inode *)foo; @@ -3008,8 +3075,8 @@ static void ntfs_big_inode_init_once(void *foo, kmem_cache_t *cachep, * Slab caches to optimize allocations and deallocations of attribute search * contexts and index contexts, respectively. */ -kmem_cache_t *ntfs_attr_ctx_cache; -kmem_cache_t *ntfs_index_ctx_cache; +struct kmem_cache *ntfs_attr_ctx_cache; +struct kmem_cache *ntfs_index_ctx_cache; /* Driver wide semaphore. */ DECLARE_MUTEX(ntfs_lock); diff --git a/fs/ntfs/upcase.c b/fs/ntfs/upcase.c index 879cdf1d5bd3..9101807dc81a 100644 --- a/fs/ntfs/upcase.c +++ b/fs/ntfs/upcase.c @@ -3,10 +3,7 @@ * Part of the Linux-NTFS project. * * Copyright (c) 2001 Richard Russon <ntfs@flatcap.org> - * Copyright (c) 2001-2004 Anton Altaparmakov - * - * Modified for mkntfs inclusion 9 June 2001 by Anton Altaparmakov. - * Modified for kernel inclusion 10 September 2001 by Anton Altparmakov. + * Copyright (c) 2001-2006 Anton Altaparmakov * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -75,12 +72,13 @@ ntfschar *generate_default_upcase(void) if (!uc) return uc; memset(uc, 0, default_upcase_len * sizeof(ntfschar)); + /* Generate the little endian Unicode upcase table used by ntfs. */ for (i = 0; i < default_upcase_len; i++) uc[i] = cpu_to_le16(i); for (r = 0; uc_run_table[r][0]; r++) for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++) - uc[i] = cpu_to_le16((le16_to_cpu(uc[i]) + - uc_run_table[r][2])); + uc[i] = cpu_to_le16(le16_to_cpu(uc[i]) + + uc_run_table[r][2]); for (r = 0; uc_dup_table[r][0]; r++) for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2) uc[i + 1] = cpu_to_le16(le16_to_cpu(uc[i + 1]) - 1); diff --git a/fs/ntfs/volume.h b/fs/ntfs/volume.h index 375cd20a9f61..406ab55dfb32 100644 --- a/fs/ntfs/volume.h +++ b/fs/ntfs/volume.h @@ -2,7 +2,7 @@ * volume.h - Defines for volume structures in NTFS Linux kernel driver. Part * of the Linux-NTFS project. * - * Copyright (c) 2001-2005 Anton Altaparmakov + * Copyright (c) 2001-2006 Anton Altaparmakov * Copyright (c) 2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -41,10 +41,8 @@ typedef struct { * structure has stabilized... (AIA) */ /* Device specifics. */ - struct super_block *sb; /* Pointer back to the super_block, - so we don't have to get the offset - every time. */ - LCN nr_blocks; /* Number of NTFS_BLOCK_SIZE bytes + struct super_block *sb; /* Pointer back to the super_block. */ + LCN nr_blocks; /* Number of sb->s_blocksize bytes sized blocks on the device. */ /* Configuration provided by user at mount time. */ unsigned long flags; /* Miscellaneous flags, see below. */ @@ -141,8 +139,8 @@ typedef enum { NV_ShowSystemFiles, /* 1: Return system files in ntfs_readdir(). */ NV_CaseSensitive, /* 1: Treat file names as case sensitive and create filenames in the POSIX namespace. - Otherwise be case insensitive and create - file names in WIN32 namespace. */ + Otherwise be case insensitive but still + create file names in POSIX namespace. */ NV_LogFileEmpty, /* 1: $LogFile journal is empty. */ NV_QuotaOutOfDate, /* 1: $Quota is out of date. */ NV_UsnJrnlStamped, /* 1: $UsnJrnl has been stamped. */ @@ -153,7 +151,7 @@ typedef enum { * Macro tricks to expand the NVolFoo(), NVolSetFoo(), and NVolClearFoo() * functions. */ -#define NVOL_FNS(flag) \ +#define DEFINE_NVOL_BIT_OPS(flag) \ static inline int NVol##flag(ntfs_volume *vol) \ { \ return test_bit(NV_##flag, &(vol)->flags); \ @@ -168,12 +166,12 @@ static inline void NVolClear##flag(ntfs_volume *vol) \ } /* Emit the ntfs volume bitops functions. */ -NVOL_FNS(Errors) -NVOL_FNS(ShowSystemFiles) -NVOL_FNS(CaseSensitive) -NVOL_FNS(LogFileEmpty) -NVOL_FNS(QuotaOutOfDate) -NVOL_FNS(UsnJrnlStamped) -NVOL_FNS(SparseEnabled) +DEFINE_NVOL_BIT_OPS(Errors) +DEFINE_NVOL_BIT_OPS(ShowSystemFiles) +DEFINE_NVOL_BIT_OPS(CaseSensitive) +DEFINE_NVOL_BIT_OPS(LogFileEmpty) +DEFINE_NVOL_BIT_OPS(QuotaOutOfDate) +DEFINE_NVOL_BIT_OPS(UsnJrnlStamped) +DEFINE_NVOL_BIT_OPS(SparseEnabled) #endif /* _LINUX_NTFS_VOLUME_H */ diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index c66bd5e4c05c..cde5d48994ae 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -27,6 +27,7 @@ #include <linux/fs.h> #include <linux/pagemap.h> #include <linux/highmem.h> +#include <linux/time.h> #include <linux/init.h> #include <linux/string.h> #include <linux/smp_lock.h> @@ -104,6 +105,7 @@ ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) d_instantiate(dentry, inode); dget(dentry); /* Extra count - pin the dentry in core */ error = 0; + dir->i_mtime = dir->i_ctime = CURRENT_TIME; } return error; } diff --git a/include/asm-i386/desc.h b/include/asm-i386/desc.h index 494e73bca095..89b8b82c82b3 100644 --- a/include/asm-i386/desc.h +++ b/include/asm-i386/desc.h @@ -24,11 +24,13 @@ struct Xgt_desc_struct { unsigned short pad; } __attribute__ ((packed)); -extern struct Xgt_desc_struct idt_descr, cpu_gdt_descr[NR_CPUS]; +extern struct Xgt_desc_struct idt_descr; +DECLARE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr); + static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) { - return ((struct desc_struct *)cpu_gdt_descr[cpu].address); + return (struct desc_struct *)per_cpu(cpu_gdt_descr, cpu).address; } #define load_TR_desc() __asm__ __volatile__("ltr %w0"::"q" (GDT_ENTRY_TSS*8)) diff --git a/include/asm-i386/kprobes.h b/include/asm-i386/kprobes.h index 27cac050a60e..a0d2d74a7dda 100644 --- a/include/asm-i386/kprobes.h +++ b/include/asm-i386/kprobes.h @@ -27,6 +27,9 @@ #include <linux/types.h> #include <linux/ptrace.h> +#define __ARCH_WANT_KPROBES_INSN_SLOT + +struct kprobe; struct pt_regs; typedef u8 kprobe_opcode_t; @@ -40,14 +43,14 @@ typedef u8 kprobe_opcode_t; #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry #define ARCH_SUPPORTS_KRETPROBES -#define arch_remove_kprobe(p) do {} while (0) +void arch_remove_kprobe(struct kprobe *p); void kretprobe_trampoline(void); /* Architecture specific copy of original instruction*/ struct arch_specific_insn { /* copy of the original instruction */ - kprobe_opcode_t insn[MAX_INSN_SIZE]; + kprobe_opcode_t *insn; }; struct prev_kprobe { diff --git a/include/asm-m32r/uaccess.h b/include/asm-m32r/uaccess.h index 0da7c47d2f01..e8ae61956a51 100644 --- a/include/asm-m32r/uaccess.h +++ b/include/asm-m32r/uaccess.h @@ -328,7 +328,7 @@ extern void __put_user_bad(void); " .long 1b,4b\n" \ " .long 2b,4b\n" \ ".previous" \ - : "=r"(err) \ + : "=&r"(err) \ : "r"(x), "r"(addr), "i"(-EFAULT), "0"(err) \ : "r14", "memory") @@ -353,7 +353,7 @@ extern void __put_user_bad(void); " .long 1b,4b\n" \ " .long 2b,4b\n" \ ".previous" \ - : "=r"(err) \ + : "=&r"(err) \ : "r"(x), "r"(addr), "i"(-EFAULT), "0"(err) \ : "r14", "memory") #else @@ -398,7 +398,7 @@ struct __large_struct { unsigned long buf[100]; }; " .balign 4\n" \ " .long 1b,3b\n" \ ".previous" \ - : "=r"(err) \ + : "=&r"(err) \ : "r"(x), "r"(addr), "i"(-EFAULT), "0"(err) \ : "r14", "memory") @@ -442,7 +442,7 @@ do { \ " .balign 4\n" \ " .long 1b,3b\n" \ ".previous" \ - : "=r"(err), "=&r"(x) \ + : "=&r"(err), "=&r"(x) \ : "r"(addr), "i"(-EFAULT), "0"(err) \ : "r14", "memory") diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index d73501ba7e44..b9ea44ac0ddb 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -543,7 +543,7 @@ asmlinkage long sys_unlinkat(int dfd, const char __user * pathname, int flag); asmlinkage long sys_symlinkat(const char __user * oldname, int newdfd, const char __user * newname); asmlinkage long sys_linkat(int olddfd, const char __user *oldname, - int newdfd, const char __user *newname); + int newdfd, const char __user *newname, int flags); asmlinkage long sys_renameat(int olddfd, const char __user * oldname, int newdfd, const char __user * newname); asmlinkage long sys_futimesat(int dfd, char __user *filename, diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 880831bd3003..67af4cea1e23 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -552,7 +552,7 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist, */ if ((flags & MPOL_MF_MOVE_ALL) || page_mapcount(page) == 1) { if (isolate_lru_page(page)) - list_add(&page->lru, pagelist); + list_add_tail(&page->lru, pagelist); } } @@ -569,6 +569,7 @@ static int migrate_pages_to(struct list_head *pagelist, LIST_HEAD(moved); LIST_HEAD(failed); int err = 0; + unsigned long offset = 0; int nr_pages; struct page *page; struct list_head *p; @@ -576,8 +577,21 @@ static int migrate_pages_to(struct list_head *pagelist, redo: nr_pages = 0; list_for_each(p, pagelist) { - if (vma) - page = alloc_page_vma(GFP_HIGHUSER, vma, vma->vm_start); + if (vma) { + /* + * The address passed to alloc_page_vma is used to + * generate the proper interleave behavior. We fake + * the address here by an increasing offset in order + * to get the proper distribution of pages. + * + * No decision has been made as to which page + * a certain old page is moved to so we cannot + * specify the correct address. + */ + page = alloc_page_vma(GFP_HIGHUSER, vma, + offset + vma->vm_start); + offset += PAGE_SIZE; + } else page = alloc_pages_node(dest, GFP_HIGHUSER, 0); @@ -585,7 +599,7 @@ redo: err = -ENOMEM; goto out; } - list_add(&page->lru, &newlist); + list_add_tail(&page->lru, &newlist); nr_pages++; if (nr_pages > MIGRATE_CHUNK_SIZE) break; diff --git a/mm/vmscan.c b/mm/vmscan.c index 1838c15ca4fd..b0af7593d01e 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1908,7 +1908,12 @@ int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) sc.swap_cluster_max = SWAP_CLUSTER_MAX; cond_resched(); - p->flags |= PF_MEMALLOC; + /* + * We need to be able to allocate from the reserves for RECLAIM_SWAP + * and we also need to be able to write out pages for RECLAIM_WRITE + * and RECLAIM_SWAP. + */ + p->flags |= PF_MEMALLOC | PF_SWAPWRITE; reclaim_state.reclaimed_slab = 0; p->reclaim_state = &reclaim_state; @@ -1932,11 +1937,10 @@ int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order) * a long time. */ shrink_slab(sc.nr_scanned, gfp_mask, order); - sc.nr_reclaimed = 1; /* Avoid getting the off node timeout */ } p->reclaim_state = NULL; - current->flags &= ~PF_MEMALLOC; + current->flags &= ~(PF_MEMALLOC | PF_SWAPWRITE); if (sc.nr_reclaimed == 0) zone->last_unsuccessful_zone_reclaim = jiffies; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index efa3e72cfcfa..f999edd846a9 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -494,6 +494,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) struct net_device *dev; struct sk_buff *frag; struct rt6_info *rt = (struct rt6_info*)skb->dst; + struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; struct ipv6hdr *tmp_hdr; struct frag_hdr *fh; unsigned int mtu, hlen, left, len; @@ -505,7 +506,12 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) hlen = ip6_find_1stfragopt(skb, &prevhdr); nexthdr = *prevhdr; - mtu = dst_mtu(&rt->u.dst) - hlen - sizeof(struct frag_hdr); + mtu = dst_mtu(&rt->u.dst); + if (np && np->frag_size < mtu) { + if (np->frag_size) + mtu = np->frag_size; + } + mtu -= hlen + sizeof(struct frag_hdr); if (skb_shinfo(skb)->frag_list) { int first_len = skb_pagelen(skb); @@ -882,7 +888,12 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, inet->cork.fl = *fl; np->cork.hop_limit = hlimit; np->cork.tclass = tclass; - inet->cork.fragsize = mtu = dst_mtu(rt->u.dst.path); + mtu = dst_mtu(rt->u.dst.path); + if (np && np->frag_size < mtu) { + if (np->frag_size) + mtu = np->frag_size; + } + inet->cork.fragsize = mtu; if (dst_allfrag(rt->u.dst.path)) inet->cork.flags |= IPCORK_ALLFRAG; inet->cork.length = 0; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index faea8a120ee2..48597538db3f 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -884,6 +884,7 @@ ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p) t->parms.encap_limit = p->encap_limit; t->parms.flowinfo = p->flowinfo; t->parms.link = p->link; + ip6_tnl_dst_reset(t); ip6ip6_tnl_link_config(t); return 0; } diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c index 31f1f2e25aa0..0345ae647681 100644 --- a/sound/drivers/opl3/opl3_oss.c +++ b/sound/drivers/opl3/opl3_oss.c @@ -146,7 +146,7 @@ void snd_opl3_init_seq_oss(struct snd_opl3 *opl3, char *name) void snd_opl3_free_seq_oss(struct snd_opl3 *opl3) { if (opl3->oss_seq_dev) { - snd_device_free(opl3->card, opl3->oss_seq_dev); + /* The instance should have been released in prior */ opl3->oss_seq_dev = NULL; } } diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index 4fa431040564..99a42138bea0 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -414,7 +414,7 @@ static int __devinit snd_card_cs423x_pnpc(int dev, struct snd_card_cs4236 *acard } /* MPU initialization */ if (acard->mpu && mpu_port[dev] > 0) { - if (snd_cs423x_pnp_init_mpu(dev, acard->ctrl, cfg) < 0) + if (snd_cs423x_pnp_init_mpu(dev, acard->mpu, cfg) < 0) goto error; } kfree(cfg); |