From 45b31a0a645d190c8b984bff33db3793a8370750 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:16:19 -0500 Subject: [PATCH] Import 2.1.116pre2 --- README | 2 +- arch/alpha/kernel/core_mcpcia.c | 1 + arch/alpha/kernel/machvec.h | 1 + arch/alpha/mm/fault.c | 1 - arch/i386/kernel/entry.S | 25 +++---- arch/i386/kernel/io_apic.c | 2 +- arch/i386/kernel/ldt.c | 28 ++------ arch/i386/kernel/process.c | 21 ------ arch/i386/kernel/setup.c | 21 ------ arch/i386/kernel/signal.c | 38 ++++++----- arch/i386/kernel/smp.c | 5 ++ arch/i386/kernel/traps.c | 25 ++++--- arch/i386/lib/Makefile | 2 +- arch/i386/lib/lock.S | 33 ++++++++++ arch/i386/lib/lock_check.c | 62 ++++++++++++++++++ arch/i386/lib/usercopy.c | 9 +++ arch/i386/mm/init.c | 6 +- arch/m68k/config.in | 22 ++++--- arch/m68k/defconfig | 2 +- arch/m68k/fpsp040/skeleton.S | 10 ++- arch/m68k/kernel/entry.S | 4 ++ arch/m68k/kernel/m68k_defs.h | 6 +- arch/m68k/kernel/m68k_ksyms.c | 1 - arch/m68k/kernel/sys_m68k.c | 7 +- arch/m68k/mac/adb-bus.c | 114 ++++++++++++++++++++++++++++++++ arch/m68k/mac/config.c | 89 ++++++++++++++++++++----- arch/m68k/mac/macints.c | 69 +++++++++++++++++--- arch/m68k/mac/mackeyb.c | 45 ++++++------- arch/m68k/mac/via6522.c | 26 ++++++++ arch/m68k/mm/memory.c | 141 +++++++++++++++------------------------- drivers/block/Config.in | 1 - drivers/block/ide-probe.c | 4 +- drivers/char/cyclades.c | 19 +++--- drivers/net/3c505.h | 2 +- drivers/net/de4x5.c | 6 +- fs/binfmt_aout.c | 2 +- fs/binfmt_elf.c | 4 +- fs/dcache.c | 69 +++++++++++++++++--- fs/exec.c | 6 +- fs/ext2/namei.c | 30 ++++++--- fs/proc/array.c | 2 +- fs/proc/root.c | 74 +++++++++++++-------- fs/read_write.c | 2 +- fs/smbfs/proc.c | 4 +- fs/vfat/namei.c | 4 +- include/asm-i386/bugs.h | 5 +- include/asm-i386/current.h | 2 + include/asm-i386/pgtable.h | 7 +- include/asm-i386/processor.h | 21 ++++++ include/asm-i386/semaphore.h | 8 +++ include/asm-i386/smplock.h | 13 +++- include/asm-i386/spinlock.h | 13 +++- include/asm-i386/system.h | 42 +++++++++--- include/asm-i386/uaccess.h | 16 +++++ include/asm-m68k/bitops.h | 17 ----- include/asm-m68k/bootinfo.h | 23 ------- include/asm-m68k/keyboard.h | 2 +- include/asm-m68k/machw.h | 33 +++++++++- include/asm-m68k/pgtable.h | 3 + include/asm-m68k/posix_types.h | 4 ++ include/asm-m68k/softirq.h | 1 + include/asm-m68k/uaccess.h | 11 +++- include/asm-m68k/unistd.h | 7 +- include/linux/cyclades.h | 4 +- include/linux/dcache.h | 8 +++ include/linux/sched.h | 28 +++++--- include/linux/sunrpc/clnt.h | 3 + ipc/msg.c | 19 ++++-- kernel/capability.c | 124 ++++++++++++++--------------------- kernel/exit.c | 6 +- kernel/fork.c | 120 +++++++++++++++++++--------------- kernel/kmod.c | 4 +- kernel/sched.c | 2 + kernel/sys.c | 18 +++-- mm/page_alloc.c | 1 + net/core/dev.c | 6 +- net/sunrpc/auth_unix.c | 5 ++ net/sunrpc/sched.c | 16 +++++ net/sunrpc/xprt.c | 33 ++++++---- 79 files changed, 1089 insertions(+), 583 deletions(-) create mode 100644 arch/i386/lib/lock.S create mode 100644 arch/i386/lib/lock_check.c diff --git a/README b/README index 0545620a8..108ebb7d9 100644 --- a/README +++ b/README @@ -240,7 +240,7 @@ IF SOMETHING GOES WRONG: the file MAINTAINERS to see if there is a particular person associated with the part of the kernel that you are having trouble with. If there isn't anyone listed there, then the second best thing is to mail - them to me (Linus.Torvalds@Helsinki.FI), and possibly to any other + them to me (torvalds@transmeta.com), and possibly to any other relevant mailing-list or to the newsgroup. The mailing-lists are useful especially for SCSI and NETworking problems, as I can't test either of those personally anyway. diff --git a/arch/alpha/kernel/core_mcpcia.c b/arch/alpha/kernel/core_mcpcia.c index b1948610b..0e101eba8 100644 --- a/arch/alpha/kernel/core_mcpcia.c +++ b/arch/alpha/kernel/core_mcpcia.c @@ -6,6 +6,7 @@ * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com). * */ +#include #include #include #include diff --git a/arch/alpha/kernel/machvec.h b/arch/alpha/kernel/machvec.h index 5aa2ead60..6ac7cc6a0 100644 --- a/arch/alpha/kernel/machvec.h +++ b/arch/alpha/kernel/machvec.h @@ -6,6 +6,7 @@ * This file has goodies to help simplify instantiation of machine vectors. */ +#include /* Whee. TSUNAMI doesn't have an HAE. Fix things up for the GENERIC kernel by defining the HAE address to be that of the cache. Now diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c index f2d5cc763..f3a923064 100644 --- a/arch/alpha/mm/fault.c +++ b/arch/alpha/mm/fault.c @@ -13,7 +13,6 @@ #include #undef __EXTERN_INLINE -#include #include #include #include diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index b67cd20d6..469ad752f 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -106,19 +106,22 @@ ENOSYS = 38 1: popl %ds; \ 2: popl %es; \ 3: addl $4,%esp; \ - iret; \ +4: iret; \ .section fixup,"ax"; \ -4: pushl $0; \ +5: pushl $0; \ popl %ds; \ jmp 2b; \ -5: pushl $0; \ +6: pushl $0; \ popl %es; \ jmp 3b; \ +7: pushl $11; \ + call do_exit; \ .previous; \ .section __ex_table,"a";\ .align 4; \ - .long 1b,4b; \ - .long 2b,5b; \ + .long 1b,5b; \ + .long 2b,6b; \ + .long 4b,7b; \ .previous #define GET_CURRENT(reg) \ @@ -150,6 +153,7 @@ ENTRY(lcall7) .globl ret_from_smpfork ret_from_smpfork: GET_CURRENT(%ebx) +call __putlock btrl $0, SYMBOL_NAME(scheduler_lock) jmp ret_from_sys_call #endif /* __SMP__ */ @@ -255,19 +259,8 @@ error_code: decl %eax # eax = -1 pushl %ecx pushl %ebx -#if 1 - xorl %ecx,%ecx # zero ecx - cld - mov %es,%cx # get the lower order bits of es -#else cld -# Some older processors leave the top 16 bits of the 32 bit destination -# register undefined, rather than zeroed in the following instruction. -# This won't matter when restoring or loading a segment register from the -# stack. It may be a problem if any code reads the full 32 bit value. -# dosemu? kernel? Would somebody like to verify that this way is really OK? movl %es,%cx -#endif xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. ) movl %esp,%edx xchgl %ecx, ES(%esp) # get the address and save es. diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 90e1d4eb9..4e1c6b563 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -1177,7 +1177,7 @@ void __init setup_IO_APIC(void) pirqs_enabled) { printk("ENABLING IO-APIC IRQs\n"); - io_apic_irqs = ~((1<<2)|(1<<13)); + io_apic_irqs = ~((1<<2)|(1<<9)|(1<<13)); } else { if (ioapic_blacklisted()) printk(" blacklisted board, DISABLING IO-APIC IRQs\n"); diff --git a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c index 2a2edffdd..40a700d0e 100644 --- a/arch/i386/kernel/ldt.c +++ b/arch/i386/kernel/ldt.c @@ -36,9 +36,7 @@ static int read_ldt(void * ptr, unsigned long bytecount) static int write_ldt(void * ptr, unsigned long bytecount, int oldmode) { struct mm_struct * mm = current->mm; - void * ldt; __u32 entry_1, entry_2, *lp; - __u16 selector, reg_fs, reg_gs; int error; struct modify_ldt_ldt_s ldt_info; @@ -70,8 +68,8 @@ static int write_ldt(void * ptr, unsigned long bytecount, int oldmode) * For no good reason except historical, the GDT index of the LDT * is chosen to follow the index number in the task[] array. */ - ldt = mm->segments; - if (!ldt) { + if (!mm->segments) { + void * ldt; error = -ENOMEM; ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); if (!ldt) @@ -85,7 +83,7 @@ static int write_ldt(void * ptr, unsigned long bytecount, int oldmode) mm->segments = ldt; set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, ldt, LDT_ENTRIES); load_ldt(i); - if (mm->count > 1) + if (atomic_read(&mm->count) > 1) printk(KERN_WARNING "LDT allocated for cloned task!\n"); } else { @@ -93,19 +91,7 @@ static int write_ldt(void * ptr, unsigned long bytecount, int oldmode) } } - /* - * Check whether the entry to be changed is currently in use. - * If it is, we may need extra validation checks in case the - * kernel is forced to save and restore the selector. - * - * Note: we check the fs and gs values as well, as these are - * loaded by the signal code and during a task switch. - */ - selector = (ldt_info.entry_number << 3) | 4; - __asm__("movw %%fs,%0" : "=r"(reg_fs)); - __asm__("movw %%gs,%0" : "=r"(reg_gs)); - - lp = (__u32 *) ((selector & ~7) + (char *) ldt); + lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->segments); /* Allow LDTs to be cleared by the user. */ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { @@ -118,7 +104,7 @@ static int write_ldt(void * ptr, unsigned long bytecount, int oldmode) ldt_info.useable == 0 )) { entry_1 = 0; entry_2 = 0; - goto out_check; + goto install; } } @@ -136,8 +122,8 @@ static int write_ldt(void * ptr, unsigned long bytecount, int oldmode) if (!oldmode) entry_2 |= (ldt_info.useable << 20); -out_check: - /* OK to change the entry ... */ + /* Install the new entry ... */ +install: *lp = entry_1; *(lp+1) = entry_2; error = 0; diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 657bb5f65..3bcd0f9bc 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -582,27 +582,6 @@ void copy_segments(int nr, struct task_struct *p, struct mm_struct *new_mm) #define savesegment(seg,value) \ asm volatile("movl %%" #seg ",%0":"=m" (*(int *)&(value))) -/* - * Load a segment. Fall back on loading the zero - * segment if something goes wrong.. - */ -#define loadsegment(seg,value) \ - asm volatile("\n" \ - "1:\t" \ - "movl %0,%%" #seg "\n" \ - "2:\n" \ - ".section fixup,\"ax\"\n" \ - "3:\t" \ - "pushl $0\n\t" \ - "popl %%" #seg "\n\t" \ - "jmp 2b\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n\t" \ - ".align 4\n\t" \ - ".long 1b,3b\n" \ - ".previous" \ - : :"m" (*(unsigned int *)&(value))) - int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, struct task_struct * p, struct pt_regs * regs) { diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 84eaf4962..b2bb69243 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -255,27 +255,6 @@ __initfunc(static int amd_model(struct cpuinfo_x86 *c)) } /* - * Cyrix CPU configuration register indexes - */ -#define CX86_CCR2 0xc2 -#define CX86_CCR3 0xc3 -#define CX86_CCR4 0xe8 -#define CX86_CCR5 0xe9 -#define CX86_DIR0 0xfe -#define CX86_DIR1 0xff - -/* - * Cyrix CPU indexed register access macros - */ - -#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); }) - -#define setCx86(reg, data) do { \ - outb((reg), 0x22); \ - outb((data), 0x23); \ -} while (0) - -/* * Use the Cyrix DEVID CPU registers if avail. to get more detailed info. */ __initfunc(static void do_cyrix_devid(struct cpuinfo_x86 *c)) diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index 08462e328..05e53287a 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -178,12 +178,13 @@ static inline int restore_i387(struct _fpstate *buf) static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *peax) { - unsigned int tmp, err = 0; + unsigned int err = 0; #define COPY(x) err |= __get_user(regs->x, &sc->x) #define COPY_SEG(seg) \ - { err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp; \ + err |= __get_user(tmp, &sc->seg); \ if ((tmp & 0xfffc) /* not a NULL selectors */ \ && (tmp & 0x4) != 0x4 /* not a LDT selector */ \ && (tmp & 3) != 3) /* not a RPL3 GDT selector */ \ @@ -191,17 +192,19 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *peax) regs->x##seg = tmp; } #define COPY_SEG_STRICT(seg) \ - { err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp; \ + err |= __get_user(tmp, &sc->seg); \ if ((tmp & 0xfffc) && (tmp & 3) != 3) goto badframe; \ regs->x##seg = tmp; } #define GET_SEG(seg) \ - { err |= __get_user(tmp, &sc->seg); \ + { unsigned short tmp; \ + err |= __get_user(tmp, &sc->seg); \ if ((tmp & 0xfffc) /* not a NULL selectors */ \ && (tmp & 0x4) != 0x4 /* not a LDT selector */ \ && (tmp & 3) != 3) /* not a RPL3 GDT selector */ \ goto badframe; \ - __asm__ __volatile__("movl %w0,%%" #seg : : "r"(tmp)); } + loadsegment(seg,tmp); } GET_SEG(gs); GET_SEG(fs); @@ -218,16 +221,21 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *peax) COPY_SEG_STRICT(cs); COPY_SEG_STRICT(ss); - err |= __get_user(tmp, &sc->eflags); - regs->eflags = (regs->eflags & ~0x40DD5) | (tmp & 0x40DD5); - regs->orig_eax = -1; /* disable syscall checks */ - - err |= __get_user(tmp, (unsigned long *)&sc->fpstate); - if (tmp) { - struct _fpstate * buf = (struct _fpstate *) tmp; - if (verify_area(VERIFY_READ, buf, sizeof(*buf))) - goto badframe; - err |= restore_i387(buf); + { + unsigned int tmpflags; + err |= __get_user(tmpflags, &sc->eflags); + regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); + regs->orig_eax = -1; /* disable syscall checks */ + } + + { + struct _fpstate * buf; + err |= __get_user(buf, &sc->fpstate); + if (buf) { + if (verify_area(VERIFY_READ, buf, sizeof(*buf))) + goto badframe; + err |= restore_i387(buf); + } } err |= __get_user(*peax, &sc->eax); diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 4729db876..d230574ed 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -658,6 +658,7 @@ __initfunc(unsigned long init_smp_mappings(unsigned long memory_start)) { unsigned long apic_phys, ioapic_phys; + memory_start = PAGE_ALIGN(memory_start); if (smp_found_config) { apic_phys = mp_lapic_addr; ioapic_phys = mp_ioapic_addr; @@ -749,7 +750,11 @@ __initfunc(void initialize_secondary(void)) /* * We don't actually need to load the full TSS, * basically just the stack pointer and the eip. + * + * Get the scheduler lock, because we're going + * to release it as part of the "reschedule" return. */ + spin_lock(&scheduler_lock); asm volatile("lldt %%ax": :"a" (p->ldt)); asm volatile("ltr %%ax": :"a" (p->tr)); asm volatile( diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 50ff9ba32..1f632e570 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -42,12 +42,10 @@ static inline void console_verbose(void) #define DO_ERROR(trapnr, signr, str, name, tsk) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ - lock_kernel(); \ tsk->tss.error_code = error_code; \ tsk->tss.trap_no = trapnr; \ force_sig(signr, tsk); \ - die_if_kernel(str,regs,error_code); \ - unlock_kernel(); \ + die_if_no_fixup(str,regs,error_code); \ } #define DO_VM86_ERROR(trapnr, signr, str, name, tsk) \ @@ -191,6 +189,20 @@ static void die_if_kernel(const char * str, struct pt_regs * regs, long err) die(str, regs, err); } +static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err) +{ + if (!(regs->eflags & VM_MASK) && !(3 & regs->xcs)) + { + unsigned long fixup; + fixup = search_exception_table(regs->eip); + if (fixup) { + regs->eip = fixup; + return; + } + die(str, regs, err); + } +} + DO_VM86_ERROR( 0, SIGFPE, "divide error", divide_error, current) DO_VM86_ERROR( 3, SIGTRAP, "int3", int3, current) DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow, current) @@ -228,10 +240,9 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) if (!(regs->xcs & 3)) goto gp_in_kernel; - lock_kernel(); current->tss.error_code = error_code; current->tss.trap_no = 13; - force_sig(SIGSEGV, current); + force_sig(SIGSEGV, current); return; gp_in_vm86: @@ -453,9 +464,7 @@ __initfunc(void trap_init_f00f_bug(void)) /* * Allocate a new page in virtual address space, - * and move the IDT to have entry #7 starting at - * the beginning of the page. We'll force a page - * fault for IDT entries #0-#6.. + * move the IDT into it and write protect this page. */ page = (unsigned long) vmalloc(PAGE_SIZE); memcpy((void *) page, idt_table, 256*8); diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index 6490984b1..53996c0c8 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -6,6 +6,6 @@ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o L_TARGET = lib.a -L_OBJS = checksum.o semaphore.o delay.o usercopy.o getuser.o putuser.o +L_OBJS = checksum.o semaphore.o delay.o usercopy.o getuser.o putuser.o lock.o lock_check.o include $(TOPDIR)/Rules.make diff --git a/arch/i386/lib/lock.S b/arch/i386/lib/lock.S new file mode 100644 index 000000000..c500c05f8 --- /dev/null +++ b/arch/i386/lib/lock.S @@ -0,0 +1,33 @@ +.globl __getlock +__getlock: + pushl %eax + + movl $-8192,%eax + andl %esp,%eax + movl 36(%eax),%eax + incl spinlocks(,%eax,4) + + popl %eax + ret + +.globl __putlock +__putlock: + pushl %eax + + movl $-8192,%eax + andl %esp,%eax + movl 36(%eax),%eax + decl spinlocks(,%eax,4) + js __bad_put + + popl %eax + ret + +__bad_put: + pushl %edx + pushl %ecx + call __putlock_negative + popl %ecx + popl %edx + popl %eax + ret diff --git a/arch/i386/lib/lock_check.c b/arch/i386/lib/lock_check.c new file mode 100644 index 000000000..e95ca6145 --- /dev/null +++ b/arch/i386/lib/lock_check.c @@ -0,0 +1,62 @@ +#include +#include + +unsigned int spinlocks[32]; + +static void show_stack(unsigned int *stack) +{ + int i; + + for (i = 0; i < 40; i++) { + extern int get_options, __start_fixup; + unsigned int p = stack[i]; + if (p >= (unsigned int) &get_options && p < (unsigned int)&__start_fixup) + printk("[<%08x>] ", p); + } +} + +void __putlock_negative( + unsigned int ecx, + unsigned int edx, + unsigned int eax, + unsigned int from_where) +{ + static int count = 0; + + spinlocks[current->processor] = 0; + + if (count < 5) { + count++; + printk("negative putlock from %x\n", from_where); + show_stack(&ecx); + } +} + +void __check_locks(unsigned int type) +{ + static int warned = 0; + + if (warned < 5) { + unsigned int from_where = (&type)[-1]; + unsigned int this_cpu = current->processor; + int bad_irq = 0; + + if (type) { + unsigned long flags; + __save_flags(flags); + if (!(flags & 0x200) || (global_irq_holder == this_cpu)) + bad_irq = 1; + } + + if (spinlocks[this_cpu] || + local_irq_count[this_cpu] || + local_bh_count[this_cpu] || + bad_irq) { + warned++; + printk("scheduling with spinlocks=%d at %x\n", spinlocks[this_cpu], from_where); + show_stack(&type); + } + } +} + + diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c index 6b313d99c..8901882db 100644 --- a/arch/i386/lib/usercopy.c +++ b/arch/i386/lib/usercopy.c @@ -10,6 +10,8 @@ inline unsigned long __generic_copy_to_user(void *to, const void *from, unsigned long n) { + if ((unsigned long) to < TASK_SIZE) + __check_locks(1); if (access_ok(VERIFY_WRITE, to, n)) __copy_user(to,from,n); return n; @@ -18,6 +20,8 @@ __generic_copy_to_user(void *to, const void *from, unsigned long n) inline unsigned long __generic_copy_from_user(void *to, const void *from, unsigned long n) { + if ((unsigned long) from < TASK_SIZE) + __check_locks(1); if (access_ok(VERIFY_READ, from, n)) __copy_user(to,from,n); return n; @@ -56,6 +60,7 @@ long __strncpy_from_user(char *dst, const char *src, long count) { long res; + __check_locks(1); __do_strncpy_from_user(dst, src, count, res); return res; } @@ -64,6 +69,7 @@ long strncpy_from_user(char *dst, const char *src, long count) { long res = -EFAULT; + __check_locks(1); if (access_ok(VERIFY_READ, src, 1)) __do_strncpy_from_user(dst, src, count, res); return res; @@ -96,6 +102,7 @@ strncpy_from_user(char *dst, const char *src, long count) unsigned long clear_user(void *to, unsigned long n) { + __check_locks(1); if (access_ok(VERIFY_WRITE, to, n)) __do_clear_user(to, n); return n; @@ -104,6 +111,7 @@ clear_user(void *to, unsigned long n) unsigned long __clear_user(void *to, unsigned long n) { + __check_locks(1); __do_clear_user(to, n); return n; } @@ -118,6 +126,7 @@ long strlen_user(const char *s) { unsigned long res; + __check_locks(1); __asm__ __volatile__( "0: repne; scasb\n" " notl %0\n" diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 7ee11e1f7..b4cba8730 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -210,15 +210,15 @@ static inline void set_in_cr4(unsigned long mask) /* * allocate page table(s) for compile-time fixed mappings */ -static unsigned long fixmap_init (unsigned long start_mem) +static unsigned long __init fixmap_init(unsigned long start_mem) { pgd_t * pg_dir; unsigned int idx; unsigned long address; - start_mem &= PAGE_MASK; + start_mem = PAGE_ALIGN(start_mem); - for (idx=1; idx < __end_of_fixed_addresses; idx += PTRS_PER_PTE) + for (idx=1; idx <= __end_of_fixed_addresses; idx += PTRS_PER_PTE) { address = fix_to_virt(__end_of_fixed_addresses-idx); pg_dir = swapper_pg_dir + (address >> PGDIR_SHIFT); diff --git a/arch/m68k/config.in b/arch/m68k/config.in index f2ab0f061..33164f7bc 100644 --- a/arch/m68k/config.in +++ b/arch/m68k/config.in @@ -235,11 +235,23 @@ if [ "$CONFIG_ATARI" = "y" ]; then tristate 'PAMsNet support' CONFIG_ATARI_PAMSNET fi fi +fi endmenu fi + +source fs/Config.in + +if [ "$CONFIG_VME" = "n" ]; then + define_bool CONFIG_FB y + mainmenu_option next_comment + comment 'Console drivers' + source drivers/video/Config.in + endmenu fi +source fs/nls/Config.in + mainmenu_option next_comment comment 'Character devices' @@ -254,7 +266,7 @@ if [ "$CONFIG_ATARI" = "y" ]; then define_bool CONFIG_NVRAM y fi -tristate 'Parallel printer support' CONFIG_PRINTER +tristate 'Parallel printer support' CONFIG_M68K_PRINTER if [ "$CONFIG_ZORRO" = "y" ]; then dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_PRINTER fi @@ -334,14 +346,6 @@ if [ "$CONFIG_ATARI" = "y" ]; then fi endmenu -source fs/Config.in - -if [ "$CONFIG_VME" = "n" ]; then - define_bool CONFIG_FB y - source drivers/video/Config.in -fi - -source fs/nls/Config.in mainmenu_option next_comment comment 'Sound support' diff --git a/arch/m68k/defconfig b/arch/m68k/defconfig index 071884d45..e866b5dd3 100644 --- a/arch/m68k/defconfig +++ b/arch/m68k/defconfig @@ -196,7 +196,7 @@ CONFIG_NLS_CODEPAGE_437=y # CONFIG_VT=y CONFIG_VT_CONSOLE=y -# CONFIG_PRINTER is not set +# CONFIG_M68K_PRINTER is not set CONFIG_AMIGAMOUSE=y CONFIG_ATARIMOUSE=y CONFIG_AMIGA_BUILTIN_SERIAL=y diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S index 719bcc9ce..1e4d0cf72 100644 --- a/arch/m68k/fpsp040/skeleton.S +++ b/arch/m68k/fpsp040/skeleton.S @@ -378,14 +378,12 @@ fpsp_done: beq Lnotkern rte Lnotkern: - tstl SYMBOL_NAME(need_resched) - bne Lmustsched - rte -Lmustsched: SAVE_ALL_INT GET_CURRENT(%d0) - bral SYMBOL_NAME(ret_from_exception) | deliver signals, reschedule etc.. - + tstl %curptr@(LTASK_NEEDRESCHED) + jne SYMBOL_NAME(ret_from_exception) | deliver signals, + | reschedule etc.. + RESTORE_ALL | | mem_write --- write to user or supervisor address space diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 620ca32f1..eba9842cf 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -583,6 +583,10 @@ SYMBOL_NAME_LABEL(sys_call_table) .long SYMBOL_NAME(sys_capget) .long SYMBOL_NAME(sys_capset) /* 185 */ .long SYMBOL_NAME(sys_sigaltstack) + .long SYMBOL_NAME(sys_sendfile) + .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ + .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ + .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4 .long SYMBOL_NAME(sys_ni_syscall) .endr diff --git a/arch/m68k/kernel/m68k_defs.h b/arch/m68k/kernel/m68k_defs.h index 905b71332..992d390c7 100644 --- a/arch/m68k/kernel/m68k_defs.h +++ b/arch/m68k/kernel/m68k_defs.h @@ -3,6 +3,6 @@ */ #define TS_MAGICKEY 0x5a5a5a5a -#define TS_TSS 462 -#define TS_ESP0 482 -#define TS_FPU 486 +#define TS_TSS 478 +#define TS_ESP0 498 +#define TS_FPU 502 diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c index 9d66a4223..ee73b3ff2 100644 --- a/arch/m68k/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index f3b902a82..75da52541 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -66,12 +66,11 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg) struct file * file = NULL; struct mmap_arg_struct a; - down(¤t->mm->mmap_sem); - lock_kernel(); - error = -EFAULT; if (copy_from_user(&a, arg, sizeof(a))) - goto out; + return -EFAULT; + down(¤t->mm->mmap_sem); + lock_kernel(); if (!(a.flags & MAP_ANONYMOUS)) { error = -EBADF; file = fget(a.fd); diff --git a/arch/m68k/mac/adb-bus.c b/arch/m68k/mac/adb-bus.c index d60815ae7..0f41bc6aa 100644 --- a/arch/m68k/mac/adb-bus.c +++ b/arch/m68k/mac/adb-bus.c @@ -107,6 +107,7 @@ extern void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs); static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs); static void adb_hw_setup_IIsi(void); +static void adb_hw_setup_cuda(void); /* * debug level 10 required for ADB logging (should be && debug_adb, ideally) @@ -206,10 +207,14 @@ void adb_bus_init(void) */ case MAC_ADB_CUDA: printk("adb: CUDA interface.\n"); +#if 0 /* don't know what to set up here ... */ adb_state = idle; /* Set the lines up. We want TREQ as input TACK|TIP as output */ via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ)); +#endif + adb_hw_setup_cuda(); + adb_state = idle; request_irq(IRQ_MAC_ADB, adb_cuda_interrupt, IRQ_FLG_LOCK, "adb CUDA interrupt", adb_cuda_interrupt); break; @@ -281,6 +286,115 @@ void adb_bus_init(void) restore_flags(flags); } +void adb_hw_setup_cuda(void) +{ + int x; + unsigned long flags; + + printk("CUDA: HW Setup:"); + + save_flags(flags); + cli(); + + if (console_loglevel == 10) + printk(" 1,"); + + /* Set the direction of the cuda signals, TIP+TACK are output TREQ is an input */ + via_write( via1, vDirB, via_read( via1, vDirB ) | TIP | TACK ); + via_write( via1, vDirB, via_read( via1, vDirB ) & ~TREQ ); + + if (console_loglevel == 10) + printk("2,"); + + /* Set the clock control. Set to shift data in by external clock CB1 */ + via_write( via1, vACR, ( via_read(via1, vACR ) | SR_EXT ) & ~SR_OUT ); + + if (console_loglevel == 10) + printk("3,"); + + /* Clear any possible Cuda interrupt */ + x = via_read( via1, vSR ); + + if (console_loglevel == 10) + printk("4,"); + + /* Terminate transaction and set idle state */ + via_write( via1, vBufB, via_read( via1, vBufB ) | TIP | TACK ); + + if (console_loglevel == 10) + printk("5,"); + + /* Delay 4 mS for ADB reset to complete */ + udelay(4000); + + if (console_loglevel == 10) + printk("6,"); + + /* Clear pending interrupts... */ + x = via_read( via1, vSR ); + + if (console_loglevel == 10) + printk("7,"); + /* Issue a sync transaction, TACK asserted while TIP negated */ + via_write( via1, vBufB, via_read( via1, vBufB ) & ~TACK ); + + if (console_loglevel == 10) + printk("8,"); + + /* Wait for the sync acknowledgement, Cuda to assert TREQ */ + while( ( via_read( via1, vBufB ) & TREQ ) != 0 ) + barrier(); + + if (console_loglevel == 10) + printk("9,"); + + /* Wait for the sync acknowledment interrupt */ + while( ( via_read( via1, vIFR ) & SR_INT ) == 0 ) + barrier(); + + if (console_loglevel == 10) + printk("10,"); + + /* Clear pending interrupts... */ + x = via_read( via1, vSR ); + + if (console_loglevel == 10) + printk("11,"); + + /* Terminate the sync cycle by negating TACK */ + via_write( via1, vBufB, via_read( via1, vBufB ) | TACK ); + + if (console_loglevel == 10) + printk("12,"); + + /* Wait for the sync termination acknowledgement, Cuda to negate TREQ */ + while( ( via_read( via1, vBufB ) & TREQ ) == 0 ) + barrier(); + + if (console_loglevel == 10) + printk("13,"); + + /* Wait for the sync termination acknowledment interrupt */ + while( ( via_read( via1, vIFR ) & SR_INT ) == 0 ) + barrier(); + + if (console_loglevel == 10) + printk("14,"); + + /* Terminate transaction and set idle state, TIP+TACK negate */ + via_write( via1, vBufB, via_read( via1, vBufB ) | TIP ); + + if (console_loglevel == 10) + printk("15 !"); + + /* Clear pending interrupts... */ + x = via_read( via1, vSR ); + + restore_flags(flags); + + printk("\nCUDA: HW Setup done!\n"); +} + void adb_hw_setup_IIsi(void) { int dummy; diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index 6fd4a2d48..fe77ded05 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -35,6 +35,7 @@ #include #include +#include #include "via6522.h" @@ -60,24 +61,43 @@ extern unsigned long mac_videobase; /* The phys. video addr. - might be bogus on some machines */ unsigned long mac_orig_videoaddr; +/* Mac specific keyboard functions */ extern int mac_keyb_init(void); extern int mac_kbdrate(struct kbd_repeat *k); extern void mac_kbd_leds(unsigned int leds); extern void mac_kbd_reset_setup(char*, int); +/* Mac specific irq functions */ +extern void mac_init_IRQ (void); +extern void (*mac_handlers[]) (int, void *, struct pt_regs *); +extern int mac_request_irq (unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, + void *dev_id); +extern void mac_free_irq (unsigned int irq, void *dev_id); +extern void mac_enable_irq (unsigned int); +extern void mac_disable_irq (unsigned int); +static void mac_get_model(char *model); +/*static int mac_get_hardware_list(char *buffer);*/ +extern int mac_get_irq_list (char *); + +/* Mac specific timer functions */ +extern unsigned long mac_gettimeoffset (void); +extern void mac_gettod (int *, int *, int *, int *, int *, int *); +extern int mac_hwclk (int, struct hwclk_time *); +extern int mac_set_clock_mmss (unsigned long); +extern void via_init_clock(void (*func)(int, void *, struct pt_regs *)); + extern void (*kd_mksound)(unsigned int, unsigned int); extern void mac_mksound(unsigned int, unsigned int); extern int mac_floppy_init(void); extern void mac_floppy_setup(char *,int *); -extern void mac_gettod (int *, int *, int *, int *, int *, int *); - extern void nubus_sweep_video(void); -extern void via_init_clock(void (*func)(int, void *, struct pt_regs *)); -extern void mac_debugging_long(int, long); /* Mac specific debug functions (in debug.c) */ extern void mac_debug_init(void); +extern void mac_debugging_long(int, long); #ifdef CONFIG_MAGIC_SYSRQ @@ -108,17 +128,11 @@ void mac_sched_init(void (*vector)(int, void *, struct pt_regs *)) via_init_clock(vector); } -unsigned long mac_gettimeoffset (void) -{ - return 0L; -} - extern int console_loglevel; /* * This function translates the boot timeval into a proper date, to initialize * the system time. - * Known problem: off by one after Feb. 27 on leap years */ void mac_gettod (int *yearp, int *monp, int *dayp, @@ -174,6 +188,26 @@ void mac_gettod (int *yearp, int *monp, int *dayp, return; } +/* + * TBI: read and write hwclock + */ + +int mac_hwclk( int op, struct hwclk_time *t ) +{ + return 0; +} + +/* + * TBI: set minutes/seconds in hwclock + */ + +int mac_set_clock_mmss (unsigned long nowtime) +{ + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + + return 0; +} + void mac_waitbut (void) { ; @@ -272,6 +306,8 @@ __initfunc(void config_mac(void)) mach_get_irq_list = mac_get_irq_list; mach_gettimeoffset = mac_gettimeoffset; mach_gettod = mac_gettod; + mach_hwclk = mac_hwclk; + mach_set_clock_mmss = mac_set_clock_mmss; #if 0 mach_mksound = mac_mksound; #endif @@ -379,7 +415,7 @@ static struct mac_model mac_data_table[]= * 0xF9000000, via is like a MacII. We label it differently as some of the * stuff connected to VIA2 seems different. Better SCSI chip and ???? onboard ethernet * in all cases using a NatSemi SONIC. The 700, 900 and 950 have some I/O chips in the wrong - * place to confuse us. The 840 seems to have a scsi location of its own + * place to confuse us. The 840AV seems to have a scsi location of its own */ { MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, @@ -389,9 +425,9 @@ static struct mac_model mac_data_table[]= /* The Q700 does have a NS Sonic */ { MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_SONIC, MAC_NUBUS}, - /* Does the 840 have ethernet ??? documents seem to indicate its not quite a + /* Does the 840AV have ethernet ??? documents seem to indicate its not quite a Quadra in this respect ? */ - { MAC_MODEL_Q840, "Quadra 840", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II, MAC_ETHER_NONE, MAC_NUBUS}, /* These might have IOP problems */ { MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS}, { MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_IOP, MAC_ETHER_SONIC, MAC_NUBUS}, @@ -418,7 +454,7 @@ static struct mac_model mac_data_table[]= { MAC_MODEL_C610, "Centris 610", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, { MAC_MODEL_C650, "Centris 650", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, - { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, + { MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA, MAC_ETHER_NONE, MAC_NUBUS}, /* * Power books - seem similar to early Quadras ? (most have 030 though) @@ -497,10 +533,10 @@ void mac_identify(void) * Report booter data: */ printk (" Penguin bootinfo data:\n"); - printk (" Video: addr 0x%lx row 0x%lx depth %lx dimensions %d x %d\n", + printk (" Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n", mac_bi_data.videoaddr, mac_bi_data.videorow, - mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF, - mac_bi_data.dimensions >> 16); + mac_bi_data.videodepth, (int) (mac_bi_data.dimensions & 0xFFFF), + (int) (mac_bi_data.dimensions >> 16)); printk (" Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n", mac_bi_data.videological, mac_orig_videoaddr, mac_bi_data.sccbase); @@ -522,6 +558,25 @@ void mac_identify(void) /* * TODO: set the various fields in macintosh_config->hw_present here! */ + switch (macintosh_config->scsi_type) { + case MAC_SCSI_OLD: + MACHW_SET(MAC_SCSI_80); + break; + case MAC_SCSI_QUADRA: + case MAC_SCSI_QUADRA2: + case MAC_SCSI_QUADRA3: + MACHW_SET(MAC_SCSI_96); + if ((macintosh_config->ident == MAC_MODEL_Q900) || + (macintosh_config->ident == MAC_MODEL_Q950)) + MACHW_SET(MAC_SCSI_96_2); + break; + default: + printk("config.c: wtf: unknown scsi, using 53c80\n"); + MACHW_SET(MAC_SCSI_80); + break; + + } + } diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c index 9ee60f0a4..d2ea26e05 100644 --- a/arch/m68k/mac/macints.c +++ b/arch/m68k/mac/macints.c @@ -189,6 +189,12 @@ static void oss_do_nubus(int irq, void *dev_id, struct pt_regs *regs); void psc_irq(int irq, void *dev_id, struct pt_regs *regs); /* + * PSC hooks + */ + +extern void psc_init(void); + +/* * console_loglevel determines NMI handler function */ @@ -241,8 +247,7 @@ void mac_init_IRQ(void) /* no real VIA2, the OSS seems _very_different */ via2_is_oss = 1; /* IIfx has OSS, at a different base address than RBV */ - if (macintosh_config->ident == MAC_MODEL_IIFX) - rbv_regp = (unsigned char *) OSS_BAS; + rbv_regp = (unsigned char *) OSS_BAS; sys_request_irq(2, oss_irq, IRQ_FLG_LOCK, "oss", oss_irq); } else { /* VIA2 is part of the RBV: different base, other offsets */ @@ -318,7 +323,7 @@ void mac_init_IRQ(void) param_table[0] = &via1_param[0]; mac_irqs[0] = &via1_irqs[0]; - if (via2_is_rbv) { + if (via2_is_rbv || via2_is_oss) { via_table[1] = rbv_regp; handler_table[1] = &rbv_handler[0]; param_table[1] = &rbv_param[0]; @@ -656,10 +661,28 @@ void mac_clear_pending_irq( unsigned int irq ) int mac_irq_pending( unsigned int irq ) { + int pending = 0; + volatile unsigned char *via; + int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1; int irqidx = (irq & IRQ_IDX_MASK); - return (irq_flags[srcidx].pending & (1<= SRC_VIA2) + pending |= via_read(via, (0x100 + 0x10*srcidx))&(1<pc, fp->sr, fp); #endif for (i=0; i<100; i++) udelay(1000); + + if (in_nmi == 1) { + nmi_hold = 1; + printk("... pausing, press NMI to resume ..."); + } else { + printk(" ok!\n"); + nmi_hold = 0; + } + + barrier(); + + while (nmi_hold == 1) + udelay(1000); + +#if 0 scsi_mac_polled(); +#endif if ( console_loglevel >= 8 ) { #if 0 @@ -804,6 +848,7 @@ void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp) /* printk("NMI "); */ #endif } + in_nmi--; } /* @@ -1511,8 +1556,10 @@ static void oss_do_nubus(int slot, void *via, struct pt_regs *regs) #endif /* IDE hack for Quadra: uses Nubus interrupt without any slot bit set */ +#ifdef CONFIG_BLK_DEV_MAC_IDE if (mac_ide_intr_hook) mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs); +#endif while(1) { @@ -1523,9 +1570,11 @@ static void oss_do_nubus(int slot, void *via, struct pt_regs *regs) printk("nubus_irq: map %x mask %x\n", map, nubus_active); #endif if( (map = (map&nubus_active)) ==0 ) { +#ifdef CONFIG_BLK_DEV_MAC_IDE if (!mac_ide_intr_hook) printk("nubus_irq: nothing pending, map %x mask %x\n", map, nubus_active); +#endif nubus_irqs[7]++; break; } diff --git a/arch/m68k/mac/mackeyb.c b/arch/m68k/mac/mackeyb.c index cf746a97d..5946a9e8b 100644 --- a/arch/m68k/mac/mackeyb.c +++ b/arch/m68k/mac/mackeyb.c @@ -642,11 +642,12 @@ __initfunc(int mac_keyb_init(void)) ct=0; while (!autopoll_req.got_reply && ++ct<1000) { - adb_poll(); udelay(10); } - if(ct==1000) + if(ct==1000) { printk("Keyboard timed out.\n"); + autopoll_req.got_reply = 1; + } } /* @@ -654,7 +655,7 @@ __initfunc(int mac_keyb_init(void)) * care of that for other Macs. */ - printk("Configuring keyboard\n"); + printk("Configuring keyboard:\n"); /* * turn on all leds - the keyboard driver will turn them back off @@ -668,17 +669,17 @@ __initfunc(int mac_keyb_init(void)) * The polling stuff should go away as soon as the ADB driver is stable */ ct = 0; - adb_poll(); while (!led_request.got_reply && ++ct<1000) { - adb_poll(); udelay(10); } - if(ct==1000) - printk("Keyboard timed out.\n"); + if(ct==1000) { + printk("keyboard timed out.\n"); + led_request.got_reply = 1; + } #if 1 - printk("Configuring coding mode ...\n"); + printk("configuring coding mode ...\n"); /* * get the keyboard to send separate codes for @@ -688,14 +689,14 @@ __initfunc(int mac_keyb_init(void)) ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3); ct=0; - adb_poll(); while (!confcod_req.got_reply && ++ct<1000) { - adb_poll(); udelay(10); } - if(ct==1000) - printk("Keyboard timed out.\n"); + if(ct==1000) { + printk("keyboard timed out.\n"); + confcod_req.got_reply = 1; + } #endif #if 0 /* seems to hurt, at least Geert's Mac */ @@ -710,10 +711,8 @@ __initfunc(int mac_keyb_init(void)) ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 ); ct=0; - adb_poll(); while (!mouse_req.got_reply && ++ct<1000) { - adb_poll(); udelay(10); } if(ct==1000) @@ -734,19 +733,8 @@ __initfunc(int mac_keyb_init(void)) ADB_READREG(ADB_KEYBOARD, KEYB_KEYREG)); #endif - /* - * fake 'request done' for the driver if requests timed out - */ - - autopoll_req.got_reply = 1; -#if 0 - /* XXX: results in race and hang with mac_kbd_leds and serial (why ?) */ - led_request.got_reply = 1; -#endif - confcod_req.got_reply = 1; - in_keybinit = 0; - printk("Keyboard init done\n"); + printk("keyboard init done\n"); return 0; } @@ -755,3 +743,8 @@ __initfunc(int mac_keyb_init(void)) __initfunc(void mac_kbd_reset_setup(char *str, int *ints)) { } + +/* for "kbd-reset" cmdline param */ +__initfunc(void mac_kbd_reset_setup(char *str, int *ints)) +{ +} diff --git a/arch/m68k/mac/via6522.c b/arch/m68k/mac/via6522.c index 7c99532a7..c867bc96d 100644 --- a/arch/m68k/mac/via6522.c +++ b/arch/m68k/mac/via6522.c @@ -179,6 +179,32 @@ void via_init_clock(void (*func)(int, void *, struct pt_regs *)) } /* + * get time offset between scheduling timer ticks + * Code stolen from arch/m68k/atari/time.c; underflow check probably + * wrong. + */ +#define TICK_SIZE 10000 + +/* This is always executed with interrupts disabled. */ +unsigned long mac_gettimeoffset (void) +{ + unsigned long ticks, offset = 0; + + /* read VIA1 timer 2 current value */ + ticks = via_read(via1, vT1CL) + (via_read(via1, vT1CH)<<8); + /* The probability of underflow is less than 2% */ + if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50) + /* Check for pending timer interrupt in VIA1 IFR */ + if (via_read(via1, vIFR) & 0x40) + offset = TICK_SIZE; + + ticks = MAC_CLOCK_TICK - ticks; + ticks = ticks * 10000L / MAC_CLOCK_TICK; + + return ticks + offset; +} + +/* * PSC (AV Macs; level 3-6): initialize interrupt enable registers */ diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c index 1f4d3a3fe..ad7c8141a 100644 --- a/arch/m68k/mm/memory.c +++ b/arch/m68k/mm/memory.c @@ -82,27 +82,25 @@ pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset) } -static struct ptable_desc { - struct ptable_desc *prev; - struct ptable_desc *next; - unsigned long page; - unsigned char alloced; -} ptable_list = { &ptable_list, &ptable_list, 0, 0xff }; - -#define PD_NONEFREE(dp) ((dp)->alloced == 0xff) -#define PD_ALLFREE(dp) ((dp)->alloced == 0) -#define PD_TABLEFREE(dp,i) (!((dp)->alloced & (1<<(i)))) -#define PD_MARKUSED(dp,i) ((dp)->alloced |= (1<<(i))) -#define PD_MARKFREE(dp,i) ((dp)->alloced &= ~(1<<(i))) +/* ++andreas: {get,free}_pointer_table rewritten to use unused fields from + struct page instead of separately kmalloced struct. Stolen from + arch/sparc/mm/srmmu.c ... */ + +typedef struct page ptable_desc; +static ptable_desc ptable_list = { &ptable_list, &ptable_list }; + +#define PD_MARKBITS(dp) (*(unsigned char *)&(dp)->offset) +#define PD_PAGE(dp) (PAGE_OFFSET + ((dp)->map_nr << PAGE_SHIFT)) +#define PAGE_PD(page) ((ptable_desc *)&mem_map[MAP_NR(page)]) #define PTABLE_SIZE (PTRS_PER_PMD * sizeof(pmd_t)) pmd_t *get_pointer_table (void) { - pmd_t *pmdp = NULL; - unsigned long flags; - struct ptable_desc *dp = ptable_list.next; - int i; + ptable_desc *dp = ptable_list.next; + unsigned char mask = PD_MARKBITS (dp); + unsigned char tmp; + unsigned int off; /* * For a pointer table for a user process address space, a @@ -110,103 +108,70 @@ pmd_t *get_pointer_table (void) * page can hold 8 pointer tables. The page is remapped in * virtual address space to be noncacheable. */ - if (PD_NONEFREE (dp)) { + if (mask == 0) { + unsigned long page; + ptable_desc *new; - if (!(dp = kmalloc (sizeof(struct ptable_desc),GFP_KERNEL))) { + if (!(page = get_free_page (GFP_KERNEL))) return 0; - } - if (!(dp->page = get_free_page (GFP_KERNEL))) { - kfree (dp); - return 0; - } + flush_tlb_kernel_page(page); + nocache_page (page); - flush_tlb_kernel_page((unsigned long) dp->page); - nocache_page (dp->page); - - dp->alloced = 0; - /* put at head of list */ - save_flags(flags); - cli(); - dp->next = ptable_list.next; - dp->prev = ptable_list.next->prev; - ptable_list.next->prev = dp; - ptable_list.next = dp; - restore_flags(flags); + new = PAGE_PD(page); + PD_MARKBITS(new) = 0xfe; + (new->prev = dp->prev)->next = new; + (new->next = dp)->prev = new; + return (pmd_t *)page; } - for (i = 0; i < 8; i++) - if (PD_TABLEFREE (dp, i)) { - PD_MARKUSED (dp, i); - pmdp = (pmd_t *)(dp->page + PTABLE_SIZE*i); - break; - } + for (tmp = 1, off = 0; (mask & tmp) == 0; tmp <<= 1, off += PTABLE_SIZE); + PD_MARKBITS(dp) = mask & ~tmp; + if (!PD_MARKBITS(dp)) { + ptable_desc *last, *next; - if (PD_NONEFREE (dp)) { /* move to end of list */ - save_flags(flags); - cli(); - dp->prev->next = dp->next; - dp->next->prev = dp->prev; - - dp->next = ptable_list.next->prev; - dp->prev = ptable_list.prev; - ptable_list.prev->next = dp; - ptable_list.prev = dp; - restore_flags(flags); - } - - memset (pmdp, 0, PTABLE_SIZE); + next = dp->next; + (next->prev = dp->prev)->next = next; - return pmdp; + last = ptable_list.prev; + (dp->next = last->next)->prev = dp; + (dp->prev = last)->next = dp; + } + return (pmd_t *) (PD_PAGE(dp) + off); } int free_pointer_table (pmd_t *ptable) { - struct ptable_desc *dp; + ptable_desc *dp, *first; unsigned long page = (unsigned long)ptable & PAGE_MASK; - int index = ((unsigned long)ptable - page)/PTABLE_SIZE; - unsigned long flags; - - for (dp = ptable_list.next; dp->page && dp->page != page; dp = dp->next) - ; + unsigned char mask = 1 << (((unsigned long)ptable - page)/PTABLE_SIZE); - if (!dp->page) - panic ("unable to find desc for ptable %p on list!", ptable); - - if (PD_TABLEFREE (dp, index)) + dp = PAGE_PD(page); + if (PD_MARKBITS (dp) & mask) panic ("table already free!"); - PD_MARKFREE (dp, index); + PD_MARKBITS (dp) |= mask; - if (PD_ALLFREE (dp)) { + if (PD_MARKBITS(dp) == 0xff) { /* all tables in page are free, free page */ - save_flags(flags); - cli(); - dp->prev->next = dp->next; - dp->next->prev = dp->prev; - restore_flags(flags); - cache_page (dp->page); - free_page (dp->page); - kfree (dp); + ptable_desc *next = dp->next; + (next->prev = dp->prev)->next = next; + cache_page (page); + free_page (page); return 1; - } else { + } else if ((first = ptable_list.next) != dp) { /* * move this descriptor to the front of the list, since * it has one or more free tables. */ - save_flags(flags); - cli(); - dp->prev->next = dp->next; - dp->next->prev = dp->prev; - - dp->next = ptable_list.next; - dp->prev = ptable_list.next->prev; - ptable_list.next->prev = dp; - ptable_list.next = dp; - restore_flags(flags); - return 0; + ptable_desc *next = dp->next; + (next->prev = dp->prev)->next = next; + + (dp->prev = first->prev)->next = dp; + (dp->next = first)->prev = dp; } + return 0; } /* maximum pages used for kpointer tables */ diff --git a/drivers/block/Config.in b/drivers/block/Config.in index d46744f3c..86208ba98 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -32,7 +32,6 @@ else bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 bool ' Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then - # Either the DMA code is buggy or the DMA hardware is unreliable. FIXME. bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then bool ' Use DMA by default when available' CONFIG_IDEDMA_AUTO diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c index 535fb21b3..ffe446afe 100644 --- a/drivers/block/ide-probe.c +++ b/drivers/block/ide-probe.c @@ -45,8 +45,8 @@ static inline void do_identify (ide_drive_t *drive, byte cmd) int bswap = 1; struct hd_driveid *id; - id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_KERNEL); - ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */ + id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC); /* called with interrupts disabled! */ + ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */ ide__sti(); /* local CPU only */ ide_fix_driveid(id); diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index c05659fd2..976219825 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -1,7 +1,7 @@ #define BLOCKMOVE #define Z_WAKE static char rcsid[] = -"$Revision: 2.2.1.4 $$Date: 1998/08/04 11:02:50 $"; +"$Revision: 2.2.1.5 $$Date: 1998/08/10 18:10:28 $"; /* * linux/drivers/char/cyclades.c @@ -31,6 +31,9 @@ static char rcsid[] = * void cleanup_module(void); * * $Log: cyclades.c,v $ + * Revision 2.2.1.5 1998/08/10 18:10:28 ivan + * Fixed Cyclom-4Yo hardware detection bug. + * * Revision 2.2.1.4 1998/08/04 11:02:50 ivan * /proc/cyclades implementation with great collaboration of * Marc Lewis ; @@ -583,7 +586,7 @@ static unsigned long cy_get_user(unsigned long *addr) #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif -#define IS_CYC_Z(card) ((card).num_chips == 1) +#define IS_CYC_Z(card) ((card).num_chips == -1) #define Z_FPGA_CHECK(card) \ ((cy_readl(&((struct RUNTIME_9060 *) \ @@ -599,7 +602,7 @@ static unsigned long cy_get_user(unsigned long *addr) #define STD_COM_FLAGS (0) -#define JIFFIES_DIFF(n, j) ((n) >= (j) ? (n) - (j) : ULONG_MAX - (n) + (j)) +#define JIFFIES_DIFF(n, j) ((n) - (j)) static DECLARE_TASK_QUEUE(tq_cyclades); @@ -3472,7 +3475,7 @@ get_modem_info(struct cyclades_port * info, unsigned int *value) } else { base_addr = (unsigned char*) (cy_card[card].base_addr); - if (cy_card[card].num_chips != 1){ + if (cy_card[card].num_chips != -1){ return -EINVAL; } @@ -4784,7 +4787,7 @@ cy_detect_pci(void)) cy_card[j].irq = (int) cy_pci_irq; cy_card[j].bus_index = 1; cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = 1; + cy_card[j].num_chips = -1; IRQ_cards[cy_pci_irq] = &cy_card[j]; /* print message */ @@ -4867,7 +4870,7 @@ cy_detect_pci(void)) cy_card[j].irq = (int) cy_pci_irq; cy_card[j].bus_index = 1; cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = 1; + cy_card[j].num_chips = -1; IRQ_cards[cy_pci_irq] = &cy_card[j]; /* print message */ @@ -4941,7 +4944,7 @@ cyclades_get_proc_info(char *buf, char **start, off_t offset, int length, if (info->count) size = sprintf(buf+len, - "%3d %8lu %10lu %8lu %10lu %8lu %9lu %6ld\n", + "%3d %8lu %10lu %8lu %10lu %8lu %9lu %6d\n", info->line, JIFFIES_DIFF(info->idle_stats.in_use, cur_jifs) / HZ, info->idle_stats.xmit_bytes, @@ -5108,7 +5111,7 @@ cy_init(void)) /* initialize per-port data structures for each valid board found */ for (board = 0 ; board < cy_nboard ; board++) { cinfo = &cy_card[board]; - if (cinfo->num_chips == 1){ /* Cyclades-Z */ + if (cinfo->num_chips == -1){ /* Cyclades-Z */ number_z_boards++; mailbox = cy_readl(&((struct RUNTIME_9060 *) cy_card[board].ctl_addr)->mail_box_0); diff --git a/drivers/net/3c505.h b/drivers/net/3c505.h index 3ff5bd19d..41993d4ec 100644 --- a/drivers/net/3c505.h +++ b/drivers/net/3c505.h @@ -65,7 +65,7 @@ #define DMA_BRST 0x01 /* DMA burst */ /* - * maximum amount of data data allowed in a PCB + * maximum amount of data allowed in a PCB */ #define MAX_PCB_DATA 62 diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c index dec9ac256..deb25d949 100644 --- a/drivers/net/de4x5.c +++ b/drivers/net/de4x5.c @@ -2197,7 +2197,7 @@ pci_probe(struct device *dev, u_long ioaddr)) } } - if (loading_module) lastPCI = NO_MORE_PCI; + lastPCI = NO_MORE_PCI; return; } @@ -3898,7 +3898,7 @@ de4x5_ms_delay(u32 msec) static int EISA_signature(char *name, s32 eisa_id) { - c_char *signatures[] = DE4X5_SIGNATURE; + static c_char *signatures[] = DE4X5_SIGNATURE; char ManCode[DE4X5_STRLEN]; union { s32 ID; @@ -3933,7 +3933,7 @@ EISA_signature(char *name, s32 eisa_id) static int PCI_signature(char *name, struct bus_type *lp) { - c_char *de4x5_signatures[] = DE4X5_SIGNATURE; + static c_char *de4x5_signatures[] = DE4X5_SIGNATURE; int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *); if (lp->chipset == DC21040) { diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index 2f00feaa6..122491c7a 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -101,7 +101,7 @@ do_aout_core_dump(long signr, struct pt_regs * regs) # define START_STACK(u) (u.start_stack) #endif - if (!current->dumpable || current->mm->count != 1) + if (!current->dumpable || atomic_read(¤t->mm->count) != 1) return 0; current->dumpable = 0; diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 0428d9e77..1c8811848 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1061,7 +1061,9 @@ static int elf_core_dump(long signr, struct pt_regs * regs) elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ - if (!current->dumpable || limit < ELF_EXEC_PAGESIZE || current->mm->count != 1) + if (!current->dumpable || + limit < ELF_EXEC_PAGESIZE || + atomic_read(¤t->mm->count) != 1) return 0; current->dumpable = 0; diff --git a/fs/dcache.c b/fs/dcache.c index 912474d45..979f7b903 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -29,6 +30,8 @@ extern unsigned long num_physpages, page_cache_size; extern int inodes_stat[]; #define nr_inodes (inodes_stat[0]) +kmem_cache_t *dentry_cache; + /* * This is the single most critical data structure when it comes * to the dcache: the hashtable for lookups. Somebody should try @@ -56,8 +59,9 @@ static inline void d_free(struct dentry *dentry) { if (dentry->d_op && dentry->d_op->d_release) dentry->d_op->d_release(dentry); - kfree(dentry->d_name.name); - kfree(dentry); + if (dname_external(dentry)) + kfree(dentry->d_name.name); + kmem_cache_free(dentry_cache, dentry); } /* @@ -498,15 +502,18 @@ printk("d_alloc: %d unused, pruning dcache\n", dentry_stat.nr_unused); free_inode_memory(8); } - dentry = kmalloc(sizeof(struct dentry), GFP_KERNEL); + dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); if (!dentry) return NULL; - str = kmalloc(NAME_ALLOC_LEN(name->len), GFP_KERNEL); - if (!str) { - kfree(dentry); - return NULL; - } + if (name->len > DNAME_INLINE_LEN-1) { + str = kmalloc(NAME_ALLOC_LEN(name->len), GFP_KERNEL); + if (!str) { + kmem_cache_free(dentry_cache, dentry); + return NULL; + } + } else + str = dentry->d_iname; memcpy(str, name->name, name->len); str[name->len] = 0; @@ -692,6 +699,32 @@ void d_add(struct dentry * entry, struct inode * inode) x = y; y = __tmp; } while (0) /* + * When switching names, the actual string doesn't strictly have to + * be preserved in the target - because we're dropping the target + * anyway. As such, we can just do a simple memcpy() to copy over + * the new name before we switch. + * + * Note that we have to be a lot more careful about getting the hash + * switched - we have to switch the hash value properly even if it + * then no longer matches the actual (corrupted) string of the target. + * The has value has to match the hash queue that the dentry is on.. + */ +static inline void switch_names(struct dentry * dentry, struct dentry * target) +{ + const unsigned char *old_name, *new_name; + + memcpy(dentry->d_iname, target->d_iname, DNAME_INLINE_LEN); + old_name = target->d_name.name; + new_name = dentry->d_name.name; + if (old_name == target->d_iname) + old_name = dentry->d_iname; + if (new_name == dentry->d_iname) + new_name = target->d_iname; + target->d_name.name = new_name; + dentry->d_name.name = old_name; +} + +/* * We cannibalize "target" when moving dentry on top of it, * because it's going to be thrown away anyway. We could be more * polite about it, though. @@ -723,10 +756,12 @@ void d_move(struct dentry * dentry, struct dentry * target) list_del(&target->d_child); /* Switch the parents and the names.. */ + switch_names(dentry, target); do_switch(dentry->d_parent, target->d_parent); - do_switch(dentry->d_name.name, target->d_name.name); do_switch(dentry->d_name.len, target->d_name.len); do_switch(dentry->d_name.hash, target->d_name.hash); + + /* And add them back to the (new) parent lists */ list_add(&target->d_child, &target->d_parent->d_subdirs); list_add(&dentry->d_child, &dentry->d_parent->d_subdirs); } @@ -885,6 +920,22 @@ __initfunc(void dcache_init(void)) int i; struct list_head *d = dentry_hashtable; + /* + * A constructor could be added for stable state like the lists, + * but it is probably not worth it because of the cache nature + * of the dcache. + * If fragmentation is too bad then the SLAB_HWCACHE_ALIGN + * flag could be removed here, to hint to the allocator that + * it should not try to get multiple page regions. + */ + dentry_cache = kmem_cache_create("dentry_cache", + sizeof(struct dentry), + 0, + SLAB_HWCACHE_ALIGN, + NULL, NULL); + if (!dentry_cache) + panic("Cannot create dentry cache"); + i = D_HASHSIZE; do { INIT_LIST_HEAD(d); diff --git a/fs/exec.c b/fs/exec.c index 81de32468..a76757c93 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -394,7 +394,7 @@ static int exec_mmap(void) struct mm_struct * mm, * old_mm; int retval, nr; - if (current->mm->count == 1) { + if (atomic_read(¤t->mm->count) == 1) { flush_cache_mm(current->mm); exit_mmap(current->mm); clear_page_tables(current); @@ -666,9 +666,9 @@ int prepare_binprm(struct linux_binprm *bprm) /* (current->mm->count > 1 is ok, as we'll get a new mm anyway) */ if (IS_NOSUID(inode) || (current->flags & PF_PTRACED) - || (current->fs->count > 1) + || (atomic_read(¤t->fs->count) > 1) || (atomic_read(¤t->sig->count) > 1) - || (current->files->count > 1)) { + || (atomic_read(¤t->files->count) > 1)) { if (id_change && !capable(CAP_SETUID)) return -EPERM; if (cap_raised && !capable(CAP_SETPCAP)) diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 362beec3a..ddf72ec4c 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -41,14 +41,17 @@ /* * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure. + * + * `len <= EXT2_NAME_LEN' is guaranteed by caller. + * `de != NULL' is guaranteed by caller. */ static inline int ext2_match (int len, const char * const name, struct ext2_dir_entry_2 * de) { - if (!de || !le32_to_cpu(de->inode) || len > EXT2_NAME_LEN) - return 0; if (len != de->name_len) return 0; + if (!de->inode) + return 0; return !memcmp(name, de->name, len); } @@ -121,10 +124,17 @@ static struct buffer_head * ext2_find_entry (struct inode * dir, de = (struct ext2_dir_entry_2 *) bh->b_data; dlimit = bh->b_data + sb->s_blocksize; while ((char *) de < dlimit) { - if (!ext2_check_dir_entry ("ext2_find_entry", dir, - de, bh, offset)) - goto failure; - if (ext2_match (namelen, name, de)) { + /* this code is executed quadratically often */ + /* do minimal checking `by hand' */ + int de_len; + + if ((char *) de + namelen <= dlimit && + ext2_match (namelen, name, de)) { + /* found a match - + just to be sure, do a full check */ + if (!ext2_check_dir_entry("ext2_find_entry", + dir, de, bh, offset)) + goto failure; for (i = 0; i < NAMEI_RA_SIZE; ++i) { if (bh_use[i] != bh) brelse (bh_use[i]); @@ -132,9 +142,13 @@ static struct buffer_head * ext2_find_entry (struct inode * dir, *res_dir = de; return bh; } - offset += le16_to_cpu(de->rec_len); + /* prevent looping on a bad block */ + de_len = le16_to_cpu(de->rec_len); + if (de_len <= 0) + goto failure; + offset += de_len; de = (struct ext2_dir_entry_2 *) - ((char *) de + le16_to_cpu(de->rec_len)); + ((char *) de + de_len); } brelse (bh); diff --git a/fs/proc/array.c b/fs/proc/array.c index 113647683..0d4b748fc 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -1061,7 +1061,7 @@ static ssize_t read_maps (int pid, struct file * file, char * buf, goto getlen_out; /* Check whether the mmaps could change if we sleep */ - volatile_task = (p != current || p->mm->count > 1); + volatile_task = (p != current || atomic_read(&p->mm->count) > 1); /* decode f_pos */ lineno = *ppos >> MAPS_LINE_SHIFT; diff --git a/fs/proc/root.c b/fs/proc/root.c index 1f5a1ea5d..e74e91366 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -819,16 +819,14 @@ static int proc_root_lookup(struct inode * dir, struct dentry * dentry) } read_lock(&tasklist_lock); p = find_task_by_pid(pid); + read_unlock(&tasklist_lock); inode = NULL; if (pid && p) { unsigned long ino = (pid << 16) + PROC_PID_INO; inode = proc_get_inode(dir->i_sb, ino, &proc_pid); - if (!inode) { - read_unlock(&tasklist_lock); + if (!inode) return -EINVAL; - } } - read_unlock(&tasklist_lock); dentry->d_op = &proc_dentry_operations; d_add(dentry, inode); @@ -895,46 +893,68 @@ int proc_readdir(struct file * filp, return 1; } -#define NUMBUF 10 +#define PROC_NUMBUF 10 +#define PROC_MAXPIDS 20 + +/* + * Get a few pid's to return for filldir - we need to hold the + * tasklist lock while doing this, and we must release it before + * we actually do the filldir itself, so we use a temp buffer.. + */ +static int get_pid_list(unsigned int index, unsigned int *pids) +{ + struct task_struct *p; + int nr = FIRST_PROCESS_ENTRY; + int nr_pids = 0; + + read_lock(&tasklist_lock); + for_each_task(p) { + int pid; + if (nr++ < index) + continue; + pid = p->pid; + if (!pid) + continue; + pids[nr_pids] = pid; + nr_pids++; + if (nr_pids >= PROC_MAXPIDS) + break; + } + read_unlock(&tasklist_lock); + return nr_pids; +} static int proc_root_readdir(struct file * filp, void * dirent, filldir_t filldir) { - struct task_struct *p; - char buf[NUMBUF]; + unsigned int pid_array[PROC_MAXPIDS]; + char buf[PROC_NUMBUF]; unsigned int nr = filp->f_pos; + unsigned int nr_pids, i; if (nr < FIRST_PROCESS_ENTRY) { int error = proc_readdir(filp, dirent, filldir); if (error <= 0) return error; - filp->f_pos = FIRST_PROCESS_ENTRY; + filp->f_pos = nr = FIRST_PROCESS_ENTRY; } - nr = FIRST_PROCESS_ENTRY; - read_lock(&tasklist_lock); - for_each_task(p) { - unsigned int pid; + nr_pids = get_pid_list(nr, pid_array); - if(nr++ < filp->f_pos) - continue; + for (i = 0; i < nr_pids; i++) { + int pid = pid_array[i]; + unsigned long j = PROC_NUMBUF; - if((pid = p->pid) != 0) { - unsigned long j = NUMBUF, i = pid; + do { + j--; + buf[j] = '0' + (pid % 10); + pid /= 10; + } while (pid); - do { - j--; - buf[j] = '0' + (i % 10); - i /= 10; - } while (i); - - if (filldir(dirent, buf+j, NUMBUF-j, - filp->f_pos, (pid << 16) + PROC_PID_INO) < 0) - break; - } + if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, (pid << 16) + PROC_PID_INO) < 0) + break; filp->f_pos++; } - read_unlock(&tasklist_lock); return 0; } diff --git a/fs/read_write.c b/fs/read_write.c index b71f06b49..1f5c69e67 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -106,7 +106,7 @@ asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high, offset = llseek(file, ((loff_t) offset_high << 32) | offset_low, origin); - retval = (int)offset & INT_MAX; + retval = (int)offset; if (offset >= 0) { retval = -EFAULT; if (!copy_to_user(result, &offset, sizeof(offset))) diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index 5597c2e6d..2334ff729 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -179,13 +179,13 @@ extern struct timezone sys_tz; static time_t utc2local(time_t time) { - return time - sys_tz.tz_minuteswest * 60; + return time - sys_tz.tz_minuteswest * 60 - (sys_tz.tz_dsttime ? 3600 :0); } static time_t local2utc(time_t time) { - return time + sys_tz.tz_minuteswest * 60; + return time + sys_tz.tz_minuteswest * 60 + (sys_tz.tz_dsttime ? 3600 : 0); } /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index 9e7184213..be37113d5 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -1771,6 +1771,8 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, MSDOS_I(new_inode)->i_logstart = MSDOS_I(old_inode)->i_logstart; MSDOS_I(new_inode)->i_attrs = MSDOS_I(old_inode)->i_attrs; + old_inode->i_nlink = 0; + fat_cache_inval_inode(old_inode); mark_inode_dirty(new_inode); @@ -1822,8 +1824,6 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, put_new_inode = 0; } - clear_inode(old_inode); - rename_done: if (locked) fat_unlock_creation(); diff --git a/include/asm-i386/bugs.h b/include/asm-i386/bugs.h index f9b6694bd..ba3a969ae 100644 --- a/include/asm-i386/bugs.h +++ b/include/asm-i386/bugs.h @@ -281,12 +281,13 @@ __initfunc(static void check_cx686_cpuid_slop(void)) if (boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX && (boot_cpu_data.x86_model & 0xf0) == 0x30) { /* 6x86(L) */ int dummy; - unsigned char ccr3, ccr5; + unsigned char ccr3, ccr4, ccr5; cli(); ccr3 = getCx86(CX86_CCR3); setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ - setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x80); /* enable cpuid */ + ccr4 = getCx86(CX86_CCR4); + setCx86(CX86_CCR4, ccr4 | 0x80); /* enable cpuid */ ccr5 = getCx86(CX86_CCR5); if (ccr5 & 2) /* reset SLOP if needed, old BIOS do this wrong */ setCx86(CX86_CCR5, ccr5 & 0xfd); diff --git a/include/asm-i386/current.h b/include/asm-i386/current.h index 3d0b299fc..bc1496a2c 100644 --- a/include/asm-i386/current.h +++ b/include/asm-i386/current.h @@ -1,6 +1,8 @@ #ifndef _I386_CURRENT_H #define _I386_CURRENT_H +struct task_struct; + static inline struct task_struct * get_current(void) { struct task_struct *current; diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h index 4ed1de3b2..4a8e92c54 100644 --- a/include/asm-i386/pgtable.h +++ b/include/asm-i386/pgtable.h @@ -100,7 +100,8 @@ static inline void flush_tlb_range(struct mm_struct *mm, static inline void flush_tlb_current_task(void) { - if (current->mm->count == 1) /* just one copy of this mm */ + /* just one copy of this mm? */ + if (atomic_read(¤t->mm->count) == 1) local_flush_tlb(); /* and that's us, so.. */ else smp_flush_tlb(); @@ -112,7 +113,7 @@ static inline void flush_tlb_current_task(void) static inline void flush_tlb_mm(struct mm_struct * mm) { - if (mm == current->mm && mm->count == 1) + if (mm == current->mm && atomic_read(&mm->count) == 1) local_flush_tlb(); else smp_flush_tlb(); @@ -121,7 +122,7 @@ static inline void flush_tlb_mm(struct mm_struct * mm) static inline void flush_tlb_page(struct vm_area_struct * vma, unsigned long va) { - if (vma->vm_mm == current->mm && current->mm->count == 1) + if (vma->vm_mm == current->mm && atomic_read(¤t->mm->count) == 1) __flush_tlb_one(va); else smp_flush_tlb(); diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index f56ce91e7..29f024b51 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -114,6 +114,27 @@ extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx) } /* + * Cyrix CPU configuration register indexes + */ +#define CX86_CCR2 0xc2 +#define CX86_CCR3 0xc3 +#define CX86_CCR4 0xe8 +#define CX86_CCR5 0xe9 +#define CX86_DIR0 0xfe +#define CX86_DIR1 0xff + +/* + * Cyrix CPU indexed register access macros + */ + +#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); }) + +#define setCx86(reg, data) do { \ + outb((reg), 0x22); \ + outb((data), 0x23); \ +} while (0) + +/* * Bus types (default is ISA, but people can check others with these..) */ extern int EISA_bus; diff --git a/include/asm-i386/semaphore.h b/include/asm-i386/semaphore.h index a68b23fc6..c78e20618 100644 --- a/include/asm-i386/semaphore.h +++ b/include/asm-i386/semaphore.h @@ -3,6 +3,12 @@ #include +#ifdef __SMP__ +extern void __check_locks(unsigned int); +#else +#define __check_locks(x) do { } while (0) +#endif + /* * SMP- and interrupt-safe semaphores.. * @@ -84,6 +90,7 @@ static inline int waking_non_zero(struct semaphore *sem) */ extern inline void down(struct semaphore * sem) { + __check_locks(0); __asm__ __volatile__( "# atomic down operation\n\t" #ifdef __SMP__ @@ -105,6 +112,7 @@ extern inline int down_interruptible(struct semaphore * sem) { int result; + __check_locks(0); __asm__ __volatile__( "# atomic interruptible down operation\n\t" #ifdef __SMP__ diff --git a/include/asm-i386/smplock.h b/include/asm-i386/smplock.h index 3bb933e42..004e69951 100644 --- a/include/asm-i386/smplock.h +++ b/include/asm-i386/smplock.h @@ -8,13 +8,20 @@ extern spinlock_t kernel_flag; +#ifdef __SMP__ +extern void __check_locks(unsigned int); +#else +#define __check_locks(x) do { } while (0) +#endif + /* * Release global kernel lock and global interrupt lock */ #define release_kernel_lock(task, cpu) \ do { \ if (task->lock_depth >= 0) \ - spin_unlock(&kernel_flag); \ + __asm__ __volatile__(spin_unlock_string \ + :"=m" (__dummy_lock(&kernel_flag))); \ release_irqlock(cpu); \ __sti(); \ } while (0) @@ -25,7 +32,8 @@ do { \ #define reacquire_kernel_lock(task) \ do { \ if (task->lock_depth >= 0) \ - spin_lock(&kernel_flag); \ + __asm__ __volatile__(spin_lock_string \ + :"=m" (__dummy_lock(&kernel_flag))); \ } while (0) @@ -38,6 +46,7 @@ do { \ */ extern __inline__ void lock_kernel(void) { + __check_locks(1); __asm__ __volatile__( "incl %1\n\t" "jne 9f" diff --git a/include/asm-i386/spinlock.h b/include/asm-i386/spinlock.h index e6fdf42f1..99d4e4a4c 100644 --- a/include/asm-i386/spinlock.h +++ b/include/asm-i386/spinlock.h @@ -152,10 +152,12 @@ typedef struct { unsigned long a[100]; } __dummy_lock_t; #define spin_lock(lock) \ __asm__ __volatile__( \ spin_lock_string \ +"\n\tcall __getlock" \ :"=m" (__dummy_lock(lock))) #define spin_unlock(lock) \ __asm__ __volatile__( \ +"call __putlock\n\t" \ spin_unlock_string \ :"=m" (__dummy_lock(lock))) @@ -200,6 +202,7 @@ typedef struct { asm volatile("\n1:\t" \ "lock ; incl %0\n\t" \ "js 2f\n" \ +"call __getlock\n" \ ".section .text.lock,\"ax\"\n" \ "2:\tlock ; decl %0\n" \ "3:\tcmpl $0,%0\n\t" \ @@ -209,7 +212,9 @@ typedef struct { :"=m" (__dummy_lock(&(rw)->lock))) #define read_unlock(rw) \ - asm volatile("lock ; decl %0" \ + asm volatile( \ +"call __putlock\n" \ + "lock ; decl %0" \ :"=m" (__dummy_lock(&(rw)->lock))) #define write_lock(rw) \ @@ -218,6 +223,7 @@ typedef struct { "jc 4f\n" \ "2:\ttestl $0x7fffffff,%0\n\t" \ "jne 3f\n" \ +"call __getlock\n" \ ".section .text.lock,\"ax\"\n" \ "3:\tlock ; btrl $31,%0\n" \ "4:\tcmp $0,%0\n\t" \ @@ -227,7 +233,10 @@ typedef struct { :"=m" (__dummy_lock(&(rw)->lock))) #define write_unlock(rw) \ - asm volatile("lock ; btrl $31,%0":"=m" (__dummy_lock(&(rw)->lock))) + asm volatile( \ +"call __putlock\n" \ + "lock ; btrl $31,%0": \ + "=m" (__dummy_lock(&(rw)->lock))) #define read_lock_irq(lock) do { __cli(); read_lock(lock); } while (0) #define read_unlock_irq(lock) do { read_unlock(lock); __sti(); } while (0) diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h index efe1050e3..91b98d5e8 100644 --- a/include/asm-i386/system.h +++ b/include/asm-i386/system.h @@ -36,6 +36,8 @@ __asm__("str %%ax\n\t" \ :"=a" (n) \ :"0" (0),"i" (FIRST_TSS_ENTRY<<3)) +#ifdef __KERNEL__ + struct task_struct; /* one of the stranger aspects of C forward declarations.. */ extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next)); @@ -109,15 +111,26 @@ static inline unsigned long _get_base(char * addr) #define get_base(ldt) _get_base( ((char *)&(ldt)) ) -static inline unsigned long get_limit(unsigned long segment) -{ - unsigned long __limit; - __asm__("lsll %1,%0" - :"=r" (__limit):"r" (segment)); - return __limit+1; -} - -#define nop() __asm__ __volatile__ ("nop") +/* + * Load a segment. Fall back on loading the zero + * segment if something goes wrong.. + */ +#define loadsegment(seg,value) \ + asm volatile("\n" \ + "1:\t" \ + "movl %0,%%" #seg "\n" \ + "2:\n" \ + ".section fixup,\"ax\"\n" \ + "3:\t" \ + "pushl $0\n\t" \ + "popl %%" #seg "\n\t" \ + "jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n\t" \ + ".align 4\n\t" \ + ".long 1b,3b\n" \ + ".previous" \ + : :"m" (*(unsigned int *)&(value))) /* * Clear and set 'TS' bit respectively @@ -132,6 +145,17 @@ __asm__ __volatile__ ( \ : /* no inputs */ \ :"ax") +#endif /* __KERNEL__ */ + +static inline unsigned long get_limit(unsigned long segment) +{ + unsigned long __limit; + __asm__("lsll %1,%0" + :"=r" (__limit):"r" (segment)); + return __limit+1; +} + +#define nop() __asm__ __volatile__ ("nop") #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) #define tas(ptr) (xchg((ptr),1)) diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h index 9da2fff06..ae8bcbcf2 100644 --- a/include/asm-i386/uaccess.h +++ b/include/asm-i386/uaccess.h @@ -7,6 +7,12 @@ #include #include +#ifdef __SMP__ +extern void __check_locks(unsigned int); +#else +#define __check_locks(x) do { } while (0) +#endif + #define VERIFY_READ 0 #define VERIFY_WRITE 1 @@ -112,6 +118,7 @@ extern void __get_user_4(void); /* Careful: we have to cast the result to the type of the pointer for sign reasons */ #define get_user(x,ptr) \ ({ int __ret_gu,__val_gu; \ + __check_locks(1); \ switch(sizeof (*(ptr))) { \ case 1: __get_user_x(1,__ret_gu,__val_gu,ptr); break; \ case 2: __get_user_x(2,__ret_gu,__val_gu,ptr); break; \ @@ -136,6 +143,7 @@ extern void __put_user_bad(void); #define put_user(x,ptr) \ ({ int __ret_pu; \ + __check_locks(1); \ switch(sizeof (*(ptr))) { \ case 1: __put_user_x(1,__ret_pu,(__typeof__(*(ptr)))(x),ptr); break; \ case 2: __put_user_x(2,__ret_pu,(__typeof__(*(ptr)))(x),ptr); break; \ @@ -153,6 +161,7 @@ extern void __put_user_bad(void); #define __put_user_nocheck(x,ptr,size) \ ({ \ long __pu_err; \ + __check_locks(1); \ __put_user_size((x),(ptr),(size),__pu_err); \ __pu_err; \ }) @@ -195,6 +204,7 @@ struct __large_struct { unsigned long buf[100]; }; #define __get_user_nocheck(x,ptr,size) \ ({ \ long __gu_err, __gu_val; \ + __check_locks(1); \ __get_user_size(__gu_val,(ptr),(size),__gu_err); \ (x) = (__typeof__(*(ptr)))__gu_val; \ __gu_err; \ @@ -274,6 +284,7 @@ do { \ static inline unsigned long __generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n) { + __check_locks(1); __copy_user(to,from,n); return n; } @@ -281,6 +292,7 @@ __generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n) static inline unsigned long __generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n) { + __check_locks(1); __copy_user(to,from,n); return n; } @@ -375,6 +387,7 @@ unsigned long __generic_copy_from_user(void *, const void *, unsigned long); static inline unsigned long __constant_copy_to_user(void *to, const void *from, unsigned long n) { + __check_locks(1); if (access_ok(VERIFY_WRITE, to, n)) __constant_copy_user(to,from,n); return n; @@ -383,6 +396,7 @@ __constant_copy_to_user(void *to, const void *from, unsigned long n) static inline unsigned long __constant_copy_from_user(void *to, const void *from, unsigned long n) { + __check_locks(1); if (access_ok(VERIFY_READ, from, n)) __constant_copy_user(to,from,n); return n; @@ -391,6 +405,7 @@ __constant_copy_from_user(void *to, const void *from, unsigned long n) static inline unsigned long __constant_copy_to_user_nocheck(void *to, const void *from, unsigned long n) { + __check_locks(1); __constant_copy_user(to,from,n); return n; } @@ -398,6 +413,7 @@ __constant_copy_to_user_nocheck(void *to, const void *from, unsigned long n) static inline unsigned long __constant_copy_from_user_nocheck(void *to, const void *from, unsigned long n) { + __check_locks(1); __constant_copy_user(to,from,n); return n; } diff --git a/include/asm-m68k/bitops.h b/include/asm-m68k/bitops.h index 53db5755e..97aac09b2 100644 --- a/include/asm-m68k/bitops.h +++ b/include/asm-m68k/bitops.h @@ -218,23 +218,6 @@ extern __inline__ unsigned long ffz(unsigned long word) * differs in spirit from the above ffz (man ffs). */ -#define ffs(x) generic_ffs(x) - -/* - * hweightN: returns the hamming weight (i.e. the number - * of bits set) of a N-bit word - */ - -#define hweight32(x) generic_hweight32(x) -#define hweight16(x) generic_hweight16(x) -#define hweight8(x) generic_hweight8(x) - -/* - * ffs: find first bit set. This is defined the same way as - * the libc and compiler builtin ffs routines, therefore - * differs in spirit from the above ffz (man ffs). - */ - extern __inline__ int ffs(int x) { int cnt; diff --git a/include/asm-m68k/bootinfo.h b/include/asm-m68k/bootinfo.h index ff5d41ef8..c0a7e6cb0 100644 --- a/include/asm-m68k/bootinfo.h +++ b/include/asm-m68k/bootinfo.h @@ -262,10 +262,6 @@ struct compat_bi_Atari { #ifndef __ASSEMBLY__ -#define MACHW_DECLARE(name) unsigned name : 1 -#define MACHW_SET(name) (boot_info.bi_mac.hw_present.name = 1) -#define MACHW_PRESENT(name) (boot_info.bi_mac.hw_present.name) - struct compat_bi_Macintosh { unsigned long videoaddr; @@ -290,25 +286,6 @@ struct compat_bi_Macintosh unsigned long rombase; unsigned long adbdelay; unsigned long timedbra; - struct { - /* video hardware */ - /* sound hardware */ - /* disk storage interfaces */ - MACHW_DECLARE(MAC_SCSI); /* Directly mapped NCR5380 */ - MACHW_DECLARE(IDE); /* IDE Interface */ - /* other I/O hardware */ - MACHW_DECLARE(SCC); /* Serial Communications Contr. */ - /* DMA */ - MACHW_DECLARE(SCSI_DMA); /* DMA for the NCR5380 */ - /* real time clocks */ - MACHW_DECLARE(RTC_CLK); /* clock chip */ - /* supporting hardware */ - MACHW_DECLARE(VIA1); /* Versatile Interface Ad. 1 */ - MACHW_DECLARE(VIA2); /* Versatile Interface Ad. 2 */ - MACHW_DECLARE(RBV); /* Versatile Interface Ad. 2+ */ - /* NUBUS */ - MACHW_DECLARE(NUBUS); /* NUBUS */ - } hw_present; }; #else diff --git a/include/asm-m68k/keyboard.h b/include/asm-m68k/keyboard.h index cb013200b..c30c8dc04 100644 --- a/include/asm-m68k/keyboard.h +++ b/include/asm-m68k/keyboard.h @@ -24,7 +24,7 @@ static __inline__ int kbd_setkeycode(unsigned int scancode, static __inline__ int kbd_getkeycode(unsigned int scancode) { - return -EOPNOTSUPP; + return scancode > 127 ? -EINVAL : scancode; } static __inline__ int kbd_pretranslate(unsigned char scancode, char raw_mode) diff --git a/include/asm-m68k/machw.h b/include/asm-m68k/machw.h index e0812e048..90ff6b627 100644 --- a/include/asm-m68k/machw.h +++ b/include/asm-m68k/machw.h @@ -99,7 +99,7 @@ struct VIA # define via_1 ((*(volatile struct VIA *)VIA1_BAS)) # define via_2 ((*(volatile struct VIA *)VIA2_BAS)) -# define via1_regp ((volatile unsigned char *)VIA1_BAS) +# define via1_regp ((volatile unsigned char *)VIA1_BAS) /* * OSS/RBV base address @@ -112,4 +112,35 @@ struct VIA #define nIFR 0x203 #define oIFR 0x202 + +/* hardware stuff */ + +#define MACHW_DECLARE(name) unsigned name : 1 +#define MACHW_SET(name) (mac_hw_present.name = 1) +#define MACHW_PRESENT(name) (mac_hw_present.name) + +struct { + /* video hardware */ + /* sound hardware */ + /* disk storage interfaces */ + MACHW_DECLARE(MAC_SCSI_80); /* Directly mapped NCR5380 */ + MACHW_DECLARE(MAC_SCSI_96); /* 53c9[46] */ + MACHW_DECLARE(MAC_SCSI_96_2); /* 2nd 53c9[46] Q900 and Q950 */ + MACHW_DECLARE(IDE); /* IDE Interface */ + /* other I/O hardware */ + MACHW_DECLARE(SCC); /* Serial Communications Contr. */ + /* DMA */ + MACHW_DECLARE(SCSI_DMA); /* DMA for the NCR5380 */ + /* real time clocks */ + MACHW_DECLARE(RTC_CLK); /* clock chip */ + /* supporting hardware */ + MACHW_DECLARE(VIA1); /* Versatile Interface Ad. 1 */ + MACHW_DECLARE(VIA2); /* Versatile Interface Ad. 2 */ + MACHW_DECLARE(RBV); /* Versatile Interface Ad. 2+ */ + /* NUBUS */ + MACHW_DECLARE(NUBUS); /* NUBUS */ +} mac_hw_present; + +/* extern struct mac_hw_present mac_hw_present; */ + #endif /* linux/machw.h */ diff --git a/include/asm-m68k/pgtable.h b/include/asm-m68k/pgtable.h index c05a7c600..d49f985bf 100644 --- a/include/asm-m68k/pgtable.h +++ b/include/asm-m68k/pgtable.h @@ -852,4 +852,7 @@ extern inline void update_mmu_cache(struct vm_area_struct * vma, #define module_map vmalloc #define module_unmap vfree +/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ +#define PageSkip(page) (0) + #endif /* _M68K_PGTABLE_H */ diff --git a/include/asm-m68k/posix_types.h b/include/asm-m68k/posix_types.h index 33c423980..460de0b30 100644 --- a/include/asm-m68k/posix_types.h +++ b/include/asm-m68k/posix_types.h @@ -37,6 +37,8 @@ typedef struct { #endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ } __kernel_fsid_t; +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) + #undef __FD_SET #define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d)) @@ -49,4 +51,6 @@ typedef struct { #undef __FD_ZERO #define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp))) +#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ + #endif diff --git a/include/asm-m68k/softirq.h b/include/asm-m68k/softirq.h index bed386d44..0798b0d7d 100644 --- a/include/asm-m68k/softirq.h +++ b/include/asm-m68k/softirq.h @@ -61,5 +61,6 @@ extern inline void end_bh_atomic(void) /* These are for the irq's testing the lock */ #define softirq_trylock(cpu) (local_bh_count[cpu] ? 0 : (local_bh_count[cpu]=1)) #define softirq_endlock(cpu) (local_bh_count[cpu] = 0) +#define synchronize_bh() do { } while (0) #endif diff --git a/include/asm-m68k/uaccess.h b/include/asm-m68k/uaccess.h index 864c49657..64b8be7bd 100644 --- a/include/asm-m68k/uaccess.h +++ b/include/asm-m68k/uaccess.h @@ -200,6 +200,7 @@ __generic_copy_to_user(void *to, const void *from, unsigned long n) "5:\n" ".section .fixup,\"ax\"\n" " .even\n" + "60:addql #1,%2\n" "6: lsll #2,%2\n" " addl %4,%2\n" " jra 5b\n" @@ -210,9 +211,11 @@ __generic_copy_to_user(void *to, const void *from, unsigned long n) ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" + " .long 1b,60b\n" " .long 22b,6b\n" " .long 2b,6b\n" " .long 24b,7b\n" + " .long 3b,60b\n" " .long 4b,7b\n" " .long 25b,8b\n" " .long 5b,8b\n" @@ -458,16 +461,20 @@ __constant_copy_from_user(void *to, const void *from, unsigned long n) "31: movesl %%d0,(%0)+\n" \ "11: subql #1,%2\n" \ " jne 10b\n" \ + "41:\n" \ ".section .fixup,\"ax\"\n" \ " .even\n" \ + "22: addql #1,%2\n" \ "12: lsll #2,%2\n" \ fixup "\n" \ " jra 13f\n" \ ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 4\n" \ + " .long 10b,22b\n" \ " .long 31b,12b\n" \ " .long 11b,12b\n" \ + " .long 41b,22b\n" \ ".previous\n" \ copy "\n" \ "13:" \ @@ -803,6 +810,7 @@ clear_user(void *to, unsigned long n) "5:\n" ".section .fixup,\"ax\"\n" " .even\n" + "61:addql #1,%1\n" "6: lsll #2,%1\n" " addl %2,%1\n" " jra 5b\n" @@ -813,8 +821,9 @@ clear_user(void *to, unsigned long n) ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" - " .long 1b,6b\n" + " .long 1b,61b\n" " .long 2b,6b\n" + " .long 3b,61b\n" " .long 24b,7b\n" " .long 4b,7b\n" " .long 25b,8b\n" diff --git a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h index c9836a6ba..4ed5d9f34 100644 --- a/include/asm-m68k/unistd.h +++ b/include/asm-m68k/unistd.h @@ -27,7 +27,7 @@ #define __NR_lseek 19 #define __NR_getpid 20 #define __NR_mount 21 -#define __NR_umount 22 +#define __NR_oldumount 22 #define __NR_setuid 23 #define __NR_getuid 24 #define __NR_stime 25 @@ -57,7 +57,7 @@ #define __NR_geteuid 49 #define __NR_getegid 50 #define __NR_acct 51 -#define __NR_phys 52 +#define __NR_umount 52 #define __NR_lock 53 #define __NR_ioctl 54 #define __NR_fcntl 55 @@ -191,6 +191,9 @@ #define __NR_capget 184 #define __NR_capset 185 #define __NR_sigaltstack 186 +#define __NR_sendfile 187 +#define __NR_streams1 188 /* some people actually want it */ +#define __NR_streams2 189 /* some people actually want it */ /* user-visible error numbers are in the range -1 - -122: see */ diff --git a/include/linux/cyclades.h b/include/linux/cyclades.h index e03a2a626..024104c31 100644 --- a/include/linux/cyclades.h +++ b/include/linux/cyclades.h @@ -1,4 +1,4 @@ -/* $Revision: 2.5 $$Date: 1998/08/03 16:57:01 $ +/* $Revision: 2.6 $$Date: 1998/08/10 16:57:01 $ * linux/include/linux/cyclades.h * * This file is maintained by Ivan Passos , @@ -492,7 +492,7 @@ struct cyclades_card { long base_addr; long ctl_addr; int irq; - int num_chips; /* 0 if card absent, 1 if Z/PCI, else Y */ + int num_chips; /* 0 if card absent, -1 if Z/PCI, else Y */ int first_line; /* minor number of first channel on card */ int bus_index; /* address shift - 0 for ISA, 1 for PCI */ int inact_ctrl; /* FW Inactivity control - 0 disabled, 1 enabled */ diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 42866df59..b546fb5af 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -50,6 +50,8 @@ static __inline__ unsigned int full_name_hash(const char * name, unsigned int le return end_name_hash(hash); } +#define DNAME_INLINE_LEN 16 + struct dentry { int d_count; unsigned int d_flags; @@ -68,6 +70,7 @@ struct dentry { struct super_block * d_sb; /* The root of the dentry tree */ unsigned long d_reftime; /* last time referenced */ void * d_fsdata; /* fs-specific data */ + unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */ }; struct dentry_operations { @@ -114,6 +117,11 @@ static __inline__ void d_drop(struct dentry * dentry) INIT_LIST_HEAD(&dentry->d_hash); } +static __inline__ int dname_external(struct dentry *d) +{ + return d->d_name.name != d->d_iname; +} + /* * These are the low-level FS interfaces to the dcache.. */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 3c466017d..b81b3660a 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -127,7 +127,7 @@ asmlinkage void schedule(void); * Open file table structure */ struct files_struct { - int count; + atomic_t count; int max_fds; struct file ** fd; /* current fd array */ fd_set close_on_exec; @@ -135,7 +135,7 @@ struct files_struct { }; #define INIT_FILES { \ - 1, \ + ATOMIC_INIT(1), \ NR_OPEN, \ &init_fd_array[0], \ { { 0, } }, \ @@ -143,13 +143,13 @@ struct files_struct { } struct fs_struct { - int count; + atomic_t count; int umask; struct dentry * root, * pwd; }; #define INIT_FS { \ - 1, \ + ATOMIC_INIT(1), \ 0022, \ NULL, NULL \ } @@ -160,7 +160,8 @@ struct fs_struct { struct mm_struct { struct vm_area_struct *mmap, *mmap_cache; pgd_t * pgd; - int count, map_count; + atomic_t count; + int map_count; struct semaphore mmap_sem; unsigned long context; unsigned long start_code, end_code, start_data, end_data; @@ -177,7 +178,8 @@ struct mm_struct { }; #define INIT_MM { \ - &init_mmap, NULL, swapper_pg_dir, 1, 1, \ + &init_mmap, NULL, swapper_pg_dir, \ + ATOMIC_INIT(1), 1, \ MUTEX, \ 0, \ 0, 0, 0, 0, \ @@ -198,6 +200,13 @@ struct signal_struct { { {{0,}}, }, \ SPIN_LOCK_UNLOCKED } +/* + * Some day this will be a full-fledged user tracking system.. + * Right now it is only used to track how many processes a + * user has, but it has the potential to track memory usage etc. + */ +struct user_struct; + struct task_struct { /* these are hardcoded - don't touch */ volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ @@ -270,6 +279,7 @@ struct task_struct { int ngroups; gid_t groups[NGROUPS]; kernel_cap_t cap_effective, cap_inheritable, cap_permitted; + struct user_struct *user; /* limits */ struct rlimit rlim[RLIM_NLIMITS]; unsigned short used_math; @@ -348,6 +358,7 @@ struct task_struct { /* uid etc */ 0,0,0,0,0,0,0,0, \ /* suppl grps*/ 0, {0,}, \ /* caps */ CAP_INIT_EFF_SET,CAP_INIT_INH_SET,CAP_FULL_SET, \ +/* user */ NULL, \ /* rlimits */ INIT_RLIMITS, \ /* math */ 0, \ /* comm */ "swapper", \ @@ -427,7 +438,8 @@ extern __inline__ struct task_struct *find_task_by_pid(int pid) } /* per-UID process charging. */ -extern int charge_uid(struct task_struct *p, int count); +extern int alloc_uid(struct task_struct *p); +void free_uid(struct task_struct *p); #include @@ -587,7 +599,7 @@ extern inline int capable(int cap) extern struct mm_struct * mm_alloc(void); static inline void mmget(struct mm_struct * mm) { - mm->count++; + atomic_inc(&mm->count); } extern void mmput(struct mm_struct *); diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index da2b2cdd1..8553a05c5 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -127,6 +127,9 @@ rpc_set_timeout(struct rpc_clnt *clnt, unsigned int retr, unsigned long incr) xprt_set_timeout(&clnt->cl_timeout, retr, incr); } +extern void rpciod_tcp_dispatcher(void); +extern void rpciod_wake_up(void); + /* * Helper function for NFSroot support */ diff --git a/ipc/msg.c b/ipc/msg.c index 217967e02..bcc58a4c5 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -1,6 +1,13 @@ /* * linux/ipc/msg.c * Copyright (C) 1992 Krishna Balasubramanian + * + * Removed all the remaining kerneld mess + * Catch the -EFAULT stuff properly + * Use GFP_KERNEL for messages as in 1.2 + * Fixed up the unchecked user space derefs + * Copyright (C) 1998 Alan Cox & Andi Kleen + * */ #include @@ -42,7 +49,7 @@ void __init msg_init (void) static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg) { - int id, err; + int id; struct msqid_ds *msq; struct ipc_perm *ipcp; struct msg *msgh; @@ -80,12 +87,16 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg } /* allocate message header and text space*/ - msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz, GFP_ATOMIC); + msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz, GFP_KERNEL); if (!msgh) return -ENOMEM; msgh->msg_spot = (char *) (msgh + 1); - copy_from_user (msgh->msg_spot, msgp->mtext, msgsz); + if (copy_from_user(msgh->msg_spot, msgp->mtext, msgsz)) + { + kfree(msgh); + return -EFAULT; + } if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID || msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) { @@ -120,7 +131,7 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty struct ipc_perm *ipcp; struct msg *tmsg, *leastp = NULL; struct msg *nmsg = NULL; - int id, err; + int id; if (msqid < 0 || (long) msgsz < 0) return -EINVAL; diff --git a/kernel/capability.c b/kernel/capability.c index b5b5367ac..cd576cf4a 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -14,17 +14,7 @@ #include -static inline void cap_fromuser(kernel_cap_t *k, __u32 *u) -{ - copy_from_user(k, u, sizeof(*k)); -} - - -static inline void cap_touser(__u32 *u, const kernel_cap_t *k) -{ - copy_to_user(u, k, sizeof(*k)); -} - +/* Note: never hold tasklist_lock while spinning for this one */ spinlock_t task_capability_lock; /* @@ -33,65 +23,58 @@ spinlock_t task_capability_lock; * uninteresting and/or not to be changed. */ -asmlinkage int sys_capget(cap_user_header_t header, cap_user_data_t data) +asmlinkage int sys_capget(cap_user_header_t header, cap_user_data_t dataptr) { - int error = -EINVAL, pid; + int error, pid; __u32 version; struct task_struct *target; + struct __user_cap_data_struct data; - if (!access_ok(VERIFY_WRITE, &header->version, sizeof(*header))) { - /* not large enough for current header so indicate error */ - if (access_ok(VERIFY_WRITE, &header->version, - sizeof(header->version))) { - return error; - } - goto all_done; - } - - copy_from_user(&version, &header->version, sizeof(header->version)); + if (get_user(version, &header->version)) + return -EFAULT; + + error = -EINVAL; if (version != _LINUX_CAPABILITY_VERSION) { - /* if enough space for kernel version, write that */ - - all_done: version = _LINUX_CAPABILITY_VERSION; - copy_to_user(&header->version, &version, - sizeof(header->version)); + if (put_user(version, &header->version)) + error = -EFAULT; return error; } - if (!access_ok(VERIFY_WRITE, data, sizeof(*data))) { - return error; - } + if (get_user(pid, &header->pid)) + return -EFAULT; - copy_from_user(&pid, &header->pid, sizeof(header->pid)); - if (pid < 0) { - return error; - } + if (pid < 0) + return -EINVAL; + + error = 0; spin_lock(&task_capability_lock); if (pid && pid != current->pid) { - read_lock(&tasklist_lock); + read_lock(&tasklist_lock); target = find_task_by_pid(pid); /* identify target of query */ - if (!target) { + if (!target) error = -ESRCH; - goto out; - } } else { target = current; } - cap_touser(&data->permitted, &target->cap_permitted); - cap_touser(&data->inheritable, &target->cap_inheritable); - cap_touser(&data->effective, &target->cap_effective); + if (!error) { + data.permitted = target->cap_permitted.cap; + data.inheritable = target->cap_inheritable.cap; + data.effective = target->cap_effective.cap; + } - error = 0; + if (target != current) + read_unlock(&tasklist_lock); + spin_unlock(&task_capacibility_lock); -out: - if (target != current) { - read_unlock(&tasklist_lock); + if (!error) { + if (copy_to_user(dataptr, &data, sizeof data)) + return -EFAULT; } - spin_unlock(&task_capability_lock); + return error; } @@ -152,38 +135,31 @@ asmlinkage int sys_capset(cap_user_header_t header, const cap_user_data_t data) kernel_cap_t inheritable, permitted, effective; __u32 version; struct task_struct *target; - int error = -EINVAL, pid; - - if (!access_ok(VERIFY_WRITE, &header->version, sizeof(*header))) { - /* not large enough for current header so indicate error */ - if (!access_ok(VERIFY_WRITE, &header->version, - sizeof(header->version))) { - return error; - } - goto all_done; - } + int error, pid; - copy_from_user(&version, &header->version, sizeof(header->version)); - if (version != _LINUX_CAPABILITY_VERSION) { + if (get_user(version, &header->version)) + return -EFAULT; - all_done: + if (version != _LINUX_CAPABILITY_VERSION) { version = _LINUX_CAPABILITY_VERSION; - copy_to_user(&header->version, &version, - sizeof(header->version)); - return error; - } - - if (!access_ok(VERIFY_READ, data, sizeof(*data))) { - return error; + if (put_user(version, &header->version)) + return -EFAULT; + return -EINVAL; } /* may want to set other processes at some point -- for now demand 0 */ - copy_from_user(&pid, &header->pid, sizeof(pid)); + if (get_user(pid, &header->pid)) + return -EFAULT; - error = -EPERM; if (pid && !capable(CAP_SETPCAP)) - return error; + return -EPERM; + if (copy_from_user(&effective, &data->effective, sizeof(effective)) || + copy_from_user(&inheritable, &data->inheritable, sizeof(inheritable)) || + copy_from_user(&permitted, &data->permitted, sizeof(permitted))) + return -EFAULT; + + error = -EPERM; spin_lock(&task_capability_lock); if (pid > 0 && pid != current->pid) { @@ -191,16 +167,12 @@ asmlinkage int sys_capset(cap_user_header_t header, const cap_user_data_t data) target = find_task_by_pid(pid); /* identify target of query */ if (!target) { error = -ESRCH; - goto out; - } + goto out; + } } else { target = current; } - /* copy from userspace */ - cap_fromuser(&effective, &data->effective); - cap_fromuser(&inheritable, &data->inheritable); - cap_fromuser(&permitted, &data->permitted); /* verify restrictions on target's new Inheritable set */ if (!cap_issubset(inheritable, diff --git a/kernel/exit.c b/kernel/exit.c index 3de5781c8..6f6b281ea 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -52,7 +52,7 @@ static void release(struct task_struct * p) } while (p->has_cpu); } #endif - charge_uid(p, -1); + free_uid(p); nr_tasks--; add_free_taskslot(p->tarray_ptr); @@ -196,7 +196,7 @@ static inline void __exit_files(struct task_struct *tsk) if (files) { tsk->files = NULL; - if (!--files->count) { + if (atomic_dec_and_test(&files->count)) { close_files(files); /* * Free the fd array as appropriate ... @@ -221,7 +221,7 @@ static inline void __exit_fs(struct task_struct *tsk) if (fs) { tsk->fs = NULL; - if (!--fs->count) { + if (atomic_dec_and_test(&fs->count)) { dput(fs->root); dput(fs->pwd); kfree(fs); diff --git a/kernel/fork.c b/kernel/fork.c index d956d502e..5b9e24163 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -50,9 +50,9 @@ spinlock_t taskslot_lock = SPIN_LOCK_UNLOCKED; */ #define UIDHASH_SZ (PIDHASH_SZ >> 2) -static struct uid_taskcount { - struct uid_taskcount *next, **pprev; - unsigned short uid; +static struct user_struct { + struct user_struct *next, **pprev; + unsigned int uid; int task_count; } *uidhash[UIDHASH_SZ]; @@ -62,7 +62,7 @@ kmem_cache_t *uid_cachep; #define uidhashfn(uid) (((uid >> 8) ^ uid) & (UIDHASH_SZ - 1)) -static inline void uid_hash_insert(struct uid_taskcount *up, unsigned int hashent) +static inline void uid_hash_insert(struct user_struct *up, unsigned int hashent) { spin_lock(&uidhash_lock); if((up->next = uidhash[hashent]) != NULL) @@ -72,7 +72,7 @@ static inline void uid_hash_insert(struct uid_taskcount *up, unsigned int hashen spin_unlock(&uidhash_lock); } -static inline void uid_hash_remove(struct uid_taskcount *up) +static inline void uid_hash_remove(struct user_struct *up) { spin_lock(&uidhash_lock); if(up->next) @@ -81,9 +81,9 @@ static inline void uid_hash_remove(struct uid_taskcount *up) spin_unlock(&uidhash_lock); } -static inline struct uid_taskcount *uid_find(unsigned short uid, unsigned int hashent) +static inline struct user_struct *uid_find(unsigned short uid, unsigned int hashent) { - struct uid_taskcount *up; + struct user_struct *up; spin_lock(&uidhash_lock); for(up = uidhash[hashent]; (up && up->uid != uid); up = up->next) @@ -92,31 +92,38 @@ static inline struct uid_taskcount *uid_find(unsigned short uid, unsigned int ha return up; } -int charge_uid(struct task_struct *p, int count) +void free_uid(struct task_struct *p) { - unsigned int hashent = uidhashfn(p->uid); - struct uid_taskcount *up = uid_find(p->uid, hashent); - - if(up) { - int limit = p->rlim[RLIMIT_NPROC].rlim_cur; - int newcnt = up->task_count + count; + struct user_struct *up = p->user; - if(newcnt > limit) - return -EAGAIN; - else if(newcnt == 0) { + if (up) { + p->user = NULL; + lock_kernel(); + if (!--up->task_count) { uid_hash_remove(up); kmem_cache_free(uid_cachep, up); - return 0; } - } else { + unlock_kernel(); + } +} + +int alloc_uid(struct task_struct *p) +{ + unsigned int hashent = uidhashfn(p->uid); + struct user_struct *up = uid_find(p->uid, hashent); + + p->user = up; + if (!up) { up = kmem_cache_alloc(uid_cachep, SLAB_KERNEL); - if(!up) + if (!up) return -EAGAIN; + p->user = up; up->uid = p->uid; up->task_count = 0; uid_hash_insert(up, hashent); } - up->task_count += count; + + up->task_count++; return 0; } @@ -124,7 +131,7 @@ __initfunc(void uidcache_init(void)) { int i; - uid_cachep = kmem_cache_create("uid_cache", sizeof(struct uid_taskcount), + uid_cachep = kmem_cache_create("uid_cache", sizeof(struct user_struct), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if(!uid_cachep) @@ -134,22 +141,13 @@ __initfunc(void uidcache_init(void)) uidhash[i] = 0; } -static inline int find_empty_process(void) +static inline struct task_struct ** find_empty_process(void) { - struct task_struct **tslot; + struct task_struct **tslot = NULL; - if(current->uid) { - int error; - - if(nr_tasks >= NR_TASKS - MIN_TASKS_LEFT_FOR_ROOT) - return -EAGAIN; - if((error = charge_uid(current, 1)) < 0) - return error; - } - tslot = get_free_taskslot(); - if(tslot) - return tslot - &task[0]; - return -EAGAIN; + if (!current->uid || (nr_tasks < NR_TASKS - MIN_TASKS_LEFT_FOR_ROOT)) + tslot = get_free_taskslot(); + return tslot; } /* Protects next_safe and last_pid. */ @@ -270,7 +268,7 @@ struct mm_struct * mm_alloc(void) if (mm) { *mm = *current->mm; init_new_context(mm); - mm->count = 1; + atomic_set(&mm->count, 1); mm->map_count = 0; mm->def_flags = 0; mm->mmap_sem = MUTEX_LOCKED; @@ -293,7 +291,7 @@ struct mm_struct * mm_alloc(void) */ void mmput(struct mm_struct *mm) { - if (!--mm->count) { + if (atomic_dec_and_test(&mm->count)) { release_segments(mm); exit_mmap(mm); free_page_tables(mm); @@ -347,13 +345,13 @@ fail_nomem: static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk) { if (clone_flags & CLONE_FS) { - current->fs->count++; + atomic_inc(¤t->fs->count); return 0; } tsk->fs = kmalloc(sizeof(*tsk->fs), GFP_KERNEL); if (!tsk->fs) return -1; - tsk->fs->count = 1; + atomic_set(&tsk->fs->count, 1); tsk->fs->umask = current->fs->umask; tsk->fs->root = dget(current->fs->root); tsk->fs->pwd = dget(current->fs->pwd); @@ -394,7 +392,7 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) goto out; if (clone_flags & CLONE_FILES) { - oldf->count++; + atomic_inc(&oldf->count); goto out; } @@ -417,7 +415,7 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) goto out_release; memset((void *) new_fds, 0, size); - newf->count = 1; + atomic_set(&newf->count, 1); newf->max_fds = NR_OPEN; newf->fd = new_fds; newf->close_on_exec = oldf->close_on_exec; @@ -479,19 +477,31 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) int retval = -ENOMEM; struct task_struct *p; - down(¤t->mm->mmap_sem); - lock_kernel(); p = alloc_task_struct(); if (!p) - goto bad_fork; - - retval = -EAGAIN; - nr = find_empty_process(); - if (nr < 0) - goto bad_fork_free; + goto fork_out; *p = *current; + down(¤t->mm->mmap_sem); + lock_kernel(); + + if (p->user) { + if (p->user->task_count >= p->rlim[RLIMIT_NPROC].rlim_cur) + goto bad_fork_free; + } + + { + struct task_struct **tslot; + tslot = find_empty_process(); + retval = -EAGAIN; + if (!tslot) + goto bad_fork_free; + p->tarray_ptr = tslot; + *tslot = p; + nr = tslot - &task[0]; + } + if (p->exec_domain && p->exec_domain->module) __MOD_INC_USE_COUNT(p->exec_domain->module); if (p->binfmt && p->binfmt->module) @@ -545,8 +555,6 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) #endif p->lock_depth = -1; /* -1 = no lock */ p->start_time = jiffies; - p->tarray_ptr = &task[nr]; - *p->tarray_ptr = p; { /* This makes it visible to the rest of the system */ @@ -558,6 +566,8 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) } nr_tasks++; + if (p->user) + p->user->task_count++; retval = -ENOMEM; /* copy all the process information */ @@ -599,6 +609,7 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) bad_fork: up(¤t->mm->mmap_sem); unlock_kernel(); +fork_out: return retval; bad_fork_cleanup_sighand: @@ -608,12 +619,10 @@ bad_fork_cleanup_fs: bad_fork_cleanup_files: exit_files(p); /* blocking */ bad_fork_cleanup: - charge_uid(current, -1); if (p->exec_domain && p->exec_domain->module) __MOD_DEC_USE_COUNT(p->exec_domain->module); if (p->binfmt && p->binfmt->module) __MOD_DEC_USE_COUNT(p->binfmt->module); - add_free_taskslot(p->tarray_ptr); { unsigned long flags; @@ -623,7 +632,10 @@ bad_fork_cleanup: write_unlock_irqrestore(&tasklist_lock, flags); } + if (p->user) + p->user->task_count++; nr_tasks--; + add_free_taskslot(p->tarray_ptr); bad_fork_free: free_task_struct(p); goto bad_fork; diff --git a/kernel/kmod.c b/kernel/kmod.c index b098b477b..1df9f4356 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -68,8 +68,8 @@ static int exec_modprobe(void * module_name) if (current->files->fd[i]) close(i); } - /* kernel_thread() -> ... -> charge_uid(current, 1) workaround */ - charge_uid(current, -1); + /* Drop the "current user" thing */ + free_uid(current); /* Give kmod all privileges.. */ current->uid = current->euid = current->fsuid = 0; diff --git a/kernel/sched.c b/kernel/sched.c index 1b76fee50..6861cc171 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -470,6 +470,8 @@ asmlinkage void schedule(void) goto scheduling_in_interrupt; release_kernel_lock(prev, this_cpu); + __check_locks(1); + /* Do "administrative" work here while we don't hold any locks */ if (bh_active & bh_mask) do_bottom_half(); diff --git a/kernel/sys.c b/kernel/sys.c index 169f4d699..1b4c6df40 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -405,10 +405,9 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid) * cheaply with the new uid cache, so if it matters * we should be checking for it. -DaveM */ - charge_uid(current, -1); + free_uid(current); current->uid = new_ruid; - if(new_ruid) - charge_uid(current, 1); + alloc_uid(current); } if (!issecure(SECURE_NO_SETUID_FIXUP)) { @@ -450,10 +449,9 @@ asmlinkage int sys_setuid(uid_t uid) if (new_ruid != old_ruid) { /* See comment above about NPROC rlimit issues... */ - charge_uid(current, -1); + free_uid(current); current->uid = new_ruid; - if(new_ruid) - charge_uid(current, 1); + alloc_uid(current); } if (!issecure(SECURE_NO_SETUID_FIXUP)) { @@ -473,7 +471,8 @@ asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) int old_ruid = current->uid; int old_euid = current->euid; int old_suid = current->suid; - if (!capable(CAP_SETUID)) { + + if (!capable(CAP_SETUID)) { if ((ruid != (uid_t) -1) && (ruid != current->uid) && (ruid != current->euid) && (ruid != current->suid)) return -EPERM; @@ -486,10 +485,9 @@ asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) } if (ruid != (uid_t) -1) { /* See above commentary about NPROC rlimit issues here. */ - charge_uid(current, -1); + free_uid(current); current->uid = ruid; - if(ruid) - charge_uid(current, 1); + alloc_uid(current); } if (euid != (uid_t) -1) { if (euid != current->euid) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 0803820ec..bd237cd8f 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -239,6 +239,7 @@ unsigned long __get_free_pages(int gfp_mask, unsigned long order) goto nopage; if (gfp_mask & __GFP_WAIT) { + __check_locks(1); if (in_interrupt()) { static int count = 0; if (++count < 5) { diff --git a/net/core/dev.c b/net/core/dev.c index a17baa52f..316f6d799 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -808,7 +808,7 @@ void net_bh(void) while (!skb_queue_empty(&backlog)) { - struct sk_buff * skb = backlog.next; + struct sk_buff * skb; /* Give chance to other bottom halves to run */ if (jiffies - start_time > 1) @@ -817,9 +817,7 @@ void net_bh(void) /* * We have a packet. Therefore the queue has shrunk */ - cli(); - __skb_unlink(skb, &backlog); - sti(); + skb = skb_dequeue(&backlog); #ifdef CONFIG_CPU_IS_SLOW if (ave_busy > 128*16) { diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index 0c4cc7f5a..e3025334d 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c @@ -178,6 +178,11 @@ unx_marshal(struct rpc_task *task, u32 *p, int ruid) base = p++; *p++ = htonl(jiffies/HZ); #ifndef DONT_FILLIN_HOSTNAME + /* + * Problem: The UTS name could change under us. We can't lock + * here to handle this. On the other hand we can't really + * go building a bad RPC! + */ if ((n = strlen((char *) system_utsname.nodename)) > UNX_MAXNODENAME) n = UNX_MAXNODENAME; *p++ = htonl(n); diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 2ce8903f5..8caaa46e8 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -176,6 +176,21 @@ rpc_make_runnable(struct rpc_task *task) task->tk_flags |= RPC_TASK_RUNNING; } + +/* + * For other people who may need to wake the I/O daemon + * but should (for now) know nothing about its innards + */ + +void rpciod_wake_up(void) +{ + if(rpciod_pid==0) + { + printk(KERN_ERR "rpciod: wot no daemon?\n"); + } + wake_up(&rpciod_idle); +} + /* * Prepare for sleeping on a wait queue. * By always appending tasks to the list we ensure FIFO behavior. @@ -795,6 +810,7 @@ rpciod(void *ptr) dprintk("RPC: rpciod back to sleep\n"); interruptible_sleep_on(&rpciod_idle); dprintk("RPC: switch to rpciod\n"); + rpciod_tcp_dispatcher(); rounds = 0; } restore_flags(oldflags); diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index da3e61c64..e2af81be4 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -324,6 +324,12 @@ xprt_close(struct rpc_xprt *xprt) fput(xprt->file); else sock_release(xprt->sock); + /* + * TCP doesnt require the rpciod now - other things may + * but rpciod handles that not us. + */ + if(xprt->stream) + rpciod_down(); } /* @@ -700,19 +706,17 @@ done: static struct rpc_xprt *rpc_xprt_pending = NULL; /* Chain by rx_pending of rpc_xprt's */ -static struct tq_struct rpc_tcp_tqueue = { 0, 0, 0, 0 }; - - /* - * This is protected from tcp_data_ready by the bh atomicity guarantees + * This is protected from tcp_data_ready and the stack as its run + * inside of the RPC I/O daemon */ -static void tcp_rpc_bh_run(void) +void rpciod_tcp_dispatcher(void) { struct rpc_xprt *xprt; int result; - dprintk("tcp_rpc_bh_run: Queue Running\n"); + dprintk("rpciod_tcp_dispatcher: Queue Running\n"); /* * Empty each pending socket @@ -725,7 +729,7 @@ static void tcp_rpc_bh_run(void) rpc_xprt_pending=xprt->rx_pending; xprt->rx_pending_flag=0; - dprintk("tcp_rpc_run_bh: Processing %p\n", xprt); + dprintk("rpciod_tcp_dispatcher: Processing %p\n", xprt); do { @@ -750,12 +754,9 @@ static void tcp_rpc_bh_run(void) } -static void tcp_rpc_bh_queue(void) +extern inline void tcp_rpciod_queue(void) { - rpc_tcp_tqueue.routine=(void *)(void *)tcp_rpc_bh_run; - queue_task(&rpc_tcp_tqueue, &tq_immediate); - dprintk("RPC: tcp_rpc_bh_queue: immediate op queued\n"); - mark_bh(IMMEDIATE_BH); + rpciod_wake_up(); } /* @@ -787,7 +788,7 @@ static void tcp_data_ready(struct sock *sk, int len) { dprintk("RPC: xprt queue\n"); if(rpc_xprt_pending==NULL) - tcp_rpc_bh_queue(); + tcp_rpciod_queue(); xprt->rx_pending_flag=1; xprt->rx_pending=rpc_xprt_pending; rpc_xprt_pending=xprt; @@ -1279,6 +1280,12 @@ xprt_setup(struct socket *sock, int proto, xprt->free = xprt->slot; dprintk("RPC: created transport %p\n", xprt); + + /* + * TCP requires the rpc I/O daemon is present + */ + if(proto==IPPROTO_TCP) + rpciod_up(); return xprt; } -- 2.11.4.GIT