1 diff -urN a/CREDITS b/CREDITS
11 +D: Various kernel patches
15 E: tim_alpaerts@toyota-motor-europe.com
16 D: 802.2 class II logical link control layer,
17 diff -urN a/Makefile b/Makefile
21 AS = $(CROSS_COMPILE)as
22 LD = $(CROSS_COMPILE)ld
23 CC = $(CROSS_COMPILE)gcc
25 +CC = $(CORSS_COMPILE)$(COLINUX_ROOT)/bin/tracewrapper.py gcc
27 +CC = $(CROSS_COMPILE)gcc
30 AR = $(CROSS_COMPILE)ar
31 NM = $(CROSS_COMPILE)nm
32 diff -urN a/arch/i386/Kconfig b/arch/i386/Kconfig
33 --- a/arch/i386/Kconfig
34 +++ b/arch/i386/Kconfig
38 bool "Pentium-Classic"
39 + depends on !COOPERATIVE
41 Select this for a Pentium Classic processor with the RDTSC (Read
42 Time Stamp Counter) instruction for benchmarking.
44 If you have a system with several CPUs, you do not need to say Y
45 here: the IO-APIC will be used automatically.
48 + bool 'Cooperative PIC (COPIC) support'
49 + depends on COOPERATIVE
53 depends on !SMP && X86_UP_APIC
58 - depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2) && !X86_NUMAQ
59 + depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2) && !X86_NUMAQ && !COOPERATIVE
65 source kernel/power/Kconfig
68 + bool 'Cooperative Mode'
71 source "drivers/acpi/Kconfig"
73 menu "APM (Advanced Power Management) BIOS Support"
74 diff -urN a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
75 --- a/arch/i386/kernel/Makefile
76 +++ b/arch/i386/kernel/Makefile
78 obj-$(CONFIG_X86_MSR) += msr.o
79 obj-$(CONFIG_X86_CPUID) += cpuid.o
80 obj-$(CONFIG_MICROCODE) += microcode.o
81 +obj-$(CONFIG_COOPERATIVE) += cooperative.o
82 obj-$(CONFIG_APM) += apm.o
83 obj-$(CONFIG_X86_SMP) += smp.o smpboot.o
84 obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o
85 diff -urN a/arch/i386/kernel/cooperative.c b/arch/i386/kernel/cooperative.c
86 --- a/arch/i386/kernel/cooperative.c
87 +++ b/arch/i386/kernel/cooperative.c
89 +#include <linux/kernel.h>
90 +#include <linux/string.h>
91 +#include <linux/interrupt.h>
92 +#include <linux/mm.h>
94 +#include <linux/cooperative_internal.h>
95 +#include <asm/cooperative_internal.h>
97 +#include <asm/desc.h>
98 +#include <asm/mmu_context.h>
99 +#include <asm/debugreg.h>
100 +#include <asm/i387.h>
106 + * The next asm code is the first Linux code that runs in the
107 + * coLinux kernel context. It receives %ecx which contains the
108 + * address of the passage page. The passage page code sets %ecx
109 + * to this value in its context restore part.
115 + ".globl co_start\n"
117 + " call co_start_arch\n"
121 +static int co_passage_page_holding_count = 0;
123 +static void co_early_cpu_init(void)
126 + * On the first switch to Linux we must set up a valid TR because
127 + * the passage page code assumes such one exists. This is basically
128 + * copied code from cpu_init().
130 + * P.S this is protected by CO_TRACE_STOP so that we don't
131 + * have a monitor context switch.
133 + int cpu = smp_processor_id();
134 + struct tss_struct * t = &per_cpu(init_tss, cpu);
135 + struct thread_struct *thread = ¤t->thread;
138 + * Initialize the per-CPU GDT with the boot GDT,
139 + * and set up the GDT descriptor:
141 + memcpy(&per_cpu(cpu_gdt_table, cpu), cpu_gdt_table, GDT_SIZE);
142 + cpu_gdt_descr[cpu].size = GDT_SIZE - 1;
143 + cpu_gdt_descr[cpu].address = (unsigned long)&per_cpu(cpu_gdt_table, cpu);
146 + * Set up the per-thread TLS descriptor cache:
148 + memcpy(thread->tls_array, &per_cpu(cpu_gdt_table, cpu), GDT_ENTRY_TLS_ENTRIES * 8);
150 + __asm__ __volatile__("lgdt %0" : : "m" (cpu_gdt_descr[cpu]));
151 + __asm__ __volatile__("lidt %0" : : "m" (idt_descr));
156 + __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
159 + * Set up and load the per-CPU TSS and LDT
161 + atomic_inc(&init_mm.mm_count);
162 + current->active_mm = &init_mm;
163 + enter_lazy_tlb(&init_mm, current);
165 + load_esp0(t, thread);
166 + set_tss_desc(cpu,t);
167 + per_cpu(cpu_gdt_table, cpu)[GDT_ENTRY_TSS].b &= 0xfffffdff;
171 + load_LDT(&init_mm.context);
173 + /* Set up doublefault TSS pointer in the GDT */
174 + __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss);
175 + per_cpu(cpu_gdt_table, cpu)[GDT_ENTRY_DOUBLEFAULT_TSS].b &= 0xfffffdff;
177 + /* Clear %fs and %gs. */
178 + asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
180 + __asm__ __volatile__("movl %%cr4, %0" : "=r" (mmu_cr4_features));
186 + ".globl co_arch_start_kernel\n"
187 + "co_arch_start_kernel:\n"
188 + " call co_startup_entry\n"
192 +void co_start_arch(void)
194 + co_early_cpu_init();
198 +extern void ctrl_alt_del(void);
200 +void co_handle_jiffies(long count)
202 + unsigned long flags;
203 + struct pt_regs regs;
206 + xtime.tv_sec += count / HZ;
207 + count -= ((count / HZ) * HZ);
210 + while (count > 0) {
211 + local_irq_save(flags);
212 + regs.orig_eax = TIMER_IRQ;
214 + local_irq_restore(flags);
220 +void co_handle_incoming_message(co_message_node_t *node_message)
222 + unsigned long flags;
223 + struct pt_regs regs;
224 + co_linux_message_t *message;
226 + message = (co_linux_message_t *)&node_message->msg.data;
228 + switch (message->device) {
229 + case CO_DEVICE_POWER: {
230 + co_linux_message_power_t *type = (co_linux_message_power_t *)message->data;
231 + switch (type->type) {
232 + case CO_LINUX_MESSAGE_POWER_ALT_CTRL_DEL: {
237 + co_free_message(node_message);
241 + case CO_DEVICE_KEYBOARD: {
242 + co_queue_incoming_message(node_message);
244 + local_irq_save(flags);
245 + regs.orig_eax = KEYBOARD_IRQ;
247 + local_irq_restore(flags);
251 + case CO_DEVICE_NETWORK: {
252 + co_queue_incoming_message(node_message);
254 + local_irq_save(flags);
255 + regs.orig_eax = NETWORK_IRQ;
257 + local_irq_restore(flags);
261 + case CO_DEVICE_SERIAL: {
262 + co_queue_incoming_message(node_message);
264 + local_irq_save(flags);
266 + local_irq_restore(flags);
271 + co_free_message(node_message);
276 +void co_switch_wrapper_protected(void)
278 + kernel_fpu_begin();
281 + * We don't trust the passage page code to safely restore %gs and %fs.
283 + * This wrapper ensures that if %fs or %gs are invalid, the processes
284 + * exits with a segmentation fault rather than bringing down the
287 + unsigned long fs = 0;
288 + unsigned long gs = 0;
290 + asm volatile("movl %%fs,%0": "=m" (fs));
291 + asm volatile("movl %%gs,%0": "=m" (gs));
294 + * Nullify the registers so the passage page code restores to
295 + * null segment values on return.
297 + asm volatile("movl %0, %%fs; movl %0, %%gs" : : "r" (0));
299 + /* And switch... */
303 + * Safely restore the registers.
305 + loadsegment(fs, fs);
306 + loadsegment(gs, gs);
311 +void co_switch_wrapper(void)
313 + /* taken from irq.c: debugging check for stack overflow */
316 + __asm__ __volatile__("andl %%esp,%0" : "=r" (esp) : "0" (THREAD_SIZE - 1));
317 + if (unlikely(esp < (sizeof(struct thread_info) + STACK_WARN))) {
318 + printk("co_switch_wrapper: stack overflow: %ld\n", esp - sizeof(struct thread_info));
319 + co_terminate(CO_TERMINATE_STACK_OVERFLOW);
322 + co_switch_wrapper_protected();
325 +void co_passage_page_acquire(unsigned long *flags)
327 + local_irq_save(*flags);
328 + co_passage_page_holding_count++;
331 +int co_passage_page_held(void)
333 + return co_passage_page_holding_count;
336 +void co_passage_page_release(unsigned long flags)
338 + co_passage_page_holding_count--;
339 + local_irq_restore(flags);
342 +void co_debug(const char *fmt, ...)
346 +#define MAX_TRACE_POINTS 1024
349 + unsigned char *code;
350 + unsigned char original_byte;
354 +co_tracepoint_t tracepoints[MAX_TRACE_POINTS];
355 +static int active_tracepoints = 0;
357 +void co_kernel_breakpoint(struct pt_regs * regs)
360 + unsigned char *code = (unsigned char *)regs->eip;
364 + for (i=0; i < active_tracepoints; i++) {
365 + if (tracepoints[i].code == code - 1) {
366 + co_debug("TRACEPOINT: %x\n", code - 1);
371 + if (i == active_tracepoints) {
372 + /* Bad, we don't know this tracepoint */
373 + co_terminate(CO_TERMINATE_INVALID_OPERATION);
377 + *tracepoints[i].code = tracepoints[i].original_byte;
378 + regs->eflags |= (1 << 8); /* Enable TF */
379 + regs->eip = (unsigned long)(code - 1);
380 + tracepoints[i].off = 1;
383 +void co_kernel_set_breakpoints(void)
387 + for (i=0; i < active_tracepoints; i++)
388 + if (tracepoints[i].code && tracepoints[i].off) {
389 + *tracepoints[i].code = 0xcc;
390 + tracepoints[i].off = 0;
394 +int co_kernel_debug(struct pt_regs *regs, long error_code, unsigned int condition)
396 + /* if not a single step trap */
397 + if (!(condition & DR_STEP))
404 + regs->eflags &= ~(1 << 8); /* Disable TF */
406 + co_kernel_set_breakpoints();
411 +void co_kernel_tracepoint_add(unsigned char *code)
413 + if (active_tracepoints >= MAX_TRACE_POINTS)
416 + tracepoints[active_tracepoints].code = code;
417 + tracepoints[active_tracepoints].original_byte = *code;
418 + tracepoints[active_tracepoints].off = 0;
419 + active_tracepoints++;
423 +co_arch_info_t co_arch_info = {
424 + .kernel_cs = __KERNEL_CS,
425 + .kernel_ds = __KERNEL_DS,
429 diff -urN a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
430 --- a/arch/i386/kernel/cpu/common.c
431 +++ b/arch/i386/kernel/cpu/common.c
433 #include <linux/smp.h>
434 #include <linux/module.h>
435 #include <linux/percpu.h>
436 +#include <linux/cooperative_internal.h>
437 #include <asm/semaphore.h>
438 #include <asm/processor.h>
439 #include <asm/i387.h>
440 @@ -570,11 +571,13 @@
442 /* Clear all 6 debug registers: */
444 + if (!cooperative_mode_enabled()) {
445 #define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) );
447 - CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7);
448 + CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7);
454 * Force FPU initialization:
455 diff -urN a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
456 --- a/arch/i386/kernel/entry.S
457 +++ b/arch/i386/kernel/entry.S
463 +ENTRY(ret_from_intr)
464 GET_THREAD_INFO(%ebp)
465 movl EFLAGS(%esp), %eax # mix EFLAGS and CS
467 diff -urN a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
468 --- a/arch/i386/kernel/head.S
469 +++ b/arch/i386/kernel/head.S
474 +ENTRY(co_startup_entry)
477 movl $-1,X86_CPUID # -1 for no CPUID initially
482 - .long init_thread_union+THREAD_SIZE
483 + .long init_thread_union+THREAD_SIZE-100
487 diff -urN a/arch/i386/kernel/i387.c b/arch/i386/kernel/i387.c
488 --- a/arch/i386/kernel/i387.c
489 +++ b/arch/i386/kernel/i387.c
491 #include <asm/user.h>
492 #include <asm/ptrace.h>
493 #include <asm/uaccess.h>
494 +#include <linux/cooperative_internal.h>
496 #ifdef CONFIG_MATH_EMULATION
497 #define HAVE_HWFP (boot_cpu_data.hard_math)
499 if (mask == 0) mask = 0x0000ffbf;
501 mxcsr_feature_mask &= mask;
503 + if (cooperative_mode_enabled())
515 * ptrace request handlers.
517 diff -urN a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
518 --- a/arch/i386/kernel/i8259.c
519 +++ b/arch/i386/kernel/i8259.c
521 #include <asm/i8259.h>
523 #include <linux/irq.h>
524 +#include <linux/cooperative_internal.h>
526 #include <io_ports.h>
528 +#ifdef CONFIG_COOPERATIVE
532 +void proxy_interrupt_handler(unsigned long interrupt, struct pt_regs regs)
534 + unsigned long flags;
536 + co_passage_page_acquire(&flags);
537 + co_passage_page->operation = CO_OPERATION_FORWARD_INTERRUPT;
538 + co_passage_page->params[0] = interrupt + 0x20;
539 + co_passage_page->params[1] = regs.eip;
540 + co_passage_page->params[2] = (unsigned long)(&((&interrupt)[10]));
541 + co_passage_page->host_state.flags &= ~(1 << 9); /* Turn IF off */
542 + co_switch_wrapper();
543 + co_callback(flags);
548 +#define IRQLIST_16(x) \
549 + IRQ(x,0) IRQ(x,1) IRQ(x,2) IRQ(x,3) \
550 + IRQ(x,4) IRQ(x,5) IRQ(x,6) IRQ(x,7) \
551 + IRQ(x,8) IRQ(x,9) IRQ(x,a) IRQ(x,b) \
552 + IRQ(x,c) IRQ(x,d) IRQ(x,e) IRQ(x,f)
554 +#define IRQLIST_224 \
555 + IRQLIST_16(0x0) IRQLIST_16(0x1) IRQLIST_16(0x2) IRQLIST_16(0x3) \
556 + IRQLIST_16(0x4) IRQLIST_16(0x5) IRQLIST_16(0x6) IRQLIST_16(0x7) \
557 + IRQLIST_16(0x8) IRQLIST_16(0x9) IRQLIST_16(0xa) IRQLIST_16(0xb) \
558 + IRQLIST_16(0xc) IRQLIST_16(0xd)
561 + extern asmlinkage void IRQ_proxy_##x##y##_interrupt(void);
567 + "\n"__ALIGN_STR"\n" \
568 + ".section .text\n" \
569 + ".globl IRQ_proxy_" #id "_interrupt\n" \
570 + "IRQ_proxy_" #id "_interrupt:\n" \
575 + "pushl %eax;\n\t" \
576 + "pushl %ebp;\n\t" \
577 + "pushl %edi;\n\t" \
578 + "pushl %esi;\n\t" \
579 + "pushl %edx;\n\t" \
580 + "pushl %ecx;\n\t" \
581 + "pushl %ebx;\n\t" \
582 + "movl $123, %edx;\n\t" \
583 + "movl %edx, %ds;\n\t" \
584 + "movl %edx, %es;\n\t" \
585 + "pushl $" #id "\n\t" \
586 + "call proxy_interrupt_handler\n\t" \
588 + "jmp ret_from_intr\n" \
592 +#define IRQ(x,y) BIRQ(x##y)
596 +#define IRQ(x,y) &IRQ_proxy_##x##y##_interrupt,
597 +void (*proxy_interrupt[NR_IRQS])(void) = {
608 * This is the 'legacy' 8259A Programmable Interrupt Controller,
609 * present in the majority of PC/AT boxes.
614 + if (cooperative_mode_enabled())
617 #ifdef CONFIG_X86_LOCAL_APIC
624 +#ifdef CONFIG_X86_UP_COPIC
627 + * Not like you have any other choice other than using
628 + * COPIC in Cooperative mode.
631 +static void end_COPIC_irq(unsigned int irq)
635 +#define shutdown_COPIC_irq disable_COPIC_irq
637 +static void mask_and_ack_COPIC(unsigned int irq)
641 +static unsigned int startup_COPIC_irq(unsigned int irq)
646 +void disable_COPIC_irq(unsigned int irq)
650 +void enable_COPIC_irq(unsigned int irq)
654 +static struct hw_interrupt_type co_pic_irq_type = {
657 + shutdown_COPIC_irq,
660 + mask_and_ack_COPIC,
665 +void __init init_COPIC_irqs(void)
669 + for (i = 0; i < NR_IRQS; i++) {
670 + irq_desc[i].status = IRQ_DISABLED;
671 + irq_desc[i].action = 0;
672 + irq_desc[i].depth = 1;
674 + irq_desc[i].handler = &co_pic_irq_type;
680 +#define init_COPIC_irqs() do {} while (0);
683 void __init init_IRQ(void)
687 /* all the set up before the call gates are initialised */
688 pre_intr_init_hook();
690 + if (cooperative_mode_enabled()) {
691 + printk("Setting proxy interrupt vectors\n");
695 + for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
696 + int vector = FIRST_EXTERNAL_VECTOR + i;
699 + if (vector != SYSCALL_VECTOR)
700 + set_intr_gate(vector, proxy_interrupt[i]);
707 * Cover the whole vector space, no vector can escape
708 * us. (some of these will be overridden and become
709 diff -urN a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c
710 --- a/arch/i386/kernel/ioport.c
711 +++ b/arch/i386/kernel/ioport.c
713 #include <linux/stddef.h>
714 #include <linux/slab.h>
715 #include <linux/thread_info.h>
716 +#include <linux/cooperative_internal.h>
718 /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
719 static void set_bitmap(unsigned long *bitmap, unsigned int base, unsigned int extent, int new_value)
721 struct tss_struct * tss;
722 unsigned long *bitmap;
724 + if (cooperative_mode_enabled())
727 if ((from + num <= from) || (from + num > IO_BITMAP_BITS))
729 if (turn_on && !capable(CAP_SYS_RAWIO))
731 unsigned int level = regs->ebx;
732 unsigned int old = (regs->eflags >> 12) & 3;
734 + if (cooperative_mode_enabled())
739 /* Trying to gain more privileges? */
740 diff -urN a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
741 --- a/arch/i386/kernel/process.c
742 +++ b/arch/i386/kernel/process.c
745 #include <linux/irq.h>
746 #include <linux/err.h>
747 +#include <linux/cooperative_internal.h>
749 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
751 @@ -147,21 +148,24 @@
752 /* endless idle loop with no priority at all */
754 while (!need_resched()) {
755 - void (*idle)(void);
757 - * Mark this as an RCU critical section so that
758 - * synchronize_kernel() in the unload path waits
759 - * for our completion.
763 + void (*idle)(void) = pm_idle;
766 + * Mark this as an RCU critical section so that
767 + * synchronize_kernel() in the unload path waits
768 + * for our completion.
772 + if (cooperative_mode_enabled())
773 + idle = co_idle_processor;
778 irq_stat[smp_processor_id()].idle_timestamp = jiffies;
785 diff -urN a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c
786 --- a/arch/i386/kernel/reboot.c
787 +++ b/arch/i386/kernel/reboot.c
789 #include <asm/uaccess.h>
790 #include <asm/apic.h>
791 #include "mach_reboot.h"
792 +#include <linux/cooperative_internal.h>
795 * Power off function, if any
800 + if (cooperative_mode_enabled()) {
801 + co_terminate(CO_TERMINATE_REBOOT);
807 /* Write zero to CMOS register number 0x0f, which the BIOS POST
811 #endif /* CONFIG_SMP */
816 + if (cooperative_mode_enabled()) {
817 + co_terminate(CO_TERMINATE_REBOOT);
821 #ifdef CONFIG_X86_IO_APIC
823 @@ -364,12 +375,18 @@
825 void machine_halt(void)
827 + co_terminate(CO_TERMINATE_HALT);
830 EXPORT_SYMBOL(machine_halt);
832 void machine_power_off(void)
834 + if (cooperative_mode_enabled()) {
835 + co_terminate(CO_TERMINATE_POWEROFF);
842 diff -urN a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
843 --- a/arch/i386/kernel/setup.c
844 +++ b/arch/i386/kernel/setup.c
846 #include <linux/efi.h>
847 #include <linux/init.h>
848 #include <linux/edd.h>
849 +#include <linux/cooperative_internal.h>
850 #include <video/edid.h>
851 #include <asm/e820.h>
852 #include <asm/mpspec.h>
857 - /* Save unparsed command line copy for /proc/cmdline */
858 - saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
859 + if (cooperative_mode_enabled()) {
861 + * Better to have 'root=/dev/cobd0' here.
863 + from = co_boot_parameters;
864 + snprintf(saved_command_line, COMMAND_LINE_SIZE, "%s",
865 + co_boot_parameters);
867 + /* Save unparsed command line copy for /proc/cmdline */
868 + saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
873 @@ -1019,6 +1029,8 @@
874 static unsigned long __init setup_memory(void)
876 unsigned long bootmap_size, start_pfn, max_low_pfn;
878 + unsigned long start_va = 0;
881 * partially used pages are not usable - thus
882 @@ -1026,9 +1038,16 @@
884 start_pfn = PFN_UP(init_pg_tables_end);
888 - max_low_pfn = find_max_low_pfn();
889 + if (cooperative_mode_enabled()) {
890 + max_low_pfn = max_pfn = co_memory_size / PAGE_SIZE;
891 + start_pfn = PFN_UP(__pa((unsigned long)&_end)) + 0x10;
892 + start_va = (unsigned long)__va(start_pfn << PAGE_SHIFT);
893 + co_alloc_pages(start_va, 0x20);
897 + max_low_pfn = find_max_low_pfn();
900 #ifdef CONFIG_HIGHMEM
901 highstart_pfn = highend_pfn = max_pfn;
902 @@ -1040,37 +1059,47 @@
904 printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
905 pages_to_mb(max_low_pfn));
907 - * Initialize the boot-time allocator (with low memory only):
909 - bootmap_size = init_bootmem(start_pfn, max_low_pfn);
911 - register_bootmem_low_pages(max_low_pfn);
914 - * Reserve the bootmem bitmap itself as well. We do this in two
915 - * steps (first step was init_bootmem()) because this catches
916 - * the (very unlikely) case of us accidentally initializing the
917 - * bootmem allocator with an invalid RAM area.
918 + * Initialize the boot-time allocator (with low memory only):
920 - reserve_bootmem(HIGH_MEMORY, (PFN_PHYS(start_pfn) +
921 - bootmap_size + PAGE_SIZE-1) - (HIGH_MEMORY));
922 + bootmap_size = init_bootmem(start_pfn, max_low_pfn);
925 - * reserve physical page 0 - it's a special BIOS page on many boxes,
926 - * enabling clean reboots, SMP operation, laptop functions.
928 - reserve_bootmem(0, PAGE_SIZE);
930 - /* reserve EBDA region, it's a 4K region */
931 - reserve_ebda_region();
932 + if (cooperative_mode_enabled()) {
933 + unsigned long bootmem_end = start_va + bootmap_size + (0x10 << PAGE_SHIFT);
934 + unsigned long physical_end = __PAGE_OFFSET + (max_low_pfn << PAGE_SHIFT);
936 + free_bootmem(__pa(bootmem_end), physical_end - bootmem_end);
938 + register_bootmem_low_pages(max_low_pfn);
941 + * Reserve the bootmem bitmap itself as well. We do this in two
942 + * steps (first step was init_bootmem()) because this catches
943 + * the (very unlikely) case of us accidentally initializing the
944 + * bootmem allocator with an invalid RAM area.
946 + reserve_bootmem(HIGH_MEMORY, (PFN_PHYS(start_pfn) +
947 + bootmap_size + PAGE_SIZE-1) - (HIGH_MEMORY));
950 + * reserve physical page 0 - it's a special BIOS page on many boxes,
951 + * enabling clean reboots, SMP operation, laptop functions.
953 + reserve_bootmem(0, PAGE_SIZE);
955 - /* could be an AMD 768MPX chipset. Reserve a page before VGA to prevent
956 - PCI prefetch into it (errata #56). Usually the page is reserved anyways,
957 - unless you have no PS/2 mouse plugged in. */
958 - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
959 - boot_cpu_data.x86 == 6)
960 - reserve_bootmem(0xa0000 - 4096, 4096);
961 + /* reserve EBDA region, it's a 4K region */
962 + reserve_ebda_region();
964 + /* could be an AMD 768MPX chipset. Reserve a page before VGA to prevent
965 + PCI prefetch into it (errata #56). Usually the page is reserved anyways,
966 + unless you have no PS/2 mouse plugged in. */
967 + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
968 + boot_cpu_data.x86 == 6)
969 + reserve_bootmem(0xa0000 - 4096, 4096);
974 @@ -1094,6 +1123,7 @@
977 #ifdef CONFIG_BLK_DEV_INITRD
978 +#ifndef CONFIG_COOPERATIVE
979 if (LOADER_TYPE && INITRD_START) {
980 if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
981 reserve_bootmem(INITRD_START, INITRD_SIZE);
982 @@ -1109,6 +1139,17 @@
987 + if (co_initrd != NULL) {
988 + printk(KERN_INFO "initrd enabled: start: 0x%x size: 0x%08lx)\n",
989 + (unsigned int)co_initrd, (long unsigned int)co_initrd_size);
991 + initrd_start = (unsigned long)co_initrd;
992 + initrd_end = (unsigned long)co_initrd + co_initrd_size;
994 + reserve_bootmem(virt_to_phys(co_initrd), co_initrd_size);
1000 @@ -1315,6 +1356,7 @@
1004 + boot_cpu_data.hard_math = 1;
1005 ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
1006 drive_info = DRIVE_INFO;
1007 screen_info = SCREEN_INFO;
1008 @@ -1338,7 +1380,7 @@
1013 + else if (!cooperative_mode_enabled()) {
1014 printk(KERN_INFO "BIOS-provided physical RAM map:\n");
1015 print_memory_map(machine_specific_memory_setup());
1017 @@ -1392,8 +1434,9 @@
1022 - dmi_scan_machine();
1023 + if (!cooperative_mode_enabled()) {
1024 + dmi_scan_machine();
1027 #ifdef CONFIG_X86_GENERICARCH
1028 generic_apic_probe(*cmdline_p);
1029 @@ -1411,9 +1454,14 @@
1033 - register_memory(max_low_pfn);
1034 + if (!cooperative_mode_enabled()) {
1035 + register_memory(max_low_pfn);
1039 +#ifdef CONFIG_COOPERATIVE_CONSOLE
1040 + conswitchp = &colinux_con;
1042 #if defined(CONFIG_VGA_CONSOLE)
1043 if (!efi_enabled || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
1044 conswitchp = &vga_con;
1045 @@ -1421,6 +1469,7 @@
1046 conswitchp = &dummy_con;
1052 #include "setup_arch_post.h"
1053 diff -urN a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c
1054 --- a/arch/i386/kernel/sysenter.c
1055 +++ b/arch/i386/kernel/sysenter.c
1057 #include <linux/gfp.h>
1058 #include <linux/string.h>
1059 #include <linux/elf.h>
1060 +#include <linux/cooperative_internal.h>
1062 #include <asm/cpufeature.h>
1063 #include <asm/msr.h>
1066 static int __init sysenter_setup(void)
1068 - void *page = (void *)get_zeroed_page(GFP_ATOMIC);
1069 + void *page = get_zeroed_page(GFP_ATOMIC);
1071 __set_fixmap(FIX_VSYSCALL, __pa(page), PAGE_READONLY_EXEC);
1073 - if (!boot_cpu_has(X86_FEATURE_SEP)) {
1074 + if (cooperative_mode_enabled() || !boot_cpu_has(X86_FEATURE_SEP)) {
1076 &vsyscall_int80_start,
1077 &vsyscall_int80_end - &vsyscall_int80_start);
1079 &vsyscall_sysenter_end - &vsyscall_sysenter_start);
1081 on_each_cpu(enable_sep_cpu, NULL, 1, 1);
1086 diff -urN a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
1087 --- a/arch/i386/kernel/time.c
1088 +++ b/arch/i386/kernel/time.c
1090 #include <linux/sysdev.h>
1091 #include <linux/bcd.h>
1092 #include <linux/efi.h>
1093 +#include <linux/cooperative_internal.h>
1096 #include <asm/smp.h>
1098 void do_gettimeofday(struct timeval *tv)
1101 - unsigned long usec, sec;
1102 - unsigned long max_ntp_tick;
1103 + unsigned long sec;
1105 + long max_ntp_tick;
1109 @@ -129,6 +131,13 @@
1113 + if (cooperative_mode_enabled()) {
1114 + while (usec < 0) {
1127 + if (cooperative_mode_enabled())
1130 /* gets recalled with irq locally disabled */
1131 spin_lock(&rtc_lock);
1134 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
1135 * called as close as possible to 500 ms before the new second starts.
1137 - if ((time_status & STA_UNSYNC) == 0 &&
1138 + if (!cooperative_mode_enabled() &&
1139 + (time_status & STA_UNSYNC) == 0 &&
1140 xtime.tv_sec > last_rtc_update + 660 &&
1141 (xtime.tv_nsec / 1000)
1142 >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
1145 unsigned long retval;
1147 + if (cooperative_mode_enabled())
1148 + return co_get_host_time();
1150 spin_lock(&rtc_lock);
1153 diff -urN a/arch/i386/kernel/timers/Makefile b/arch/i386/kernel/timers/Makefile
1154 --- a/arch/i386/kernel/timers/Makefile
1155 +++ b/arch/i386/kernel/timers/Makefile
1157 obj-$(CONFIG_X86_CYCLONE_TIMER) += timer_cyclone.o
1158 obj-$(CONFIG_HPET_TIMER) += timer_hpet.o
1159 obj-$(CONFIG_X86_PM_TIMER) += timer_pm.o
1160 +obj-$(CONFIG_COOPERATIVE) += timer_cooperative.o
1161 diff -urN a/arch/i386/kernel/timers/timer.c b/arch/i386/kernel/timers/timer.c
1162 --- a/arch/i386/kernel/timers/timer.c
1163 +++ b/arch/i386/kernel/timers/timer.c
1166 /* list of timers, ordered by preference, NULL terminated */
1167 static struct init_timer_opts* __initdata timers[] = {
1168 +#ifdef CONFIG_COOPERATIVE
1169 + &timer_cooperative_init,
1171 #ifdef CONFIG_X86_CYCLONE_TIMER
1172 &timer_cyclone_init,
1174 diff -urN a/arch/i386/kernel/timers/timer_cooperative.c b/arch/i386/kernel/timers/timer_cooperative.c
1175 --- a/arch/i386/kernel/timers/timer_cooperative.c
1176 +++ b/arch/i386/kernel/timers/timer_cooperative.c
1179 + * Cooperative mode timer.
1181 + * Dan Aloni <da-x@colinux.org>, 2003-2004 (C).
1184 +#include <linux/init.h>
1185 +#include <linux/errno.h>
1187 +#include <asm/timer.h>
1188 +#include <asm/cooperative.h>
1189 +#include <asm/div64.h>
1190 +#include <asm/param.h>
1192 +#include <linux/cooperative.h>
1193 +#include <linux/cooperative_internal.h>
1195 +static unsigned long long first_time;
1196 +static unsigned long frequencey;
1197 +static unsigned long long last_mark, last_mark_quotient;
1198 +static unsigned long long last_time;
1200 +static unsigned long long query_host_highprec_time(void)
1202 + unsigned long flags;
1203 + unsigned long long this_time;
1204 + unsigned long long diff;
1206 + co_passage_page_assert_valid();
1208 + co_passage_page_acquire(&flags);
1209 + co_passage_page->operation = CO_OPERATION_GET_HIGH_PREC_TIME;
1210 + co_switch_wrapper();
1212 + this_time = *(unsigned long long *)(&co_passage_page->params[0]);
1213 + frequencey = *(unsigned long *)(&co_passage_page->params[2]);
1214 + diff = ((long long)this_time - (long long)last_time);
1217 + * There shouldn't be any particularly large difference between
1218 + * the current and last host timestamps. For sanity, reset the
1219 + * global reference variables if we encounter any difference
1220 + * larger than one second.
1223 + if (diff < 0 || diff > frequencey) {
1224 + first_time = this_time;
1225 + last_mark_quotient = last_mark = 0;
1228 + last_time = this_time;
1229 + co_passage_page_release(flags);
1234 +static unsigned long long monotonic_clock_cooperative(void)
1239 +static long get_offset_cooperative(void)
1241 + unsigned long flags;
1243 + local_irq_save(flags);
1245 + unsigned long long this_time = query_host_highprec_time() - first_time;
1246 + unsigned long reminder = 0, result;
1247 + long long diff, lldiff;
1248 + long signed_result;
1250 + diff = ((long long)this_time - (long long)(last_mark));
1256 + lldiff *= 1000000;
1257 + result = div_ll_X_l_rem(lldiff, frequencey, &reminder);
1259 + signed_result = result;
1261 + signed_result = -signed_result;
1263 + local_irq_restore(flags);
1264 + return signed_result;
1267 +static void mark_offset_cooperative(void)
1269 + unsigned long flags;
1270 + local_irq_save(flags);
1272 + last_mark += frequencey / HZ;
1273 + last_mark_quotient += frequencey % HZ;
1274 + if (frequencey > HZ) {
1276 + last_mark_quotient -= HZ;
1279 + local_irq_restore(flags);
1282 +static void delay_cooperative(unsigned long loops)
1285 + * A bogos delay loop for creating BogoMIPS...
1288 + loops = loops / 10000;
1290 + query_host_highprec_time();
1295 +static int __init init_cooperative_timer(char* override)
1297 + first_time = query_host_highprec_time();
1299 + /* Always pick this timer */
1303 +/************************************************************/
1305 +/* tsc timer_opts struct */
1306 +struct timer_opts timer_cooperative = {
1307 + .name = "cooperative",
1308 + .mark_offset = mark_offset_cooperative,
1309 + .get_offset = get_offset_cooperative,
1310 + .monotonic_clock = monotonic_clock_cooperative,
1311 + .delay = delay_cooperative,
1314 +struct init_timer_opts __initdata timer_cooperative_init = {
1315 + .init = init_cooperative_timer,
1316 + .opts = &timer_cooperative,
1318 diff -urN a/arch/i386/kernel/timers/timer_cyclone.c b/arch/i386/kernel/timers/timer_cyclone.c
1319 --- a/arch/i386/kernel/timers/timer_cyclone.c
1320 +++ b/arch/i386/kernel/timers/timer_cyclone.c
1325 -static unsigned long get_offset_cyclone(void)
1326 +static long get_offset_cyclone(void)
1330 diff -urN a/arch/i386/kernel/timers/timer_hpet.c b/arch/i386/kernel/timers/timer_hpet.c
1331 --- a/arch/i386/kernel/timers/timer_hpet.c
1332 +++ b/arch/i386/kernel/timers/timer_hpet.c
1334 return base + cycles_2_ns(this_offset - last_offset);
1337 -static unsigned long get_offset_hpet(void)
1338 +static long get_offset_hpet(void)
1340 register unsigned long eax, edx;
1342 diff -urN a/arch/i386/kernel/timers/timer_none.c b/arch/i386/kernel/timers/timer_none.c
1343 --- a/arch/i386/kernel/timers/timer_none.c
1344 +++ b/arch/i386/kernel/timers/timer_none.c
1346 /* nothing needed */
1349 -static unsigned long get_offset_none(void)
1350 +static long get_offset_none(void)
1354 diff -urN a/arch/i386/kernel/timers/timer_pit.c b/arch/i386/kernel/timers/timer_pit.c
1355 --- a/arch/i386/kernel/timers/timer_pit.c
1356 +++ b/arch/i386/kernel/timers/timer_pit.c
1358 * comp.protocols.time.ntp!
1361 -static unsigned long get_offset_pit(void)
1362 +static long get_offset_pit(void)
1365 unsigned long flags;
1366 diff -urN a/arch/i386/kernel/timers/timer_pm.c b/arch/i386/kernel/timers/timer_pm.c
1367 --- a/arch/i386/kernel/timers/timer_pm.c
1368 +++ b/arch/i386/kernel/timers/timer_pm.c
1370 * get the offset (in microseconds) from the last call to mark_offset()
1371 * - Called holding a reader xtime_lock
1373 -static unsigned long get_offset_pmtmr(void)
1374 +static long get_offset_pmtmr(void)
1376 u32 now, offset, delta = 0;
1378 diff -urN a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
1379 --- a/arch/i386/kernel/timers/timer_tsc.c
1380 +++ b/arch/i386/kernel/timers/timer_tsc.c
1383 static unsigned long fast_gettimeoffset_quotient;
1385 -static unsigned long get_offset_tsc(void)
1386 +static long get_offset_tsc(void)
1388 register unsigned long eax, edx;
1390 diff -urN a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
1391 --- a/arch/i386/kernel/traps.c
1392 +++ b/arch/i386/kernel/traps.c
1394 #include <asm/arch_hooks.h>
1395 #include <asm/kdebug.h>
1397 +#include <linux/cooperative_internal.h>
1398 +#include <asm/cooperative_internal.h>
1400 #include <linux/irq.h>
1401 #include <linux/module.h>
1403 @@ -382,6 +385,12 @@
1407 + if (cooperative_mode_enabled()) {
1408 + if (trapnr == 3) {
1409 + co_kernel_breakpoint(regs);
1413 if (!fixup_exception(regs))
1414 die(str, regs, error_code);
1416 @@ -683,9 +692,15 @@
1417 unsigned int condition;
1418 struct task_struct *tsk = current;
1422 __asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
1424 + if (cooperative_mode_enabled() &&
1425 + co_kernel_debug(regs, error_code, condition))
1430 if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
1431 SIGTRAP) == NOTIFY_STOP)
1433 diff -urN a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
1434 --- a/arch/i386/kernel/vmlinux.lds.S
1435 +++ b/arch/i386/kernel/vmlinux.lds.S
1438 . = __PAGE_OFFSET + 0x100000;
1440 + _kernel_start = . ;
1441 _text = .; /* Text and read-only data */
1450 diff -urN a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
1451 --- a/arch/i386/mm/fault.c
1452 +++ b/arch/i386/mm/fault.c
1454 printk(KERN_ALERT " printing eip:\n");
1455 printk("%08lx\n", regs->eip);
1456 asm("movl %%cr3,%0":"=r" (page));
1457 - page = ((unsigned long *) __va(page))[address >> 22];
1458 + page = ((unsigned long *) __va(CO_P_TO_PP(page)))[address >> 22];
1459 + page = CO_P_TO_PP(page);
1460 printk(KERN_ALERT "*pde = %08lx\n", page);
1462 * We must not directly access the pte in the highpte
1465 address &= 0x003ff000;
1466 page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
1467 + page = CO_P_TO_PP(page);
1468 printk(KERN_ALERT "*pte = %08lx\n", page);
1474 asm("movl %%cr3,%0":"=r" (pgd_paddr));
1475 - pgd = index + (pgd_t *)__va(pgd_paddr);
1476 + pgd = index + (pgd_t *)__va(CO_P_TO_PP((unsigned long)pgd_paddr));
1477 pgd_k = init_mm.pgd + index;
1479 if (!pgd_present(*pgd_k))
1480 diff -urN a/arch/i386/mm/init.c b/arch/i386/mm/init.c
1481 --- a/arch/i386/mm/init.c
1482 +++ b/arch/i386/mm/init.c
1484 #include <linux/slab.h>
1485 #include <linux/proc_fs.h>
1486 #include <linux/efi.h>
1487 +#include <linux/cooperative_internal.h>
1489 #include <asm/processor.h>
1490 #include <asm/system.h>
1493 if (pmd_none(*pmd)) {
1494 pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
1495 - set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
1496 + set_pmd(pmd, __pmd(CO_PP_TO_P(__pa(page_table)) | _PAGE_TABLE));
1497 if (page_table != pte_offset_kernel(pmd, 0))
1500 @@ -313,21 +314,23 @@
1501 set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT));
1504 - /* Enable PSE if available */
1505 - if (cpu_has_pse) {
1506 - set_in_cr4(X86_CR4_PSE);
1509 - /* Enable PGE if available */
1510 - if (cpu_has_pge) {
1511 - set_in_cr4(X86_CR4_PGE);
1512 - __PAGE_KERNEL |= _PAGE_GLOBAL;
1513 - __PAGE_KERNEL_EXEC |= _PAGE_GLOBAL;
1514 + if (!cooperative_mode_enabled()) {
1515 + /* Enable PSE if available */
1516 + if (cpu_has_pse) {
1517 + set_in_cr4(X86_CR4_PSE);
1520 + /* Enable PGE if available */
1521 + if (cpu_has_pge) {
1522 + set_in_cr4(X86_CR4_PGE);
1523 + __PAGE_KERNEL |= _PAGE_GLOBAL;
1524 + __PAGE_KERNEL_EXEC |= _PAGE_GLOBAL;
1527 + kernel_physical_mapping_init(pgd_base);
1531 - kernel_physical_mapping_init(pgd_base);
1535 * Fixed mappings, only the page table structure has to be
1536 * created - mappings will be set by set_fixmap():
1537 @@ -394,19 +397,26 @@
1538 unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
1539 unsigned int max_dma, high, low;
1541 - max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
1542 - low = max_low_pfn;
1543 - high = highend_pfn;
1545 - if (low < max_dma)
1546 - zones_size[ZONE_DMA] = low;
1548 - zones_size[ZONE_DMA] = max_dma;
1549 - zones_size[ZONE_NORMAL] = low - max_dma;
1550 + if (!cooperative_mode_enabled()) {
1551 + max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
1552 + low = max_low_pfn;
1553 + high = highend_pfn;
1555 + if (low < max_dma)
1556 + zones_size[ZONE_DMA] = low;
1558 + zones_size[ZONE_DMA] = max_dma;
1559 + zones_size[ZONE_NORMAL] = low - max_dma;
1560 #ifdef CONFIG_HIGHMEM
1561 - zones_size[ZONE_HIGHMEM] = high - low;
1562 + zones_size[ZONE_HIGHMEM] = high - low;
1566 + zones_size[ZONE_DMA] = 0;
1567 + zones_size[ZONE_NORMAL] = max_low_pfn;
1568 + zones_size[ZONE_HIGHMEM] = 0;
1571 free_area_init(zones_size);
1579 bad_ppro = ppro_with_ram_bug();
1581 #ifdef CONFIG_HIGHMEM
1582 @@ -630,8 +639,10 @@
1584 panic("cannot execute a PAE-enabled kernel on a PAE-less CPU!");
1586 - if (boot_cpu_data.wp_works_ok < 0)
1588 + if (!cooperative_mode_enabled()) {
1589 + if (boot_cpu_data.wp_works_ok < 0)
1594 * Subtle. SMP is doing it's boot stuff late (because it has to
1595 diff -urN a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
1596 --- a/arch/i386/mm/ioremap.c
1597 +++ b/arch/i386/mm/ioremap.c
1599 #include <linux/vmalloc.h>
1600 #include <linux/init.h>
1601 #include <linux/slab.h>
1602 +#include <linux/cooperative_internal.h>
1604 #include <asm/fixmap.h>
1605 #include <asm/cacheflush.h>
1606 @@ -190,7 +191,14 @@
1607 void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size)
1609 unsigned long last_addr;
1610 - void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD);
1613 + if (cooperative_mode_enabled()) {
1614 + panic("ioremap_nocache %ld:%ld\n", phys_addr, size);
1618 + p = __ioremap(phys_addr, size, _PAGE_PCD);
1622 diff -urN a/drivers/block/Kconfig b/drivers/block/Kconfig
1623 --- a/drivers/block/Kconfig
1624 +++ b/drivers/block/Kconfig
1625 @@ -358,6 +358,15 @@
1626 "real" root file system, etc. See <file:Documentation/initrd.txt>
1629 +config BLK_DEV_COBD
1630 + tristate 'Cooperative block device support'
1632 + depends on COOPERATIVE=y
1634 + Virtual block device support for cooperative kernels.
1638 config INITRAMFS_SOURCE
1639 string "Source directory of cpio_list"
1641 diff -urN a/drivers/block/Makefile b/drivers/block/Makefile
1642 --- a/drivers/block/Makefile
1643 +++ b/drivers/block/Makefile
1645 obj-$(CONFIG_ATARI_SLM) += acsi_slm.o
1646 obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o
1647 obj-$(CONFIG_BLK_DEV_RAM) += rd.o
1648 +obj-$(CONFIG_BLK_DEV_COBD) += cobd.o
1649 obj-$(CONFIG_BLK_DEV_LOOP) += loop.o
1650 obj-$(CONFIG_BLK_DEV_PS2) += ps2esdi.o
1651 obj-$(CONFIG_BLK_DEV_XD) += xd.o
1652 diff -urN a/drivers/block/cobd.c b/drivers/block/cobd.c
1653 --- a/drivers/block/cobd.c
1654 +++ b/drivers/block/cobd.c
1657 + * Copyright (C) 2003 Dan Aloni <da-x@colinux.org>
1659 + * Cooperative Linux Block Device implementation
1662 +#include <linux/major.h>
1663 +#include <linux/config.h>
1664 +#include <linux/module.h>
1665 +#include <linux/init.h>
1666 +#include <linux/fs.h>
1667 +#include <linux/errno.h>
1668 +#include <linux/major.h>
1669 +#include <linux/stat.h>
1670 +#include <linux/slab.h>
1671 +#include <linux/bio.h>
1672 +#include <linux/blkdev.h>
1673 +#include <linux/cooperative_internal.h>
1674 +#include <linux/file.h>
1675 +#include <linux/ioctl.h>
1676 +#include <linux/ctype.h>
1678 +#include <asm/uaccess.h>
1679 +#include <asm/types.h>
1681 +#include <linux/devfs_fs_kernel.h>
1683 +#define PBD_BLOCK_SIZE 512
1685 +static int hardsect_size = 512;
1686 +static int hardsect_size_shift = 9;
1687 +static spinlock_t cobd_lock = SPIN_LOCK_UNLOCKED;
1688 +static int cobd_max;
1690 +struct cobd_device {
1693 + struct block_device *device;
1696 +static int cobd_request(struct cobd_device *cobd, co_block_request_type_t type, co_block_request_t *out_request)
1698 + co_block_request_t *request;
1699 + unsigned long flags;
1702 + co_passage_page_assert_valid();
1704 + co_passage_page_acquire(&flags);
1705 + co_passage_page->operation = CO_OPERATION_DEVICE;
1706 + co_passage_page->params[0] = CO_DEVICE_BLOCK;
1707 + co_passage_page->params[1] = cobd->unit;
1708 + request = (co_block_request_t *)&co_passage_page->params[2];
1709 + request->type = type;
1711 + co_switch_wrapper();
1713 + *out_request = *request;
1714 + co_passage_page_release(flags);
1719 +static int cobd_stat(struct cobd_device *cobd, co_block_request_t *out_request)
1721 + return cobd_request(cobd, CO_BLOCK_STAT, out_request);
1724 +static int cobd_get_alias(struct cobd_device *cobd, co_block_request_t *out_request)
1726 + return cobd_request(cobd, CO_BLOCK_GET_ALIAS, out_request);
1729 +static int cobd_ioctl(struct inode * inode, struct file * file,
1730 + unsigned int cmd, unsigned long arg)
1732 + return -ENOTTY; /* unknown command */
1735 +static int cobd_open(struct inode *inode, struct file *file)
1737 + struct cobd_device *cobd = (struct cobd_device *)(inode->i_bdev->bd_disk->private_data);
1738 + co_block_request_t *co_request;
1739 + co_block_request_t stat_request;
1740 + unsigned long flags;
1743 + if (cobd->device && cobd->device != inode->i_bdev)
1746 + if (cobd_stat(cobd, &stat_request))
1751 + co_passage_page_assert_valid();
1753 + co_passage_page_acquire(&flags);
1754 + co_passage_page->operation = CO_OPERATION_DEVICE;
1755 + co_passage_page->params[0] = CO_DEVICE_BLOCK;
1756 + co_passage_page->params[1] = cobd->unit;
1757 + co_request = (co_block_request_t *)&co_passage_page->params[2];
1758 + co_request->type = CO_BLOCK_OPEN;
1759 + co_switch_wrapper();
1760 + if (co_request->rc)
1764 + co_passage_page_release(flags);
1769 + if (cobd->refcount == 1) {
1770 + set_capacity(inode->i_bdev->bd_disk, stat_request.disk_size >> 9);
1771 + cobd->device = inode->i_bdev;
1777 +static int cobd_release(struct inode *inode, struct file *file)
1779 + struct cobd_device *cobd = (struct cobd_device *)(inode->i_bdev->bd_disk->private_data);
1780 + co_block_request_t *co_request;
1781 + unsigned long flags;
1784 + co_passage_page_assert_valid();
1786 + co_passage_page_acquire(&flags);
1787 + co_passage_page->operation = CO_OPERATION_DEVICE;
1788 + co_passage_page->params[0] = CO_DEVICE_BLOCK;
1789 + co_passage_page->params[1] = cobd->unit;
1790 + co_request = (co_block_request_t *)&co_passage_page->params[2];
1791 + co_request->type = CO_BLOCK_CLOSE;
1792 + co_switch_wrapper();
1793 + if (co_request->rc)
1796 + co_passage_page_release(flags);
1798 + if (cobd->refcount == 0)
1799 + cobd->device = NULL;
1805 + * Handle an I/O request.
1807 +static int cobd_transfer(struct cobd_device *cobd, unsigned long sector,
1808 + unsigned long nsect, char *buffer, int write)
1810 + co_block_request_t *co_request;
1811 + unsigned long flags;
1814 + co_passage_page_assert_valid();
1816 + co_passage_page_acquire(&flags);
1817 + co_passage_page->operation = CO_OPERATION_DEVICE;
1818 + co_passage_page->params[0] = CO_DEVICE_BLOCK;
1819 + co_passage_page->params[1] = cobd->unit;
1820 + co_request = (co_block_request_t *)&co_passage_page->params[2];
1822 + co_request->type = CO_BLOCK_READ;
1824 + co_request->type = CO_BLOCK_WRITE;
1825 + co_request->offset = ((unsigned long long)sector) << hardsect_size_shift;
1826 + co_request->size = nsect << hardsect_size_shift;
1827 + co_request->address = buffer;
1828 + co_request->rc = 0;
1829 + co_switch_wrapper();
1831 + if (!co_request->rc)
1834 + co_passage_page_release(flags);
1838 +static void do_cobd_request(request_queue_t *q)
1840 + struct request *req;
1841 + struct cobd_device *cobd;
1843 + while ((req = elv_next_request(q)) != NULL) {
1846 + if (!blk_fs_request(req)) {
1847 + end_request(req, 0);
1850 + cobd = (struct cobd_device *)(req->rq_disk->private_data);
1852 + ret = cobd_transfer(cobd, req->sector, req->current_nr_sectors,
1853 + req->buffer, rq_data_dir(req));
1854 + end_request(req, ret);
1858 +static struct block_device_operations cobd_fops = {
1859 + .owner = THIS_MODULE,
1860 + .open = cobd_open,
1861 + .release = cobd_release,
1862 + .ioctl = cobd_ioctl,
1865 +static struct gendisk **cobd_disks;
1867 +static struct cobd_device cobd_devs[CO_MODULE_MAX_COBD];
1869 +static int __init cobd_drives_init(void)
1873 + if (register_blkdev(COLINUX_MAJOR, "cobd")) {
1874 + printk(KERN_WARNING "Unable to get major number %d for cobd device\n", COLINUX_MAJOR);
1878 + cobd_max = CO_MODULE_MAX_COBD;
1880 + result = -ENOMEM; /* for the possible errors */
1882 + cobd_disks = kmalloc(cobd_max * sizeof(struct gendisk *), GFP_KERNEL);
1886 + for (i=0; i < cobd_max; i++) {
1887 + cobd_disks[i] = alloc_disk(1);
1888 + if (!cobd_disks[i])
1889 + goto fail_malloc3;
1892 + for (i=0; i < cobd_max; i++) {
1893 + struct cobd_device *cobd = &cobd_devs[i];
1894 + struct gendisk *disk = cobd_disks[i];
1896 + disk->queue = blk_init_queue(do_cobd_request, &cobd_lock);
1898 + goto fail_malloc4;
1900 + blk_queue_hardsect_size(disk->queue, hardsect_size);
1903 + disk->major = COLINUX_MAJOR;
1904 + disk->first_minor = i;
1905 + disk->fops = &cobd_fops;
1906 + sprintf(disk->disk_name, "cobd%d", i);
1907 + sprintf(disk->devfs_name, "cobd/%d", i);
1908 + disk->private_data = cobd;
1911 + devfs_mk_dir("cobd");
1913 + for (i=0; i < cobd_max; i++)
1914 + add_disk(cobd_disks[i]);
1916 + printk(KERN_INFO "cobd: loaded (max %d devices)\n", cobd_max);
1922 + blk_cleanup_queue(cobd_disks[i]->queue);
1923 + devfs_remove("cobd");
1928 + if (cobd_disks[i] != NULL)
1929 + put_disk(cobd_disks[i]);
1931 + kfree(cobd_disks);
1934 + if (unregister_blkdev(COLINUX_MAJOR, "cobd"))
1935 + printk(KERN_WARNING "cobd: cannot unregister blkdev\n");
1940 +struct cobd_alias_major {
1946 +struct cobd_alias {
1948 + struct cobd_alias_major *major;
1951 + struct gendisk **gendisk;
1954 +struct cobd_alias_major cobd_aliases_major_ide0 = {
1956 + .number = IDE0_MAJOR,
1959 +struct cobd_alias_major cobd_aliases_major_ide1 = {
1961 + .number = IDE1_MAJOR,
1964 +struct cobd_alias_major cobd_aliases_major_ide2 = {
1966 + .number = IDE2_MAJOR,
1969 +struct cobd_alias_major cobd_aliases_major_ide3 = {
1971 + .number = IDE3_MAJOR,
1974 +struct cobd_alias_major cobd_aliases_major_sd = {
1976 + .number = SCSI_DISK0_MAJOR,
1979 +struct cobd_alias cobd_aliases[] = {
1980 + {"hda", &cobd_aliases_major_ide0, 0x00, 21, },
1981 + {"hdb", &cobd_aliases_major_ide0, 0x40, 21, },
1982 + {"hdc", &cobd_aliases_major_ide1, 0x00, 21, },
1983 + {"hdd", &cobd_aliases_major_ide1, 0x40, 21, },
1984 + {"hde", &cobd_aliases_major_ide2, 0x00, 21, },
1985 + {"hdf", &cobd_aliases_major_ide2, 0x40, 21, },
1986 + {"hdg", &cobd_aliases_major_ide3, 0x00, 21, },
1987 + {"hdh", &cobd_aliases_major_ide3, 0x40, 21, },
1988 + {"sda", &cobd_aliases_major_sd, 0x00, 0x10, },
1989 + {"sdb", &cobd_aliases_major_sd, 0x10, 0x10, },
1990 + {"sdc", &cobd_aliases_major_sd, 0x20, 0x10, },
1991 + {"sdd", &cobd_aliases_major_sd, 0x30, 0x10, },
1992 + {"sde", &cobd_aliases_major_sd, 0x40, 0x10, },
1993 + {"sdf", &cobd_aliases_major_sd, 0x50, 0x10, },
1994 + {"sdg", &cobd_aliases_major_sd, 0x60, 0x10, },
1995 + {"sdh", &cobd_aliases_major_sd, 0x70, 0x10, },
1996 + {"sdi", &cobd_aliases_major_sd, 0x80, 0x10, },
1997 + {"sdj", &cobd_aliases_major_sd, 0x90, 0x10, },
1998 + {"sdk", &cobd_aliases_major_sd, 0xa0, 0x10, },
1999 + {"sdl", &cobd_aliases_major_sd, 0xb0, 0x10, },
2000 + {"sdm", &cobd_aliases_major_sd, 0xc0, 0x10, },
2001 + {"sdn", &cobd_aliases_major_sd, 0xd0, 0x10, },
2002 + {"sdp", &cobd_aliases_major_sd, 0xe0, 0x10, },
2003 + {"sdq", &cobd_aliases_major_sd, 0xf0, 0x10, },
2007 +static int __init skip_atoi(const char **s)
2009 + /* lib/spprintf.h */
2013 + while (isdigit(**s))
2014 + i = i*10 + *((*s)++) - '0';
2019 +static int __init cobd_spawn_alias(struct cobd_alias *alias,
2020 + const char *alias_name_requested,
2023 + const char *index_str_start = &alias_name_requested[strlen(alias->name)];
2024 + const char *index_str_end = index_str_start;
2025 + struct cobd_device *cobd;
2026 + struct gendisk *disk;
2028 + int index = skip_atoi(&index_str_end);
2030 + if (!((index >= 0) && (index <= alias->minor_count))) {
2031 + printk(KERN_WARNING "index out of bounds for alias %s (1 - %d)\n",
2032 + alias_name_requested, alias->minor_count);
2036 + if (alias->gendisk == NULL) {
2037 + static struct gendisk **gendisks;
2038 + gendisks = kmalloc(alias->minor_count * sizeof(struct gendisk *), GFP_KERNEL);
2039 + memset(gendisks, 0, alias->minor_count * sizeof(struct gendisk *));
2042 + printk(KERN_WARNING "cannot allocate gendisk array for %s\n", alias->name);
2046 + if (!alias->major->registered) {
2047 + if (register_blkdev(alias->major->number, alias->major->name)) {
2048 + printk(KERN_WARNING "unable to get major number %d for cobd alias device %s\n",
2049 + alias->major->number, alias_name_requested);
2054 + alias->major->registered = 1;
2057 + alias->gendisk = gendisks;
2058 + devfs_mk_dir(alias->name);
2061 + if (alias->gendisk[index] != NULL) {
2062 + printk(KERN_WARNING "alias %s already used\n", alias_name_requested);
2066 + disk = alloc_disk(1);
2068 + printk(KERN_WARNING "cannot allocate disk for alias %s\n", alias_name_requested);
2072 + disk->queue = blk_init_queue(do_cobd_request, &cobd_lock);
2073 + if (!disk->queue) {
2074 + printk(KERN_WARNING "cannot allocate init queue for alias %s\n", alias_name_requested);
2079 + cobd = &cobd_devs[cobd_unit];
2080 + blk_queue_hardsect_size(disk->queue, hardsect_size);
2081 + disk->major = alias->major->number;
2082 + disk->first_minor = alias->minor_start + index;
2083 + disk->fops = &cobd_fops;
2085 + sprintf(disk->disk_name, "%s%d", alias->name, index);
2087 + sprintf(disk->disk_name, "%s", alias->name);
2088 + sprintf(disk->devfs_name, "%s/%d", alias->name, index);
2089 + disk->private_data = cobd;
2091 + alias->gendisk[index] = disk;
2093 + printk("cobd alias cobd%d -> %s created\n", cobd_unit, alias_name_requested);
2098 +static int __init cobd_aliases_init(void)
2101 + co_block_request_t request;
2103 + for (unit=0; unit < cobd_max; unit++) {
2104 + int result = cobd_get_alias(&cobd_devs[unit], &request);
2108 + printk("alias for cobd%d is %s\n", unit, request.alias);
2110 + struct cobd_alias *alias = &cobd_aliases[0];
2111 + while (alias->name) {
2112 + const char *match = (strstr(request.alias, alias->name));
2113 + if (match == request.alias) {
2114 + cobd_spawn_alias(alias, request.alias, unit);
2120 + if (alias->name == NULL)
2121 + printk("alias %s is unknown (see cobd_aliases in cobd.c)\n", request.alias);
2127 +static void cobd_drives_exit(void)
2131 + for (i = 0; i < cobd_max; i++) {
2132 + blk_cleanup_queue(cobd_disks[i]->queue);
2133 + del_gendisk(cobd_disks[i]);
2134 + put_disk(cobd_disks[i]);
2137 + devfs_remove("cobd");
2138 + if (unregister_blkdev(COLINUX_MAJOR, "cobd"))
2139 + printk(KERN_WARNING "cobd: cannot unregister blkdev\n");
2141 + kfree(cobd_disks);
2144 +static void cobd_aliases_exit(void)
2146 + struct cobd_alias *alias = &cobd_aliases[0];
2147 + while (alias->name != NULL) {
2148 + if (alias->gendisk == NULL) {
2154 + for (index=0; index < alias->minor_count; index++) {
2155 + struct gendisk *disk = alias->gendisk[index];
2159 + blk_cleanup_queue(disk->queue);
2160 + del_gendisk(disk);
2164 + devfs_remove(alias->name);
2165 + if (!alias->major->registered) {
2166 + unregister_blkdev(alias->major->number, alias->major->name);
2167 + alias->major->registered = 0;
2169 + kfree(alias->gendisk);
2175 +static int __init cobd_init(void)
2177 + int result = cobd_drives_init();
2181 + cobd_aliases_init();
2186 +static void cobd_exit(void)
2188 + cobd_aliases_exit();
2189 + cobd_drives_exit();
2192 +module_init(cobd_init);
2193 +module_exit(cobd_exit);
2196 diff -urN a/drivers/char/Makefile b/drivers/char/Makefile
2197 --- a/drivers/char/Makefile
2198 +++ b/drivers/char/Makefile
2200 obj-$(CONFIG_STALLION) += stallion.o
2201 obj-$(CONFIG_ISTALLION) += istallion.o
2202 obj-$(CONFIG_DIGI) += pcxx.o
2203 +obj-$(CONFIG_COOPERATIVE) += cocd.o
2204 obj-$(CONFIG_DIGIEPCA) += epca.o
2205 obj-$(CONFIG_SPECIALIX) += specialix.o
2206 obj-$(CONFIG_MOXA_INTELLIO) += moxa.o
2207 diff -urN a/drivers/char/cocd.c b/drivers/char/cocd.c
2208 --- a/drivers/char/cocd.c
2209 +++ b/drivers/char/cocd.c
2212 + * Copyright (C) 2004 Dan Aloni <da-x@colinux.org>
2214 + * Cooperative Linux Serial Line implementation
2216 + * Compatible with UML, also based on some code from there.
2217 + * Also based on The tiny_tty.c example driver by Greg Kroah-Hartman (greg@kroah.com).
2221 + * 20040908: Ballard, Jonathan H. <jhballard@hotmail.com>
2222 + * : Implemented cocd_task() & throttle.
2223 + * 20041224: Used schedule() instead of shedule_work().
2224 + * 20050101: Uses interruptible_sleep_on() and wake_up() instead of schedule().
2225 + * : Uses list_*() for dispatched data flow to each unit.
2226 + * : Handles multiple units in seperate tasks.
2231 +#include <linux/major.h>
2232 +#include <linux/config.h>
2233 +#include <linux/module.h>
2234 +#include <linux/init.h>
2235 +#include <linux/fs.h>
2236 +#include <linux/errno.h>
2237 +#include <linux/major.h>
2238 +#include <linux/stat.h>
2239 +#include <linux/file.h>
2240 +#include <linux/ioctl.h>
2241 +#include <linux/device.h>
2242 +#include <linux/console.h>
2243 +#include <linux/wait.h>
2245 +#include <linux/workqueue.h>
2246 +#include <linux/devfs_fs_kernel.h>
2247 +#include <linux/tty.h>
2248 +#include <linux/tty_flip.h>
2250 +#include <linux/cooperative_internal.h>
2252 +#include <asm/uaccess.h>
2255 + struct semaphore sem; /* locks this structure */
2256 + struct tty_struct *tty; /* tty for this device */
2257 + unsigned open_count; /* open()/close() tally */
2258 + struct work_struct work; /* individual unit task */
2259 + struct list_head inq; /* input queue */
2260 + wait_queue_head_t waitq;
2261 + int throttled; /* data flow throttle bit */
2264 +static struct tty_driver *cocd_driver = NULL;
2265 +DECLARE_MUTEX(cocd_sem);
2267 +static void cocd_unit_task(void *data)
2269 + co_message_node_t *input;
2270 + struct cocd_tty *cocd = data;
2271 + co_linux_message_t *message;
2273 + struct tty_struct *tty;
2277 + while(cocd->open_count) {
2279 + if(list_empty(&cocd->inq)) {
2281 + interruptible_sleep_on(&cocd->waitq);
2284 + input = list_entry(cocd->inq.prev, co_message_node_t, node);
2287 + message = (co_linux_message_t *)&input->msg.data;
2288 + e = (m = p = message->data) + message->size;
2289 + while(p < e && cocd->open_count) {
2290 + if(cocd->throttled) {
2291 + interruptible_sleep_on(&cocd->waitq);
2294 + if(e < (m += (TTY_FLIPBUF_SIZE - tty->flip.count)))
2297 + tty_insert_flip_char(tty, *(p++), 0);
2298 + if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
2299 + tty_flip_buffer_push(tty);
2303 + list_del(&input->node);
2305 + co_free_message(input);
2306 + if(tty->flip.count && cocd->open_count) {
2307 + if(cocd->throttled) {
2308 + interruptible_sleep_on(&cocd->waitq);
2310 + tty_flip_buffer_push(tty);
2315 + while(!list_empty(&cocd->inq)) {
2316 + input = list_entry(cocd->inq.prev, co_message_node_t, node);
2317 + list_del(&input->node);
2318 + co_free_message(input);
2324 +int cocd_open(struct tty_struct *tty, struct file * filp)
2326 + struct cocd_tty *cocd = NULL;
2330 + /* MOD_INC_USE_COUNT; - Removed in 2.6, reference count is handled
2331 + * outside the module in 2.6
2334 + if ((cocd = (struct cocd_tty *)tty->driver_data)) {
2335 + down (&cocd->sem);
2337 + if(!(cocd = kmalloc(sizeof(*cocd), GFP_KERNEL))) {
2338 + /* MOD_DEC_USE_COUNT; - Removed in 2.6, reference count
2339 + * is handled outside the module in 2.6
2346 + init_MUTEX_LOCKED(&cocd->sem);
2347 + cocd->open_count = 0;
2349 + cocd->throttled = 0;
2350 + INIT_WORK(&cocd->work, cocd_unit_task, cocd);
2351 + INIT_LIST_HEAD(&cocd->inq);
2352 + init_waitqueue_head(&cocd->waitq);
2353 + tty->driver_data = cocd;
2354 + tty->low_latency = 1;
2355 + schedule_work(&cocd->work);
2358 + cocd->open_count++;
2366 +void cocd_close(struct tty_struct *tty, struct file * filp)
2368 + struct cocd_tty *cocd = NULL;
2372 + cocd = (struct cocd_tty *)tty->driver_data;
2374 + printk("cocd: no attached struct\n");
2379 + if (cocd->open_count == 1) { /* last close */
2380 + tty->driver_data = NULL;
2381 + wake_up(&cocd->waitq);
2383 + cocd->open_count--;
2387 + /* MOD_DEC_USE_COUNT; - Removed in 2.6, reference count is handled
2388 + * outside the module in 2.6
2394 +void cocd_interrupt(void)
2399 + co_message_node_t *input;
2400 + if(!co_get_message(&input, CO_DEVICE_SERIAL))
2405 + co_linux_message_t *message;
2406 + struct tty_struct *tty;
2407 + struct cocd_tty *cocd;
2408 + message = (co_linux_message_t *)&input->msg.data;
2410 + if (message->unit < CO_MODULE_MAX_SERIAL
2411 + && (tty = cocd_driver->ttys[message->unit])
2412 + && (cocd = (struct cocd_tty *)tty->driver_data)) {
2415 + list_add_tail(&input->node,&cocd->inq);
2417 + wake_up(&cocd->waitq);
2421 + co_free_message(input);
2424 +int cocd_write(struct tty_struct * tty,
2425 + const unsigned char *buf, int count)
2427 + const char *kbuf_scan = NULL;
2431 + count_left = count;
2433 + while (count_left > 0) {
2434 + int count_partial = count_left;
2435 + if (count_partial > 1000)
2436 + count_partial = 1000;
2438 + co_send_message(CO_MODULE_LINUX,
2439 + CO_MODULE_SERIAL0 + tty->index,
2440 + CO_PRIORITY_DISCARDABLE,
2441 + CO_MESSAGE_TYPE_STRING,
2445 + count_left -= count_partial;
2446 + kbuf_scan += count_partial;
2452 +int cocd_write_room(struct tty_struct *tty)
2454 + struct cocd_tty *cocd = NULL;
2456 + cocd = (struct cocd_tty *)tty->driver_data;
2461 + if (cocd->open_count == 0) {
2462 + /* port was not opened */
2471 +void cocd_hangup(struct tty_struct *tty)
2475 +void cocd_throttle(struct tty_struct * tty)
2477 + struct cocd_tty *cocd;
2478 + cocd = (struct cocd_tty *)tty->driver_data;
2482 + cocd->throttled = 1;
2486 +void cocd_unthrottle(struct tty_struct * tty)
2488 + struct cocd_tty *cocd;
2489 + cocd = (struct cocd_tty *)tty->driver_data;
2493 + cocd->throttled = 0;
2495 + wake_up(&cocd->waitq);
2498 +void cocd_flush_buffer(struct tty_struct *tty)
2502 +void cocd_set_termios(struct tty_struct *tty, struct termios *old_termios)
2506 +int cocd_chars_in_buffer(struct tty_struct *tty)
2511 +static struct tty_operations cocd_ops = {
2512 + .open = cocd_open,
2513 + .close = cocd_close,
2514 + .write = cocd_write,
2515 + .write_room = cocd_write_room,
2516 + .flush_buffer = cocd_flush_buffer,
2517 + .throttle = cocd_throttle,
2518 + .unthrottle = cocd_unthrottle,
2519 + .hangup = cocd_hangup,
2520 + .chars_in_buffer = cocd_chars_in_buffer,
2521 + .set_termios = cocd_set_termios,
2524 +static struct tty_driver *cocd_driver;
2526 +static void cocd_console_write(struct console *c, const char *string, unsigned len)
2530 +static struct tty_driver *cocd_console_device(struct console *c, int *index)
2532 + *index = c->index;
2533 + return cocd_driver;
2536 +static int cocd_console_setup(struct console *co, char *options)
2541 +static struct console cocd_cons = {
2543 + write: cocd_console_write,
2544 + device: cocd_console_device,
2545 + setup: cocd_console_setup,
2546 + flags: CON_PRINTBUFFER,
2550 +static int __init cocd_init(void)
2552 + cocd_driver = alloc_tty_driver(CO_MODULE_MAX_SERIAL);
2555 + panic("Couldn't allocate cocd driver");
2557 + cocd_driver->owner = THIS_MODULE;
2558 + cocd_driver->driver_name = "Cooperative serial lines";
2559 + cocd_driver->name = "ttS";
2560 + cocd_driver->devfs_name = "tts/";
2561 + cocd_driver->major = TTY_MAJOR;
2562 + cocd_driver->minor_start = 64;
2563 + cocd_driver->type = TTY_DRIVER_TYPE_SERIAL;
2564 + cocd_driver->subtype = 0;
2565 + cocd_driver->init_termios = tty_std_termios;
2566 + cocd_driver->flags = 0;
2568 + tty_set_operations(cocd_driver, &cocd_ops);
2570 + if (tty_register_driver(cocd_driver))
2571 + panic("Couldn't register cocd driver");
2573 + register_console(&cocd_cons);
2578 +module_init(cocd_init);
2579 diff -urN a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
2580 --- a/drivers/input/keyboard/Kconfig
2581 +++ b/drivers/input/keyboard/Kconfig
2584 depends on INPUT && INPUT_KEYBOARD
2586 - select SERIO_I8042 if PC
2587 + select SERIO_I8042 if PC && !COOPERATIVE
2588 select SERIO_GSCPS2 if GSC
2590 Say Y here if you want to use a standard AT or PS/2 keyboard. Usually
2591 diff -urN a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
2592 --- a/drivers/input/keyboard/atkbd.c
2593 +++ b/drivers/input/keyboard/atkbd.c
2595 #include <linux/input.h>
2596 #include <linux/serio.h>
2597 #include <linux/workqueue.h>
2598 +#include <linux/cooperative_internal.h>
2600 #define DRIVER_DESC "AT and PS/2 keyboard driver"
2604 unsigned char param[2];
2606 + if (cooperative_mode_enabled())
2610 * Some systems, where the bit-twiddling when testing the io-lines of the
2611 * controller may confuse the keyboard need a full reset of the keyboard. On
2612 diff -urN a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
2613 --- a/drivers/input/mouse/Kconfig
2614 +++ b/drivers/input/mouse/Kconfig
2617 tristate "PS/2 mouse"
2619 - depends on INPUT && INPUT_MOUSE
2620 + depends on INPUT && INPUT_MOUSE && !COOPERATIVE
2622 select SERIO_I8042 if PC
2623 select SERIO_GSCPS2 if GSC
2625 To compile this driver as a module, choose M here: the
2626 module will be called psmouse.
2628 +config MOUSE_COOPERATIVE
2629 + tristate "Cooperative Mouse driver"
2631 + depends on INPUT && INPUT_MOUSE && COOPERATIVE
2633 + Virtual mouse driver for cooperative kernels.
2637 + To compile this driver as a module, choose M here: the
2638 + module will be called psmouse.
2641 tristate "Serial mouse"
2642 - depends on INPUT && INPUT_MOUSE
2643 + depends on INPUT && INPUT_MOUSE && !COOPERATIVE
2646 Say Y here if you have a serial (RS-232, COM port) mouse connected
2650 tristate "InPort/MS/ATIXL busmouse"
2651 - depends on INPUT && INPUT_MOUSE && ISA
2652 + depends on INPUT && INPUT_MOUSE && ISA && !COOPERATIVE
2654 Say Y here if you have an InPort, Microsoft or ATI XL busmouse.
2655 They are rather rare these days.
2659 bool "ATI XL variant"
2660 - depends on MOUSE_INPORT
2661 + depends on MOUSE_INPORT && !COOPERATIVE
2663 Say Y here if your mouse is of the ATI XL variety.
2666 tristate "Logitech busmouse"
2667 - depends on INPUT && INPUT_MOUSE && ISA
2668 + depends on INPUT && INPUT_MOUSE && ISA && !COOPERATIVE
2670 Say Y here if you have a Logitech busmouse.
2671 They are rather rare these days.
2674 config MOUSE_PC110PAD
2675 tristate "IBM PC110 touchpad"
2676 - depends on INPUT && INPUT_MOUSE && ISA
2677 + depends on INPUT && INPUT_MOUSE && ISA && !COOPERATIVE
2679 Say Y if you have the IBM PC-110 micro-notebook and want its
2684 tristate "Maple bus mouse"
2685 - depends on SH_DREAMCAST && INPUT && INPUT_MOUSE && MAPLE
2686 + depends on SH_DREAMCAST && INPUT && INPUT_MOUSE && MAPLE && !COOPERATIVE
2688 Say Y if you have a DreamCast console and a mouse attached to
2693 tristate "Amiga mouse"
2694 - depends on AMIGA && INPUT && INPUT_MOUSE
2695 + depends on AMIGA && INPUT && INPUT_MOUSE && !COOPERATIVE
2697 Say Y here if you have an Amiga and want its native mouse
2698 supported by the kernel.
2702 tristate "Acorn RiscPC mouse"
2703 - depends on ARCH_ACORN && INPUT && INPUT_MOUSE
2704 + depends on ARCH_ACORN && INPUT && INPUT_MOUSE && !COOPERATIVE
2706 Say Y here if you have the Acorn RiscPC computer and want its
2707 native mouse supported.
2710 config MOUSE_VSXXXAA
2711 tristate "DEC VSXXX-AA/GA mouse and VSXXX-AB tablet"
2712 - depends on INPUT && INPUT_MOUSE
2713 + depends on INPUT && INPUT_MOUSE && !COOPERATIVE
2716 Say Y (or M) if you want to use a DEC VSXXX-AA (hockey
2717 diff -urN a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
2718 --- a/drivers/input/mouse/Makefile
2719 +++ b/drivers/input/mouse/Makefile
2721 obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o
2722 obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o
2723 obj-$(CONFIG_MOUSE_PS2) += psmouse.o
2724 +obj-$(CONFIG_MOUSE_COOPERATIVE) += comouse.o
2725 obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
2726 obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
2728 diff -urN a/drivers/input/mouse/comouse.c b/drivers/input/mouse/comouse.c
2729 --- a/drivers/input/mouse/comouse.c
2730 +++ b/drivers/input/mouse/comouse.c
2733 + * Virtual mouse driver for Linux
2735 + * Skeleton based on:
2736 + * $Id: sermouse.c,v 1.17 2002/03/13 10:03:43 vojtech Exp $
2738 + * Copyright (c) 1999-2001 Vojtech Pavlik
2740 + * Copyright (c) 2004 Dan Aloni
2743 +#include <linux/module.h>
2744 +#include <linux/slab.h>
2745 +#include <linux/interrupt.h>
2746 +#include <linux/input.h>
2747 +#include <linux/config.h>
2748 +#include <linux/serio.h>
2749 +#include <linux/init.h>
2751 +MODULE_AUTHOR("Dan Aloni <da-x@colinux.org>");
2752 +MODULE_DESCRIPTION("Virtual mouse driver");
2753 +MODULE_LICENSE("GPL");
2756 + * comouse_interrupt() handles incoming characters, either gathering them into
2757 + * packets or passing them to the command routine as command output.
2760 +static irqreturn_t comouse_interrupt(struct serio *serio,
2761 + unsigned char data, unsigned int flags, struct pt_regs *regs)
2763 + return IRQ_HANDLED;
2767 + * comouse_disconnect() cleans up after we don't want talk
2768 + * to the mouse anymore.
2771 +static void comouse_disconnect(struct serio *serio)
2776 + * comouse_connect() is a callback form the serio module when
2777 + * an unhandled serio port is found.
2780 +static void comouse_connect(struct serio *serio, struct serio_driver *dev)
2784 +static struct serio_driver comouse_dev = {
2785 + .interrupt = comouse_interrupt,
2786 + .connect = comouse_connect,
2787 + .disconnect = comouse_disconnect,
2789 + .name = "comouse",
2793 +int __init comouse_init(void)
2795 + serio_register_driver(&comouse_dev);
2799 +void __exit comouse_exit(void)
2801 + serio_unregister_driver(&comouse_dev);
2804 +module_init(comouse_init);
2805 +module_exit(comouse_exit);
2806 diff -urN a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
2807 --- a/drivers/input/serio/Kconfig
2808 +++ b/drivers/input/serio/Kconfig
2810 tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
2813 - depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K
2814 + depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K && !COOPERATIVE
2816 i8042 is the chip over which the standard AT keyboard and PS/2
2817 mouse are connected to the computer. If you use these devices,
2818 @@ -132,17 +132,22 @@
2819 module will be called maceps2.
2822 - tristate "Raw access to serio ports"
2825 - Say Y here if you want to have raw access to serio ports, such as
2826 - AUX ports on i8042 keyboard controller. Each serio port that is
2827 - bound to this driver will be accessible via a char device with
2828 - major 10 and dynamically allocated minor. The driver will try
2829 - allocating minor 1 (that historically corresponds to /dev/psaux)
2830 - first. To bind this driver to a serio port use sysfs interface:
2832 - echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver
2834 - To compile this driver as a module, choose M here: the
2835 - module will be called serio_raw.
2836 + tristate "Raw access to serio ports"
2839 + Say Y here if you want to have raw access to serio ports, such as
2840 + AUX ports on i8042 keyboard controller. Each serio port that is
2841 + bound to this driver will be accessible via a char device with
2842 + major 10 and dynamically allocated minor. The driver will try
2843 + allocating minor 1 (that historically corresponds to /dev/psaux)
2844 + first. To bind this driver to a serio port use sysfs interface:
2846 + echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver
2848 + To compile this driver as a module, choose M here: the
2849 + module will be called serio_raw.
2852 + tristate "Cooperative Linux virtual keyboard controller driver"
2853 + depends on COOPERATIVE
2855 diff -urN a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
2856 --- a/drivers/input/serio/Makefile
2857 +++ b/drivers/input/serio/Makefile
2859 obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o
2860 obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o
2861 obj-$(CONFIG_SERIO_RAW) += serio_raw.o
2862 +obj-$(CONFIG_SERIO_COKBD) += cokbd.o
2863 \ No newline at end of file
2864 diff -urN a/drivers/input/serio/cokbd.c b/drivers/input/serio/cokbd.c
2865 --- a/drivers/input/serio/cokbd.c
2866 +++ b/drivers/input/serio/cokbd.c
2869 + * Cooperative Linux virtual keyboard controller driver
2871 + * Copyright (c) 1999-2002 Dan Aloni <da-x@colinux.org)
2872 + * Based on 98kbd-io.c written by Osamu Tomita>
2876 + * This program is free software; you can redistribute it and/or modify it
2877 + * under the terms of the GNU General Public License version 2 as published by
2878 + * the Free Software Foundation.
2881 +#include <linux/config.h>
2882 +#include <linux/delay.h>
2883 +#include <linux/module.h>
2884 +#include <linux/interrupt.h>
2885 +#include <linux/ioport.h>
2886 +#include <linux/init.h>
2887 +#include <linux/serio.h>
2888 +#include <linux/sched.h>
2889 +#include <linux/cooperative_internal.h>
2891 +#include <asm/io.h>
2893 +MODULE_AUTHOR("Dan Aloni <da-x@colinux.org>");
2894 +MODULE_DESCRIPTION("Cooperative Linux virtual keyboard controller driver");
2895 +MODULE_LICENSE("GPL");
2901 +#define COKBD_PHYS_DESC "cokbd"
2903 +static struct serio cokbd_port;
2905 +static irqreturn_t cokbdio_interrupt(int irq, void *dev_id, struct pt_regs *regs);
2908 + * cokbd_flush() flushes all data that may be in the keyboard buffers
2911 +static int cokbd_flush(void)
2914 + co_linux_message_t *message;
2916 + while (co_get_message(&message, CO_DEVICE_KEYBOARD)) {
2917 + co_free_message(message);
2924 + * cokbd_write() sends a byte out through the keyboard interface.
2927 +#define ATKBD_CMD_GETID 0x02f2
2929 +static void cokbd_receive(struct serio *port, unsigned char c)
2931 + struct pt_regs regs= {0, };
2933 + serio_interrupt(port, c, 0, ®s);
2936 +static int cokbd_write(struct serio *port, unsigned char c)
2942 + * cokbd_open() is called when a port is open by the higher layer.
2943 + * It allocates the interrupt and enables in in the chip.
2946 +static int cokbd_open(struct serio *port)
2950 + if (request_irq(KEYBOARD_IRQ, cokbdio_interrupt, 0, "cokbd", NULL)) {
2951 + printk(KERN_ERR "cobkd.c: Can't get irq %d for %s, unregistering the port.\n", KEYBOARD_IRQ, "KBD");
2952 + serio_unregister_port(port);
2959 +static void cokbd_close(struct serio *port)
2961 + printk(KERN_INFO "cokbd closed\n");
2963 + free_irq(KEYBOARD_IRQ, NULL);
2969 + * Structures for registering the devices in the serio.c module.
2972 +static struct serio cokbd_port =
2974 + .type = SERIO_8042_XL,
2975 + .write = cokbd_write,
2976 + .open = cokbd_open,
2977 + .close = cokbd_close,
2978 + .name = "cokbd port",
2979 + .phys = COKBD_PHYS_DESC,
2983 + * cokbdio_interrupt() is the most important function in this driver -
2984 + * it handles the interrupts from keyboard, and sends incoming bytes
2985 + * to the upper layers.
2988 +static irqreturn_t cokbdio_interrupt(int irq, void *dev_id, struct pt_regs *regs)
2990 + co_message_node_t *node_message;
2991 + while (co_get_message(&node_message, CO_DEVICE_KEYBOARD)) {
2992 + co_linux_message_t *message = (co_linux_message_t *)&node_message->msg.data;
2993 + co_scan_code_t *sc = (co_scan_code_t *)message->data;
2994 + unsigned long scancode = sc->code;
2999 + cokbd_receive(&cokbd_port, scancode);
3001 + co_free_message(node_message);
3004 + return IRQ_HANDLED;
3007 +int __init cokbdio_init(void)
3009 + serio_register_port(&cokbd_port);
3011 + printk(KERN_INFO "serio: cokbd at irq %d\n", KEYBOARD_IRQ);
3016 +void __exit cokbdio_exit(void)
3018 + serio_unregister_port(&cokbd_port);
3021 +module_init(cokbdio_init);
3022 +module_exit(cokbdio_exit);
3023 diff -urN a/drivers/net/Kconfig b/drivers/net/Kconfig
3024 --- a/drivers/net/Kconfig
3025 +++ b/drivers/net/Kconfig
3026 @@ -127,6 +127,10 @@
3028 If you don't know what to use this for, you don't need it.
3030 +config COOPERATIVE_CONET
3031 + tristate 'Cooperative Virtual Ethernet driver support'
3032 + depends on COOPERATIVE
3035 tristate "General Instruments Surfboard 1000"
3036 depends on NETDEVICES && PNP
3037 diff -urN a/drivers/net/Makefile b/drivers/net/Makefile
3038 --- a/drivers/net/Makefile
3039 +++ b/drivers/net/Makefile
3042 # This is also a 82596 and should probably be merged
3043 obj-$(CONFIG_LP486E) += lp486e.o
3044 +obj-$(CONFIG_COOPERATIVE_CONET) += conet.o
3046 obj-$(CONFIG_ETH16I) += eth16i.o
3047 obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o
3048 diff -urN a/drivers/net/conet.c b/drivers/net/conet.c
3049 --- a/drivers/net/conet.c
3050 +++ b/drivers/net/conet.c
3053 + * Copyright (C) 2003-2004 Dan Aloni <da-x@gmx.net>
3054 + * Copyright (C) 2004 Pat Erley
3055 + * Copyright (C) 2004 George Boutwell
3057 + * Cooperative Linux Network Device implementation
3060 +#include <linux/config.h>
3061 +#include <linux/version.h>
3062 +#include <linux/module.h>
3064 +#include <linux/kernel.h>
3066 +#include <linux/netdevice.h>
3067 +#include <linux/etherdevice.h>
3068 +#include <linux/skbuff.h>
3069 +#include <linux/ethtool.h>
3071 +#include <linux/cooperative_internal.h>
3072 +#include <asm/irq.h>
3074 +struct conet_priv {
3075 + struct net_device_stats stats;
3082 +struct net_device *conet_dev[CO_MODULE_MAX_CONET];
3084 +irqreturn_t conet_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr);
3086 +static int conet_get_mac(int unit, char *address)
3088 + unsigned long flags = 0;
3089 + co_network_request_t *net_request;
3092 + co_passage_page_assert_valid();
3094 + co_passage_page_acquire(&flags);
3095 + co_passage_page->operation = CO_OPERATION_DEVICE;
3096 + co_passage_page->params[0] = CO_DEVICE_NETWORK;
3097 + net_request = (typeof(net_request))&co_passage_page->params[1];
3098 + net_request->unit = unit;
3099 + net_request->type = CO_NETWORK_GET_MAC;
3100 + co_switch_wrapper();
3101 + memcpy(address, net_request->mac_address, ETH_ALEN);
3102 + result = net_request->result;
3103 + co_passage_page_release(flags);
3108 +int conet_open(struct net_device *dev)
3110 + struct conet_priv *priv = (struct conet_priv *)dev->priv;
3112 + if (priv->enabled)
3115 + conet_get_mac(priv->unit, dev->dev_addr);
3117 + priv->enabled = 1;
3119 + netif_start_queue(dev);
3124 +int conet_stop(struct net_device *dev)
3126 + struct conet_priv *priv = (struct conet_priv *)dev->priv;
3128 + priv->enabled = 0;
3130 + netif_stop_queue(dev); /* can't transmit any more */
3135 +int conet_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
3139 + struct conet_priv *priv = (struct conet_priv *)dev->priv;
3141 + len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
3144 + dev->trans_start = jiffies; /* save the timestamp */
3146 + co_send_message(CO_MODULE_LINUX,
3147 + CO_MODULE_CONET0 + priv->unit,
3148 + CO_PRIORITY_DISCARDABLE,
3149 + CO_MESSAGE_TYPE_OTHER,
3153 + priv->stats.tx_bytes+=skb->len;
3154 + priv->stats.tx_packets++;
3156 + dev_kfree_skb(skb);
3161 +static void conet_rx(struct net_device *dev, co_linux_message_t *message)
3163 + struct sk_buff *skb;
3164 + struct conet_priv *priv = (struct conet_priv *)dev->priv;
3166 + unsigned char *buf;
3168 + len = message->size;
3169 + buf = message->data;
3172 + * The packet has been retrieved from the transmission
3173 + * medium. Build an skb around it, so upper layers can handle it
3175 + skb = dev_alloc_skb(len+2);
3177 + printk("conet rx: low on mem - packet dropped\n");
3178 + priv->stats.rx_dropped++;
3182 + memcpy(skb_put(skb, len), buf, len);
3184 + /* Write metadata, and then pass to the receive level */
3186 + skb->protocol = eth_type_trans(skb, dev);
3187 + skb->ip_summed = CHECKSUM_NONE; /* make the kernel calculate and verify
3190 + priv->stats.rx_bytes += len;
3191 + priv->stats.rx_packets++;
3197 +irqreturn_t conet_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
3199 + co_message_node_t *node_message;
3200 + while (co_get_message(&node_message, CO_DEVICE_NETWORK)) {
3201 + struct net_device *dev;
3202 + struct conet_priv *priv;
3203 + co_linux_message_t *message;
3205 + message = (co_linux_message_t *)&node_message->msg.data;
3206 + if (message->unit < 0 || message->unit >= CO_MODULE_MAX_CONET) {
3207 + printk("conet intrrupt: buggy network reception\n");
3208 + return IRQ_HANDLED;
3211 + dev = conet_dev[message->unit];
3213 + co_free_message(node_message);
3217 + if (!netif_running(dev)) {
3218 + co_free_message(node_message);
3222 + priv = (struct conet_priv *)dev->priv;
3223 + if (priv->handling) {
3224 + co_free_message(node_message);
3228 + priv->handling = 1;
3229 + conet_rx(dev, message);
3230 + co_free_message(node_message);
3231 + priv->handling = 0;
3234 + return IRQ_HANDLED;
3237 +struct net_device_stats* conet_get_stats(struct net_device *dev)
3239 + return (struct net_device_stats *)dev->priv;
3242 +int conet_init(struct net_device *dev)
3244 + struct conet_priv *priv = (struct conet_priv *)dev->priv;
3246 + memset(&priv->stats, 0, sizeof(priv->stats));
3250 + dev->open = conet_open;
3251 + dev->stop = conet_stop;
3252 + dev->hard_start_xmit = conet_hard_start_xmit;
3253 + dev->get_stats = conet_get_stats;
3254 + dev->irq = NETWORK_IRQ;
3256 + SET_MODULE_OWNER(dev);
3261 +void conet_uninit(struct net_device *dev)
3265 +static struct net_device *conet_create(int unit)
3267 + struct net_device *dev;
3268 + struct conet_priv *priv;
3271 + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
3273 + return ERR_PTR(-ENOMEM);
3276 + memset(dev, 0, sizeof(struct net_device));
3278 + priv = kmalloc(sizeof(struct conet_priv), GFP_KERNEL);
3279 + if (priv == NULL) {
3281 + return ERR_PTR(-ENOMEM);
3284 + memset(priv, 0, sizeof(struct conet_priv));
3285 + priv->unit = unit;
3288 + dev->init = conet_init;
3289 + dev->uninit = conet_uninit;
3290 + strcpy(dev->name, "eth%d");
3292 + result = register_netdev(dev);
3294 + printk("conet: error %d registering device \"%s\"\n", result, dev->name);
3297 + return ERR_PTR(-ENODEV);
3300 + printk("conet%d: initialized\n", priv->unit);
3305 +static void conet_destroy(struct net_device *dev)
3307 + struct conet_priv *priv = (struct conet_priv *) dev->priv;
3309 + printk("conet%d: freed\n", priv->unit);
3311 + unregister_netdev(dev);
3316 +static int __init conet_init_module(void)
3318 + int unit = 0, result;
3319 + struct net_device *dev;
3320 + char mac_address[6];
3322 + result = request_irq(NETWORK_IRQ, &conet_interrupt, 0, "conet", NULL);
3324 + printk("conet: loaded (max %d devices)\n", CO_MODULE_MAX_CONET);
3326 + for (unit=0; unit < CO_MODULE_MAX_CONET; unit++) {
3327 + conet_dev[unit] = NULL;
3329 + result = conet_get_mac(unit, mac_address);
3333 + dev = conet_create(unit);
3335 + conet_dev[unit] = dev;
3341 +static void __exit conet_cleanup_module(void)
3345 + free_irq(NETWORK_IRQ, NULL);
3347 + for (unit=0; unit < CO_MODULE_MAX_CONET; unit++) {
3348 + if (!conet_dev[unit])
3351 + conet_destroy(conet_dev[unit]);
3355 +module_init(conet_init_module);
3356 +module_exit(conet_cleanup_module);
3357 diff -urN a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
3358 --- a/drivers/video/console/Kconfig
3359 +++ b/drivers/video/console/Kconfig
3363 bool "VGA text console" if EMBEDDED || !X86
3364 - depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC32 && !SPARC64 && !M68K && !PARISC
3365 + depends on !COOPERATIVE && !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC32 && !SPARC64 && !M68K && !PARISC
3368 Saying Y here will allow you to use Linux in text mode through a
3373 +config COOPERATIVE_CONSOLE
3374 + bool 'coLinux Pseudo-VGA text console' if COOPERATIVE
3375 + depends on !VGA_CONSOLE && COOPERATIVE
3378 + You need to say Y here if you compile a Linux kernel in cooperative
3382 bool "Video mode selection support"
3383 depends on (X86 || X86_64) && VGA_CONSOLE
3386 config DUMMY_CONSOLE
3388 - depends on PROM_CONSOLE!=y || VGA_CONSOLE!=y || SGI_NEWPORT_CONSOLE!=y
3389 + depends on PROM_CONSOLE!=y || (COOPERATIVE_CONSOLE!=y && VGA_CONSOLE!=y) || SGI_NEWPORT_CONSOLE!=y
3392 config FRAMEBUFFER_CONSOLE
3393 diff -urN a/drivers/video/console/Makefile b/drivers/video/console/Makefile
3394 --- a/drivers/video/console/Makefile
3395 +++ b/drivers/video/console/Makefile
3397 obj-$(CONFIG_PROM_CONSOLE) += promcon.o promcon_tbl.o
3398 obj-$(CONFIG_STI_CONSOLE) += sticon.o sticore.o
3399 obj-$(CONFIG_VGA_CONSOLE) += vgacon.o
3400 +obj-$(CONFIG_COOPERATIVE_CONSOLE) += cocon.o
3401 obj-$(CONFIG_MDA_CONSOLE) += mdacon.o
3402 obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o
3403 obj-$(CONFIG_FB_TILEBLITTING) += tileblit.o
3404 diff -urN a/drivers/video/console/cocon.c b/drivers/video/console/cocon.c
3405 --- a/drivers/video/console/cocon.c
3406 +++ b/drivers/video/console/cocon.c
3409 + * linux/drivers/video/cocon.c -- Cooperative Linux console VGA driver
3411 + * This file is subject to the terms and conditions of the GNU General Public
3412 + * License. See the file COPYING in the main directory of this archive for
3415 + * Based on code copied from vgacon.c.
3417 + * Dan Aloni <da-x@gmx.net>, 2003-2004 (c)
3420 +#include <linux/config.h>
3421 +#include <linux/module.h>
3422 +#include <linux/types.h>
3423 +#include <linux/sched.h>
3424 +#include <linux/fs.h>
3425 +#include <linux/kernel.h>
3426 +#include <linux/tty.h>
3427 +#include <linux/console.h>
3428 +#include <linux/string.h>
3429 +#include <linux/kd.h>
3430 +#include <linux/slab.h>
3431 +#include <linux/vt_kern.h>
3432 +#include <linux/selection.h>
3433 +#include <linux/init.h>
3435 +#include <linux/cooperative_internal.h>
3438 + * Interface used by the world
3441 +static const char *cocon_startup(void);
3442 +static void cocon_init(struct vc_data *c, int init);
3443 +static void cocon_deinit(struct vc_data *c);
3444 +static void cocon_clear(struct vc_data *c, int, int, int, int);
3445 +static void cocon_cursor(struct vc_data *c, int mode);
3446 +static int cocon_switch(struct vc_data *c);
3447 +static int cocon_blank(struct vc_data *c, int blank, int mode_switch);
3448 +/* static int cocon_font_op(struct vc_data *c, struct console_font_op *op); */
3449 +static int cocon_set_palette(struct vc_data *c, unsigned char *table);
3450 +static int cocon_scrolldelta(struct vc_data *c, int lines);
3451 +static int cocon_set_origin(struct vc_data *c);
3452 +static void cocon_save_screen(struct vc_data *c);
3453 +static int cocon_scroll(struct vc_data *c, int t, int b, int dir, int lines);
3454 +static u8 cocon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse);
3455 +static void cocon_invert_region(struct vc_data *c, u16 *p, int count);
3457 +static const char __init *cocon_startup(void)
3459 + unsigned long flags;
3460 + co_console_message_t *message;
3461 + co_message_t *co_message;
3463 + co_message = co_send_message_save(&flags);
3464 + message = (co_console_message_t *)co_message->data;
3465 + co_message->from = CO_MODULE_LINUX;
3466 + co_message->to = CO_MODULE_CONSOLE;
3467 + co_message->priority = CO_PRIORITY_DISCARDABLE;
3468 + co_message->type = CO_MESSAGE_TYPE_STRING;
3469 + co_message->size = ((char *)(&message->type + 1)) - ((char *)message);
3470 + message->type = CO_OPERATION_CONSOLE_STARTUP;
3471 + co_send_message_restore(flags);
3476 +static void cocon_init(struct vc_data *c, int init)
3478 + unsigned long flags;
3479 + co_console_message_t *message;
3480 + co_message_t *co_message;
3482 + /* We cannot be loaded as a module, therefore init is always 1 */
3483 + c->vc_can_do_color = 1;
3486 + c->vc_complement_mask = 0x7700;
3487 + c->vc_visible_origin = 0;
3490 + co_message = co_send_message_save(&flags);
3491 + message = (co_console_message_t *)co_message->data;
3492 + co_message->from = CO_MODULE_LINUX;
3493 + co_message->to = CO_MODULE_CONSOLE;
3494 + co_message->priority = CO_PRIORITY_DISCARDABLE;
3495 + co_message->type = CO_MESSAGE_TYPE_STRING;
3496 + co_message->size = ((char *)(&message->type + 1)) - ((char *)message);
3497 + message->type = CO_OPERATION_CONSOLE_INIT;
3498 + co_send_message_restore(flags);
3501 +static void cocon_deinit(struct vc_data *c)
3503 + unsigned long flags;
3504 + co_console_message_t *message;
3505 + co_message_t *co_message;
3507 + co_message = co_send_message_save(&flags);
3508 + message = (co_console_message_t *)co_message->data;
3509 + co_message->from = CO_MODULE_LINUX;
3510 + co_message->to = CO_MODULE_CONSOLE;
3511 + co_message->priority = CO_PRIORITY_DISCARDABLE;
3512 + co_message->type = CO_MESSAGE_TYPE_STRING;
3513 + co_message->size = ((char *)(&message->type + 1)) - ((char *)message);
3514 + message->type = CO_OPERATION_CONSOLE_DEINIT;
3515 + co_send_message_restore(flags);
3519 +static void cocon_clear(struct vc_data *c, int top, int left, int rows, int cols)
3521 + unsigned long flags;
3522 + co_console_message_t *message;
3523 + co_message_t *co_message;
3525 + co_message = co_send_message_save(&flags);
3526 + message = (co_console_message_t *)co_message->data;
3527 + co_message->from = CO_MODULE_LINUX;
3528 + co_message->to = CO_MODULE_CONSOLE;
3529 + co_message->priority = CO_PRIORITY_DISCARDABLE;
3530 + co_message->type = CO_MESSAGE_TYPE_STRING;
3531 + co_message->size = ((char *)(&message->clear + 1)) - ((char *)message);
3532 + message->type = CO_OPERATION_CONSOLE_CLEAR;
3533 + message->clear.top = top;
3534 + message->clear.left = left;
3535 + message->clear.bottom = top + rows - 1;
3536 + message->clear.right = left + cols - 1;
3537 + message->clear.charattr = c->vc_video_erase_char;
3538 + co_send_message_restore(flags);
3541 +static void cocon_putc(struct vc_data *c, int charattr, int y, int x)
3543 + unsigned long flags;
3544 + co_message_t *co_message;
3545 + co_console_message_t *message;
3547 + co_message = co_send_message_save(&flags);
3548 + message = (co_console_message_t *)co_message->data;
3549 + co_message->from = CO_MODULE_LINUX;
3550 + co_message->to = CO_MODULE_CONSOLE;
3551 + co_message->priority = CO_PRIORITY_DISCARDABLE;
3552 + co_message->type = CO_MESSAGE_TYPE_STRING;
3553 + co_message->size = ((char *)(&message->putc + 1)) - ((char *)message);
3554 + message->type = CO_OPERATION_CONSOLE_PUTC;
3555 + message->putc.x = x;
3556 + message->putc.y = y;
3557 + message->putc.charattr = charattr;
3558 + co_send_message_restore(flags);
3562 +static void cocon_putcs(struct vc_data *conp,
3563 + const unsigned short *s, int count, int yy, int xx)
3565 + unsigned long flags;
3566 + co_console_message_t *message;
3567 + co_message_t *co_message;
3569 + if (count > CO_MAX_PARAM_SIZE/2 - 16)
3572 + co_message = co_send_message_save(&flags);
3573 + message = (co_console_message_t *)co_message->data;
3574 + co_message->from = CO_MODULE_LINUX;
3575 + co_message->to = CO_MODULE_CONSOLE;
3576 + co_message->priority = CO_PRIORITY_DISCARDABLE;
3577 + co_message->type = CO_MESSAGE_TYPE_STRING;
3578 + co_message->size = ((char *)(&message->putcs + 1)) - ((char *)message) +
3579 + count * sizeof(unsigned short);
3580 + message->type = CO_OPERATION_CONSOLE_PUTCS;
3581 + message->putcs.x = xx;
3582 + message->putcs.y = yy;
3583 + message->putcs.count = count;
3584 + memcpy(&message->putcs.data, s, count * sizeof(unsigned short));
3585 + co_send_message_restore(flags);
3588 +static u8 cocon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse)
3593 + attr = (attr & 0xf0) | c->vc_ulcolor;
3594 + else if (intensity == 0)
3595 + attr = (attr & 0xf0) | c->vc_halfcolor;
3597 + attr = ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) & 0x77);
3600 + if (intensity == 2)
3606 +static void cocon_invert_region(struct vc_data *c, u16 *p, int count)
3608 + unsigned long flags;
3609 + co_message_t *co_message;
3610 + co_console_message_t *message;
3611 + unsigned long x = (unsigned long)(p - c->vc_origin); // UPDATE: vc_origin = 0; but not yet
3613 + co_message = co_send_message_save(&flags);
3614 + message = (co_console_message_t *)co_message->data;
3615 + co_message->from = CO_MODULE_LINUX;
3616 + co_message->to = CO_MODULE_CONSOLE;
3617 + co_message->priority = CO_PRIORITY_DISCARDABLE;
3618 + co_message->type = CO_MESSAGE_TYPE_STRING;
3619 + co_message->size = ((char *)(&message->invert + 1)) - ((char *)message);
3620 + message->type = CO_OPERATION_CONSOLE_INVERT_REGION;
3621 + message->invert.y = ((unsigned)x)/c->vc_cols;
3622 + message->invert.x = ((unsigned)x)-(message->invert.y);
3623 + message->invert.count = count;
3624 + co_send_message_restore(flags);
3627 + u16 a = scr_readw(p);
3628 + a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
3629 + scr_writew(a, p++);
3634 +static void cocon_cursor(struct vc_data *c, int mode)
3636 + unsigned long flags;
3637 + co_console_message_t *message;
3638 + co_message_t *co_message;
3640 + co_message = co_send_message_save(&flags);
3641 + message = (co_console_message_t *)co_message->data;
3642 + co_message->from = CO_MODULE_LINUX;
3643 + co_message->to = CO_MODULE_CONSOLE;
3644 + co_message->priority = CO_PRIORITY_DISCARDABLE;
3645 + co_message->type = CO_MESSAGE_TYPE_STRING;
3646 + co_message->size = ((char *)(&message->cursor + 1)) - ((char *)message);;
3647 + if (mode==CM_ERASE) {
3648 + message->type = CO_OPERATION_CONSOLE_CURSOR_ERASE;
3649 + message->cursor.height = 0;
3650 + co_send_message_restore(flags);
3654 + if(mode==CM_MOVE) {
3655 + message->type = CO_OPERATION_CONSOLE_CURSOR_MOVE;
3656 + } else /*(mode==CM_DRAW)*/ {
3657 + message->type = CO_OPERATION_CONSOLE_CURSOR_DRAW;
3659 + message->cursor.x = c->vc_x;
3660 + message->cursor.y = c->vc_y;
3662 + switch (c->vc_cursor_type & CUR_HWMASK) {
3663 + case CUR_UNDERLINE:
3664 + message->cursor.height = 5;
3666 + case CUR_TWO_THIRDS:
3667 + message->cursor.height = 66;
3669 + case CUR_LOWER_THIRD:
3670 + message->cursor.height = 33;
3672 + case CUR_LOWER_HALF:
3673 + message->cursor.height = 50;
3676 + message->cursor.height = 0;
3679 + message->cursor.height = 5;
3683 + co_send_message_restore(flags);
3686 +static int cocon_switch(struct vc_data *c)
3688 + unsigned long flags;
3689 + co_console_message_t *message;
3690 + co_message_t *co_message;
3692 + co_message = co_send_message_save(&flags);
3693 + message = (co_console_message_t *)co_message->data;
3694 + co_message->from = CO_MODULE_LINUX;
3695 + co_message->to = CO_MODULE_CONSOLE;
3696 + co_message->priority = CO_PRIORITY_DISCARDABLE;
3697 + co_message->type = CO_MESSAGE_TYPE_STRING;
3698 + co_message->size = ((char *)(&message->type + 1)) - ((char *)message);
3699 + message->type = CO_OPERATION_CONSOLE_SWITCH;
3700 + co_send_message_restore(flags);
3702 + return 1; /* Redrawing not needed */
3705 +static int cocon_set_palette(struct vc_data *c, unsigned char *table)
3707 + unsigned long flags;
3708 + co_console_message_t *message;
3709 + co_message_t *co_message;
3711 + co_message = co_send_message_save(&flags);
3712 + message = (co_console_message_t *)co_message->data;
3713 + co_message->from = CO_MODULE_LINUX;
3714 + co_message->to = CO_MODULE_CONSOLE;
3715 + co_message->priority = CO_PRIORITY_DISCARDABLE;
3716 + co_message->type = CO_MESSAGE_TYPE_STRING;
3717 + co_message->size = ((char *)(&message->type + 1)) - ((char *)message);
3718 + message->type = CO_OPERATION_CONSOLE_SET_PALETTE;
3719 + co_send_message_restore(flags);
3724 +static int cocon_blank(struct vc_data *c, int blank, int mode_switchg)
3726 + unsigned long flags;
3727 + co_console_message_t *message;
3728 + co_message_t *co_message;
3730 + co_message = co_send_message_save(&flags);
3731 + message = (co_console_message_t *)co_message->data;
3732 + co_message->from = CO_MODULE_LINUX;
3733 + co_message->to = CO_MODULE_CONSOLE;
3734 + co_message->priority = CO_PRIORITY_DISCARDABLE;
3735 + co_message->type = CO_MESSAGE_TYPE_STRING;
3736 + co_message->size = ((char *)(&message->type + 1)) - ((char *)message);
3737 + message->type = CO_OPERATION_CONSOLE_BLANK;
3738 + co_send_message_restore(flags);
3744 +static int cocon_scrolldelta(struct vc_data *c, int lines)
3746 + unsigned long flags;
3747 + co_console_message_t *message;
3748 + co_message_t *co_message;
3750 + co_message = co_send_message_save(&flags);
3751 + message = (co_console_message_t *)co_message->data;
3752 + co_message->from = CO_MODULE_LINUX;
3753 + co_message->to = CO_MODULE_CONSOLE;
3754 + co_message->priority = CO_PRIORITY_DISCARDABLE;
3755 + co_message->type = CO_MESSAGE_TYPE_STRING;
3756 + co_message->size = ((char *)(&message->type + 1)) - ((char *)message);
3757 + message->type = CO_OPERATION_CONSOLE_SCROLLDELTA;
3758 + co_send_message_restore(flags);
3763 +static int cocon_set_origin(struct vc_data *c)
3765 + unsigned long flags;
3766 + co_console_message_t *message;
3767 + co_message_t *co_message;
3769 + co_message = co_send_message_save(&flags);
3770 + message = (co_console_message_t *)co_message->data;
3771 + co_message->from = CO_MODULE_LINUX;
3772 + co_message->to = CO_MODULE_CONSOLE;
3773 + co_message->priority = CO_PRIORITY_DISCARDABLE;
3774 + co_message->type = CO_MESSAGE_TYPE_STRING;
3775 + co_message->size = ((char *)(&message->type + 1)) - ((char *)message);
3776 + message->type = CO_OPERATION_CONSOLE_SET_ORIGIN;
3777 + co_send_message_restore(flags);
3782 +static void cocon_save_screen(struct vc_data *c)
3784 + unsigned long flags;
3785 + co_console_message_t *message;
3786 + co_message_t *co_message;
3788 + co_message = co_send_message_save(&flags);
3789 + message = (co_console_message_t *)co_message->data;
3790 + co_message->from = CO_MODULE_LINUX;
3791 + co_message->to = CO_MODULE_CONSOLE;
3792 + co_message->priority = CO_PRIORITY_DISCARDABLE;
3793 + co_message->type = CO_MESSAGE_TYPE_STRING;
3794 + co_message->size = ((char *)(&message->type + 1)) - ((char *)message);
3795 + message->type = CO_OPERATION_CONSOLE_SAVE_SCREEN;
3796 + co_send_message_restore(flags);
3799 +static int cocon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
3801 + unsigned long flags;
3802 + co_console_message_t *message;
3803 + co_message_t *co_message;
3805 + co_message = co_send_message_save(&flags);
3806 + message = (co_console_message_t *)co_message->data;
3807 + co_message->from = CO_MODULE_LINUX;
3808 + co_message->to = CO_MODULE_CONSOLE;
3809 + co_message->priority = CO_PRIORITY_DISCARDABLE;
3810 + co_message->type = CO_MESSAGE_TYPE_STRING;
3811 + co_message->size = ((char *)(&message->scroll + 1)) - ((char *)message);
3813 + message->type = CO_OPERATION_CONSOLE_SCROLL_UP;
3815 + message->type = CO_OPERATION_CONSOLE_SCROLL_DOWN;
3816 + message->scroll.top = t;
3817 + message->scroll.bottom = b-1;
3818 + message->scroll.lines = lines;
3819 + co_send_message_restore(flags);
3824 +static void cocon_bmove(struct vc_data *c, int sy, int sx, int dy, int dx, int h, int w)
3826 + unsigned long flags;
3827 + co_console_message_t *message;
3828 + co_message_t *co_message;
3830 + co_message = co_send_message_save(&flags);
3831 + message = (co_console_message_t *)co_message->data;
3832 + co_message->from = CO_MODULE_LINUX;
3833 + co_message->to = CO_MODULE_CONSOLE;
3834 + co_message->priority = CO_PRIORITY_DISCARDABLE;
3835 + co_message->type = CO_MESSAGE_TYPE_STRING;
3836 + co_message->size = ((char *)(&message->bmove + 1)) - ((char *)message);
3837 + message->type = CO_OPERATION_CONSOLE_BMOVE;
3838 + message->bmove.row = dy;
3839 + message->bmove.column = dx;
3840 + message->bmove.top = sy;
3841 + message->bmove.left = sx;
3842 + message->bmove.bottom = sy + h - 1;
3843 + message->bmove.right = sx + w - 1;
3844 + co_send_message_restore(flags);
3848 + * The console `switch' structure for the VGA based console
3851 +const struct consw colinux_con = {
3852 + con_startup: cocon_startup,
3853 + con_init: cocon_init,
3854 + con_deinit: cocon_deinit,
3855 + con_clear: cocon_clear,
3856 + con_putc: cocon_putc,
3857 + con_putcs: cocon_putcs,
3858 + con_cursor: cocon_cursor,
3859 + con_scroll: cocon_scroll,
3860 + con_bmove: cocon_bmove,
3861 + con_switch: cocon_switch,
3862 + con_blank: cocon_blank,
3863 + con_set_palette: cocon_set_palette,
3864 + con_scrolldelta: cocon_scrolldelta,
3865 + con_set_origin: cocon_set_origin,
3866 + con_save_screen: cocon_save_screen,
3867 + con_build_attr: cocon_build_attr,
3868 + con_invert_region: cocon_invert_region,
3871 +MODULE_LICENSE("GPL");
3872 diff -urN a/fs/Kconfig b/fs/Kconfig
3875 @@ -1098,6 +1098,19 @@
3876 containing the directory /) cannot be compiled as a module.
3880 + tristate "Cooperative Host file system support (COFUSE)"
3881 + depends on COOPERATIVE
3884 + In Cooperative mode, this file system allows you to mount an host
3885 + directory structure to a local mountpoint.
3886 + COFUSE (Cooperative FUSE) is based on the original FUSE
3887 + (File System in User Space).
3889 + To compile the cofuse support as a module, choose M here: the
3890 + module will be called cofusefs.
3894 tristate "EFS file system support (read only) (EXPERIMENTAL)"
3895 diff -urN a/fs/Makefile b/fs/Makefile
3899 obj-$(CONFIG_BEFS_FS) += befs/
3900 obj-$(CONFIG_HOSTFS) += hostfs/
3901 obj-$(CONFIG_HPPFS) += hppfs/
3902 +obj-$(CONFIG_COFUSE_FS) += cofusefs/
3904 diff -urN a/fs/cofusefs/Makefile b/fs/cofusefs/Makefile
3905 --- a/fs/cofusefs/Makefile
3906 +++ b/fs/cofusefs/Makefile
3909 +# Makefile for the Linux cofuse filesystem routines.
3912 +obj-$(CONFIG_COFUSE_FS) += cofusefs.o
3914 +cofusefs-objs := inode.o dir.o file.o util.o dev.o
3916 diff -urN a/fs/cofusefs/dev.c b/fs/cofusefs/dev.c
3917 --- a/fs/cofusefs/dev.c
3918 +++ b/fs/cofusefs/dev.c
3921 + FUSE: Filesystem in Userspace
3922 + Copyright (C) 2001-2004 Miklos Szeredi <miklos@szeredi.hu>
3924 + This program can be distributed under the terms of the GNU GPL.
3925 + See the file COPYING.
3928 +#include "fuse_i.h"
3930 +#include <linux/poll.h>
3931 +#include <linux/proc_fs.h>
3932 +#include <linux/file.h>
3934 +#ifndef CONFIG_COOPERATIVE
3936 +/* If more requests are outstanding, then the operation will block */
3937 +#define MAX_OUTSTANDING 10
3939 +static struct proc_dir_entry *proc_fs_fuse;
3940 +struct proc_dir_entry *proc_fuse_dev;
3941 +static kmem_cache_t *fuse_req_cachep;
3943 +static struct fuse_req *request_new(void)
3945 + struct fuse_req *req;
3947 + req = (struct fuse_req *) kmem_cache_alloc(fuse_req_cachep, SLAB_NOFS);
3949 + INIT_LIST_HEAD(&req->list);
3952 + req->interrupted = 0;
3954 + req->finished = 0;
3957 + init_waitqueue_head(&req->waitq);
3963 +static void request_free(struct fuse_req *req)
3965 + kmem_cache_free(fuse_req_cachep, req);
3968 +static int request_restartable(enum fuse_opcode opcode)
3972 + case FUSE_GETATTR:
3973 + case FUSE_READLINK:
3985 +/* Called with fuse_lock held. Releases, and then reaquires it. */
3986 +static void request_wait_answer(struct fuse_req *req)
3990 + spin_unlock(&fuse_lock);
3991 + intr = wait_event_interruptible(req->waitq, req->finished);
3992 + spin_lock(&fuse_lock);
3996 + /* Request interrupted... Wait for it to be unlocked */
3998 + req->interrupted = 1;
3999 + spin_unlock(&fuse_lock);
4000 + wait_event(req->waitq, !req->locked);
4001 + spin_lock(&fuse_lock);
4004 + /* Operations which modify the filesystem cannot safely be
4005 + restarted, because it is uncertain whether the operation has
4006 + completed or not... */
4007 + if(req->sent && !request_restartable(req->in->h.opcode))
4008 + req->out->h.error = -EINTR;
4010 + req->out->h.error = -ERESTARTSYS;
4013 +static int get_unique(struct fuse_conn *fc)
4016 + while(!fc->reqctr);
4017 + return fc->reqctr;
4020 +/* Must be called with fuse_lock held, and unlocks it */
4021 +static void request_end(struct fuse_conn *fc, struct fuse_req *req)
4023 + fuse_reqend_t endfunc = req->end;
4026 + wake_up(&req->waitq);
4027 + spin_unlock(&fuse_lock);
4029 + spin_unlock(&fuse_lock);
4030 + endfunc(fc, req->in, req->out, req->data);
4031 + request_free(req);
4032 + up(&fc->outstanding);
4036 +void request_send(struct fuse_conn *fc, struct fuse_in *in,
4037 + struct fuse_out *out)
4039 + struct fuse_req *req;
4041 + out->h.error = -ERESTARTSYS;
4042 + if(down_interruptible(&fc->outstanding))
4045 + out->h.error = -ENOMEM;
4046 + req = request_new();
4053 + spin_lock(&fuse_lock);
4054 + out->h.error = -ENOTCONN;
4056 + in->h.unique = get_unique(fc);
4057 + list_add_tail(&req->list, &fc->pending);
4058 + wake_up(&fc->waitq);
4059 + request_wait_answer(req);
4060 + list_del(&req->list);
4062 + spin_unlock(&fuse_lock);
4063 + request_free(req);
4066 + up(&fc->outstanding);
4070 +static inline void destroy_request(struct fuse_req *req)
4074 + request_free(req);
4078 +/* This one is currently only used for sending FORGET and RELEASE,
4079 + which are kernel initiated request. So the outstanding semaphore
4081 +int request_send_noreply(struct fuse_conn *fc, struct fuse_in *in)
4083 + struct fuse_req *req;
4085 + req = request_new();
4092 + spin_lock(&fuse_lock);
4094 + spin_unlock(&fuse_lock);
4095 + request_free(req);
4099 + list_add_tail(&req->list, &fc->pending);
4100 + wake_up(&fc->waitq);
4101 + spin_unlock(&fuse_lock);
4105 +int request_send_nonblock(struct fuse_conn *fc, struct fuse_in *in,
4106 + struct fuse_out *out, fuse_reqend_t end, void *data)
4109 + struct fuse_req *req;
4113 + if(down_trylock(&fc->outstanding))
4114 + return -EWOULDBLOCK;
4117 + req = request_new();
4125 + spin_lock(&fuse_lock);
4128 + in->h.unique = get_unique(fc);
4129 + list_add_tail(&req->list, &fc->pending);
4130 + wake_up(&fc->waitq);
4131 + spin_unlock(&fuse_lock);
4134 + spin_unlock(&fuse_lock);
4135 + request_free(req);
4137 + up(&fc->outstanding);
4141 +static void request_wait(struct fuse_conn *fc)
4143 + DECLARE_WAITQUEUE(wait, current);
4145 + add_wait_queue_exclusive(&fc->waitq, &wait);
4146 + while(fc->sb != NULL && list_empty(&fc->pending)) {
4147 + set_current_state(TASK_INTERRUPTIBLE);
4148 + if(signal_pending(current))
4151 + spin_unlock(&fuse_lock);
4153 + spin_lock(&fuse_lock);
4155 + set_current_state(TASK_RUNNING);
4156 + remove_wait_queue(&fc->waitq, &wait);
4159 +static inline int copy_in_one(const void *src, size_t srclen, char **dstp,
4162 + if(*dstlenp < srclen) {
4163 + printk("fuse_dev_read: buffer too small\n");
4167 + if(copy_to_user(*dstp, src, srclen))
4171 + *dstlenp -= srclen;
4176 +static inline int copy_in_args(struct fuse_in *in, char *buf, size_t nbytes)
4180 + size_t orignbytes = nbytes;
4182 + err = copy_in_one(&in->h, sizeof(in->h), &buf, &nbytes);
4186 + for(i = 0; i < in->numargs; i++) {
4187 + struct fuse_in_arg *arg = &in->args[i];
4188 + err = copy_in_one(arg->value, arg->size, &buf, &nbytes);
4193 + return orignbytes - nbytes;
4196 +static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes,
4200 + struct fuse_conn *fc = DEV_FC(file);
4201 + struct fuse_req *req = NULL;
4203 + spin_lock(&fuse_lock);
4205 + if(fc->sb != NULL && !list_empty(&fc->pending)) {
4206 + req = list_entry(fc->pending.next, struct fuse_req, list);
4207 + list_del_init(&req->list);
4210 + spin_unlock(&fuse_lock);
4211 + if(fc->sb == NULL)
4216 + ret = copy_in_args(req->in, buf, nbytes);
4217 + spin_lock(&fuse_lock);
4220 + req->out->h.error = -EPROTO;
4221 + req->finished = 1;
4223 + list_add_tail(&req->list, &fc->processing);
4227 + if(ret < 0 || req->interrupted)
4228 + /* Unlocks fuse_lock: */
4229 + request_end(fc, req);
4231 + spin_unlock(&fuse_lock);
4233 + spin_unlock(&fuse_lock);
4234 + destroy_request(req);
4239 +static struct fuse_req *request_find(struct fuse_conn *fc, unsigned int unique)
4241 + struct list_head *entry;
4242 + struct fuse_req *req = NULL;
4244 + list_for_each(entry, &fc->processing) {
4245 + struct fuse_req *tmp;
4246 + tmp = list_entry(entry, struct fuse_req, list);
4247 + if(tmp->in->h.unique == unique) {
4256 +static void process_getdir(struct fuse_req *req)
4258 + struct fuse_getdir_out *arg;
4259 + arg = (struct fuse_getdir_out *) req->out->args[0].value;
4260 + arg->file = fget(arg->fd);
4263 +static inline int copy_out_one(struct fuse_out_arg *arg, const char **srcp,
4264 + size_t *srclenp, int allowvar)
4266 + size_t dstlen = arg->size;
4267 + if(*srclenp < dstlen) {
4269 + printk("fuse_dev_write: write is short\n");
4272 + dstlen = *srclenp;
4276 + if(copy_from_user(arg->value, *srcp, dstlen))
4281 + *srclenp -= dstlen;
4282 + arg->size = dstlen;
4287 +static inline int copy_out_args(struct fuse_out *out, const char *buf,
4293 + buf += sizeof(struct fuse_out_header);
4294 + nbytes -= sizeof(struct fuse_out_header);
4296 + if(!out->h.error) {
4297 + for(i = 0; i < out->numargs; i++) {
4298 + struct fuse_out_arg *arg = &out->args[i];
4301 + if(out->argvar && i == out->numargs - 1)
4306 + err = copy_out_one(arg, &buf, &nbytes, allowvar);
4313 + printk("fuse_dev_write: write is long\n");
4320 +static inline int copy_out_header(struct fuse_out_header *oh, const char *buf,
4323 + if(nbytes < sizeof(struct fuse_out_header)) {
4324 + printk("fuse_dev_write: write is short\n");
4328 + if(copy_from_user(oh, buf, sizeof(struct fuse_out_header)))
4335 +static int fuse_invalidate(struct fuse_conn *fc, struct fuse_user_header *uh)
4337 + struct inode *inode = ilookup(fc->sb, uh->ino);
4340 + invalidate_inode_pages(inode->i_mapping);
4345 +static int fuse_invalidate(struct fuse_conn *fc, struct fuse_user_header *uh)
4347 + struct inode *inode = iget(fc->sb, uh->ino);
4348 + int err = -ENOENT;
4350 + if(inode->u.generic_ip) {
4351 + invalidate_inode_pages(inode);
4360 +static int fuse_user_request(struct fuse_conn *fc, const char *buf,
4363 + struct fuse_user_header uh;
4366 + if (nbytes < sizeof(struct fuse_user_header)) {
4367 + printk("fuse_dev_write: write is short\n");
4371 + if(copy_from_user(&uh, buf, sizeof(struct fuse_out_header)))
4374 + switch(uh.opcode) {
4375 + case FUSE_INVALIDATE:
4376 + err = fuse_invalidate(fc, &uh);
4386 +static ssize_t fuse_dev_write(struct file *file, const char *buf,
4387 + size_t nbytes, loff_t *off)
4390 + struct fuse_conn *fc = DEV_FC(file);
4391 + struct fuse_req *req;
4392 + struct fuse_out_header oh;
4397 + err = copy_out_header(&oh, buf, nbytes);
4402 + err = fuse_user_request(fc, buf, nbytes);
4406 + if (oh.error <= -512 || oh.error > 0) {
4407 + printk("fuse_dev_write: bad error value\n");
4411 + spin_lock(&fuse_lock);
4412 + req = request_find(fc, oh.unique);
4414 + list_del_init(&req->list);
4417 + spin_unlock(&fuse_lock);
4422 + err = copy_out_args(req->out, buf, nbytes);
4424 + spin_lock(&fuse_lock);
4426 + req->out->h.error = -EPROTO;
4428 + /* fget() needs to be done in this context */
4429 + if(req->in->h.opcode == FUSE_GETDIR && !oh.error)
4430 + process_getdir(req);
4432 + req->finished = 1;
4434 + /* Unlocks fuse_lock: */
4435 + request_end(fc, req);
4445 +static unsigned int fuse_dev_poll(struct file *file, poll_table *wait)
4447 + struct fuse_conn *fc = DEV_FC(file);
4448 + unsigned int mask = POLLOUT | POLLWRNORM;
4453 + poll_wait(file, &fc->waitq, wait);
4455 + spin_lock(&fuse_lock);
4456 + if (!list_empty(&fc->pending))
4457 + mask |= POLLIN | POLLRDNORM;
4458 + spin_unlock(&fuse_lock);
4463 +static struct fuse_conn *new_conn(void)
4465 + struct fuse_conn *fc;
4467 + fc = kmalloc(sizeof(*fc), GFP_KERNEL);
4473 + fc->oldrelease = 0;
4474 + init_waitqueue_head(&fc->waitq);
4475 + INIT_LIST_HEAD(&fc->pending);
4476 + INIT_LIST_HEAD(&fc->processing);
4477 + sema_init(&fc->outstanding, MAX_OUTSTANDING);
4483 +static int fuse_dev_open(struct inode *inode, struct file *file)
4485 + struct fuse_conn *fc;
4492 + file->private_data = fc;
4497 +static void end_requests(struct fuse_conn *fc, struct list_head *head)
4499 + while(!list_empty(head)) {
4500 + struct fuse_req *req;
4501 + req = list_entry(head->next, struct fuse_req, list);
4502 + list_del_init(&req->list);
4504 + req->out->h.error = -ECONNABORTED;
4505 + req->finished = 1;
4506 + /* Unlocks fuse_lock: */
4507 + request_end(fc, req);
4508 + spin_lock(&fuse_lock);
4510 + destroy_request(req);
4514 +static int fuse_dev_release(struct inode *inode, struct file *file)
4516 + struct fuse_conn *fc = DEV_FC(file);
4518 + spin_lock(&fuse_lock);
4520 + end_requests(fc, &fc->pending);
4521 + end_requests(fc, &fc->processing);
4523 + spin_unlock(&fuse_lock);
4527 +static struct file_operations fuse_dev_operations = {
4528 + .owner = THIS_MODULE,
4529 + .read = fuse_dev_read,
4530 + .write = fuse_dev_write,
4531 + .poll = fuse_dev_poll,
4532 + .open = fuse_dev_open,
4533 + .release = fuse_dev_release,
4536 +int fuse_dev_init()
4540 + proc_fs_fuse = NULL;
4541 + proc_fuse_dev = NULL;
4543 + fuse_req_cachep = kmem_cache_create("cofuser_request",
4544 + sizeof(struct fuse_req),
4545 + 0, 0, NULL, NULL);
4546 + if(!fuse_req_cachep)
4550 + proc_fs_fuse = proc_mkdir("fuse", proc_root_fs);
4551 + if(!proc_fs_fuse) {
4552 + printk("fuse: failed to create directory in /proc/fs\n");
4556 + proc_fs_fuse->owner = THIS_MODULE;
4557 + proc_fuse_dev = create_proc_entry("dev", S_IFSOCK | 0600, proc_fs_fuse);
4558 + if(!proc_fuse_dev) {
4559 + printk("fuse: failed to create entry in /proc/fs/fuse\n");
4563 + proc_fuse_dev->proc_fops = &fuse_dev_operations;
4568 + fuse_dev_cleanup();
4572 +void fuse_dev_cleanup()
4574 + if (cooperative_mode_enabled()) {
4575 + kmem_cache_destroy(fuse_req_cachep);
4579 + if(proc_fs_fuse) {
4580 + remove_proc_entry("dev", proc_fs_fuse);
4581 + remove_proc_entry("fuse", proc_root_fs);
4584 + kmem_cache_destroy(fuse_req_cachep);
4589 +struct fuse_conn *cofs_volumes[CO_MODULE_MAX_COFS] = {NULL, };
4591 +static void cofuse_request_start(unsigned long *flags, struct fuse_conn *fc, struct fuse_in *in)
4593 + co_passage_page_assert_valid();
4595 + co_passage_page_acquire(flags);
4596 + co_passage_page->operation = CO_OPERATION_DEVICE;
4597 + co_passage_page->params[0] = CO_DEVICE_FILESYSTEM;
4598 + co_passage_page->params[1] = fc->cofs_unit;
4599 + co_passage_page->params[2] = in->h.opcode;
4600 + co_passage_page->params[3] = in->h.ino;
4601 + co_passage_page->params[4] = 0;
4604 +static void cofuse_request_end(unsigned long flags, struct fuse_out *out)
4606 + unsigned long ret;
4607 + ret = co_passage_page->params[4];
4608 + co_passage_page_release(flags);
4609 + out->h.error = ret;
4612 +void request_send(struct fuse_conn *fc, struct fuse_in *in,
4613 + struct fuse_out *out)
4615 + unsigned long flags;
4618 + switch ((unsigned long)in->h.opcode) {
4619 + case FUSE_STATFS: {
4620 + struct fuse_statfs_out *arg;
4622 + arg = (struct fuse_statfs_out *)out->args[0].value;
4624 + cofuse_request_start(&flags, fc, in);
4625 + co_switch_wrapper();
4626 + *arg = *(struct fuse_statfs_out *)&co_passage_page->params[5];
4627 + cofuse_request_end(flags, out);
4632 + struct fuse_open_in *opin = (struct fuse_open_in *)in->args[0].value;
4634 + cofuse_request_start(&flags, fc, in);
4635 + co_passage_page->params[5] = opin->flags;
4636 + co_switch_wrapper();
4637 + cofuse_request_end(flags, out);
4641 + case FUSE_WRITE: {
4642 + struct fuse_write_in *write_in = (struct fuse_write_in *)in->args[0].value;
4643 + unsigned long long *offset_passage = (unsigned long long *)&co_passage_page->params[5];
4645 + cofuse_request_start(&flags, fc, in);
4646 + *offset_passage = write_in->offset;
4647 + co_passage_page->params[7] = write_in->size;
4648 + co_passage_page->params[8] = (unsigned long)in->args[1].value;
4649 + co_switch_wrapper();
4650 + cofuse_request_end(flags, out);
4655 + struct fuse_read_in *read_in = (struct fuse_read_in *)in->args[0].value;
4656 + unsigned long long *offset_passage = (unsigned long long *)&co_passage_page->params[5];
4658 + cofuse_request_start(&flags, fc, in);
4659 + *offset_passage = read_in->offset;
4660 + co_passage_page->params[7] = read_in->size;
4661 + co_passage_page->params[8] = (unsigned long)out->args[0].value;
4662 + co_switch_wrapper();
4663 + cofuse_request_end(flags, out);
4667 + case FUSE_LOOKUP: {
4668 + struct fuse_lookup_out *arg;
4670 + arg = (struct fuse_lookup_out *)out->args[0].value;
4671 + str = (char *)&co_passage_page->params[30];
4673 + cofuse_request_start(&flags, fc, in);
4674 + memcpy(str, (char *)in->args[0].value, in->args[0].size);
4675 + co_switch_wrapper();
4676 + *arg = *(struct fuse_lookup_out *)&co_passage_page->params[5];
4677 + cofuse_request_end(flags, out);
4681 + case FUSE_RENAME: {
4682 + struct fuse_rename_in *arg;
4685 + arg = (struct fuse_rename_in *)in->args[0].value;
4686 + str = (char *)(&co_passage_page->params[30]);
4687 + str2 = str + in->args[1].size;
4689 + cofuse_request_start(&flags, fc, in);
4690 + co_passage_page->params[5] = arg->newdir;
4691 + memcpy(str, (char *)in->args[1].value, in->args[1].size);
4692 + memcpy(str2, (char *)in->args[2].value, in->args[2].size);
4693 + co_switch_wrapper();
4694 + cofuse_request_end(flags, out);
4698 + case FUSE_MKNOD: {
4699 + struct fuse_mknod_in *inarg;
4700 + struct fuse_mknod_out *outarg;
4703 + inarg = (struct fuse_mknod_in *)(in->args[0].value);
4704 + outarg = (struct fuse_mknod_out *)(out->args[0].value);
4706 + cofuse_request_start(&flags, fc, in);
4707 + co_passage_page->params[5] = inarg->mode;
4708 + co_passage_page->params[6] = inarg->rdev;
4709 + str = (char *)&co_passage_page->params[30];
4710 + memcpy(str, (char *)in->args[1].value, in->args[1].size);
4711 + co_switch_wrapper();
4712 + outarg->ino = co_passage_page->params[7];
4713 + outarg->attr = *(struct fuse_attr *)(&co_passage_page->params[8]);
4714 + cofuse_request_end(flags, out);
4718 + case FUSE_SETATTR: {
4719 + struct fuse_setattr_in *inarg;
4720 + struct fuse_setattr_out *outarg;
4721 + struct fuse_attr *attr;
4723 + inarg = (struct fuse_setattr_in *)(in->args[0].value);
4724 + outarg = (struct fuse_setattr_out *)(out->args[0].value);
4725 + attr = (struct fuse_attr *)(&co_passage_page->params[6]);
4727 + cofuse_request_start(&flags, fc, in);
4728 + co_passage_page->params[5] = inarg->valid;
4729 + *attr = inarg->attr;
4730 + co_switch_wrapper();
4731 + outarg->attr = *attr;
4732 + cofuse_request_end(flags, out);
4736 + case FUSE_MKDIR: {
4737 + struct fuse_mkdir_in *arg;
4739 + arg = (struct fuse_mkdir_in *)(in->args[0].value);
4740 + str = (char *)&co_passage_page->params[30];
4742 + cofuse_request_start(&flags, fc, in);
4743 + co_passage_page->params[5] = arg->mode;
4744 + memcpy(str, (char *)in->args[1].value, in->args[1].size);
4745 + co_switch_wrapper();
4746 + cofuse_request_end(flags, out);
4751 + case FUSE_RMDIR: {
4752 + str = (char *)&co_passage_page->params[30];
4754 + cofuse_request_start(&flags, fc, in);
4755 + memcpy(str, (char *)in->args[0].value, in->args[0].size);
4756 + co_switch_wrapper();
4757 + cofuse_request_end(flags, out);
4761 + case FUSE_GETATTR: {
4762 + struct fuse_getattr_out *arg;
4763 + arg = (struct fuse_getattr_out *)out->args[0].value;
4765 + co_passage_page_assert_valid();
4766 + cofuse_request_start(&flags, fc, in);
4767 + co_switch_wrapper();
4768 + *arg = *(struct fuse_getattr_out *)&co_passage_page->params[5];
4769 + cofuse_request_end(flags, out);
4774 + /* printk("cofuse: request_send %d\n", in->h.opcode); */
4775 + out->h.error = -EIO;
4778 +int request_send_noreply(struct fuse_conn *fc, struct fuse_in *in)
4783 +int request_send_nonblock(struct fuse_conn *fc, struct fuse_in *in,
4784 + struct fuse_out *out, fuse_reqend_t end, void *data)
4786 + /* printk("cofuse: request_send_nonblock %d\n", in->h.opcode); */
4787 + request_send(fc, in, out);
4788 + end(fc, in, out, data);
4792 +int fuse_dev_init()
4797 +void fuse_dev_cleanup()
4804 + * Local Variables:
4805 + * indent-tabs-mode: t
4806 + * c-basic-offset: 8
4809 diff -urN a/fs/cofusefs/dir.c b/fs/cofusefs/dir.c
4810 --- a/fs/cofusefs/dir.c
4811 +++ b/fs/cofusefs/dir.c
4814 + FUSE: Filesystem in Userspace
4815 + Copyright (C) 2001-2004 Miklos Szeredi <miklos@szeredi.hu>
4817 + This program can be distributed under the terms of the GNU GPL.
4818 + See the file COPYING.
4821 +#include "fuse_i.h"
4823 +#include <linux/pagemap.h>
4824 +#include <linux/slab.h>
4825 +#include <linux/file.h>
4827 +static struct inode_operations fuse_dir_inode_operations;
4828 +static struct inode_operations fuse_file_inode_operations;
4829 +static struct inode_operations fuse_symlink_inode_operations;
4831 +static struct file_operations fuse_dir_operations;
4833 +static struct dentry_operations fuse_dentry_operations;
4835 +/* FIXME: This should be user configurable */
4836 +#define FUSE_REVALIDATE_TIME (1 * HZ)
4839 +#define new_decode_dev(x) (x)
4840 +#define new_encode_dev(x) (x)
4843 +static void change_attributes(struct inode *inode, struct fuse_attr *attr)
4845 + if(S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) {
4847 + invalidate_inode_pages(inode->i_mapping);
4849 + invalidate_inode_pages(inode);
4853 + inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
4854 + inode->i_nlink = attr->nlink;
4855 + inode->i_uid = attr->uid;
4856 + inode->i_gid = attr->gid;
4857 + i_size_write(inode, attr->size);
4858 + inode->i_blksize = PAGE_CACHE_SIZE;
4859 + inode->i_blocks = attr->blocks;
4861 + inode->i_atime.tv_sec = attr->atime;
4862 + inode->i_atime.tv_nsec = 0;
4863 + inode->i_mtime.tv_sec = attr->mtime;
4864 + inode->i_mtime.tv_nsec = 0;
4865 + inode->i_ctime.tv_sec = attr->ctime;
4866 + inode->i_ctime.tv_nsec = 0;
4868 + inode->i_atime = attr->atime;
4869 + inode->i_mtime = attr->mtime;
4870 + inode->i_ctime = attr->ctime;
4874 +static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
4876 + inode->i_mode = attr->mode & S_IFMT;
4877 + i_size_write(inode, attr->size);
4878 + if(S_ISREG(inode->i_mode)) {
4879 + inode->i_op = &fuse_file_inode_operations;
4880 + fuse_init_file_inode(inode);
4882 + else if(S_ISDIR(inode->i_mode)) {
4883 + inode->i_op = &fuse_dir_inode_operations;
4884 + inode->i_fop = &fuse_dir_operations;
4886 + else if(S_ISLNK(inode->i_mode)) {
4887 + inode->i_op = &fuse_symlink_inode_operations;
4890 + inode->i_op = &fuse_file_inode_operations;
4891 + init_special_inode(inode, inode->i_mode,
4892 + new_decode_dev(attr->rdev));
4894 + inode->u.generic_ip = inode;
4897 +struct inode *fuse_iget(struct super_block *sb, ino_t ino,
4898 + struct fuse_attr *attr, int version)
4900 + struct inode *inode;
4902 + inode = iget(sb, ino);
4904 + if(!inode->u.generic_ip)
4905 + fuse_init_inode(inode, attr);
4907 + change_attributes(inode, attr);
4908 + inode->i_version = version;
4914 +static int fuse_do_lookup(struct inode *dir, struct dentry *entry,
4915 + struct fuse_lookup_out *outarg, int *version)
4917 + struct fuse_conn *fc = INO_FC(dir);
4918 + struct fuse_in in = FUSE_IN_INIT;
4919 + struct fuse_out out = FUSE_OUT_INIT;
4921 + if (entry->d_name.len > FUSE_NAME_MAX)
4922 + return -ENAMETOOLONG;
4924 + in.h.opcode = FUSE_LOOKUP;
4925 + in.h.ino = dir->i_ino;
4927 + in.args[0].size = entry->d_name.len + 1;
4928 + in.args[0].value = entry->d_name.name;
4930 + out.args[0].size = sizeof(struct fuse_lookup_out);
4931 + out.args[0].value = outarg;
4932 + request_send(fc, &in, &out);
4934 + *version = out.h.unique;
4935 + return out.h.error;
4938 +static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
4939 + struct inode **inodep)
4942 + struct fuse_lookup_out outarg;
4944 + struct inode *inode = NULL;
4946 + err = fuse_do_lookup(dir, entry, &outarg, &version);
4948 + inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr, version);
4951 + } else if(err != -ENOENT)
4954 + entry->d_time = jiffies;
4955 + entry->d_op = &fuse_dentry_operations;
4960 +static void uncache_dir(struct inode *dir)
4962 + struct dentry *entry = d_find_alias(dir);
4966 + entry->d_time = jiffies - FUSE_REVALIDATE_TIME - 1;
4971 +/* create needs to return a positive entry, so this is actually an
4973 +static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
4976 + struct fuse_conn *fc = INO_FC(dir);
4977 + struct fuse_in in = FUSE_IN_INIT;
4978 + struct fuse_out out = FUSE_OUT_INIT;
4979 + struct fuse_mknod_in inarg;
4980 + struct fuse_mknod_out outarg;
4981 + struct inode *inode;
4983 + memset(&inarg, 0, sizeof(inarg));
4984 + inarg.mode = mode;
4985 + inarg.rdev = new_encode_dev(rdev);
4987 + in.h.opcode = FUSE_MKNOD;
4988 + in.h.ino = dir->i_ino;
4990 + in.args[0].size = sizeof(inarg);
4991 + in.args[0].value = &inarg;
4992 + in.args[1].size = entry->d_name.len + 1;
4993 + in.args[1].value = entry->d_name.name;
4995 + out.args[0].size = sizeof(outarg);
4996 + out.args[0].value = &outarg;
4997 + request_send(fc, &in, &out);
5000 + return out.h.error;
5002 + inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr, out.h.unique);
5006 + /* Don't allow userspace to do really stupid things... */
5007 + if((inode->i_mode ^ mode) & S_IFMT) {
5009 + printk("fuse_mknod: inode has wrong type\n");
5013 + d_instantiate(entry, inode);
5018 +static int _fuse_create(struct inode *dir, struct dentry *entry, int mode)
5020 + return _fuse_mknod(dir, entry, mode, 0);
5023 +/* knfsd needs the new entry instantiated in mkdir/symlink/link. this
5024 + should rather be done like mknod: attributes returned in out arg to
5025 + save a call to userspace */
5026 +static int lookup_new_entry(struct inode *dir, struct dentry *entry)
5028 + struct inode *inode;
5029 + int err = fuse_lookup_iget(dir, entry, &inode);
5030 + if(err || !inode) {
5031 + printk("fuse_mkdir: failed to look up new entry\n");
5032 + return err ? err : -ENOENT;
5034 + d_instantiate(entry, inode);
5039 +static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
5041 + struct fuse_conn *fc = INO_FC(dir);
5042 + struct fuse_in in = FUSE_IN_INIT;
5043 + struct fuse_out out = FUSE_OUT_INIT;
5044 + struct fuse_mkdir_in inarg;
5046 + memset(&inarg, 0, sizeof(inarg));
5047 + inarg.mode = mode;
5049 + in.h.opcode = FUSE_MKDIR;
5050 + in.h.ino = dir->i_ino;
5052 + in.args[0].size = sizeof(inarg);
5053 + in.args[0].value = &inarg;
5054 + in.args[1].size = entry->d_name.len + 1;
5055 + in.args[1].value = entry->d_name.name;
5056 + request_send(fc, &in, &out);
5058 + return out.h.error;
5060 + return lookup_new_entry(dir, entry);
5063 +static int fuse_symlink(struct inode *dir, struct dentry *entry,
5066 + struct fuse_conn *fc = INO_FC(dir);
5067 + struct fuse_in in = FUSE_IN_INIT;
5068 + struct fuse_out out = FUSE_OUT_INIT;
5069 + unsigned int len = strlen(link) + 1;
5071 + if (len > FUSE_SYMLINK_MAX)
5072 + return -ENAMETOOLONG;
5074 + in.h.opcode = FUSE_SYMLINK;
5075 + in.h.ino = dir->i_ino;
5077 + in.args[0].size = entry->d_name.len + 1;
5078 + in.args[0].value = entry->d_name.name;
5079 + in.args[1].size = len;
5080 + in.args[1].value = link;
5081 + request_send(fc, &in, &out);
5083 + return out.h.error;
5085 + return lookup_new_entry(dir, entry);
5088 +static int fuse_remove(struct inode *dir, struct dentry *entry,
5089 + enum fuse_opcode op)
5091 + struct fuse_conn *fc = INO_FC(dir);
5092 + struct fuse_in in = FUSE_IN_INIT;
5093 + struct fuse_out out = FUSE_OUT_INIT;
5096 + in.h.ino = dir->i_ino;
5098 + in.args[0].size = entry->d_name.len + 1;
5099 + in.args[0].value = entry->d_name.name;
5100 + request_send(fc, &in, &out);
5102 + return out.h.error;
5105 +static int fuse_unlink(struct inode *dir, struct dentry *entry)
5107 + int err = fuse_remove(dir, entry, FUSE_UNLINK);
5109 + /* FIXME: the new i_nlink could be returned by the
5110 + unlink operation */
5111 + err = fuse_do_getattr(entry->d_inode);
5112 + if(err == -ENOENT)
5113 + entry->d_inode->i_nlink = 0;
5121 +static int fuse_rmdir(struct inode *dir, struct dentry *entry)
5123 + int err = fuse_remove(dir, entry, FUSE_RMDIR);
5125 + entry->d_inode->i_nlink = 0;
5131 +static int fuse_rename(struct inode *olddir, struct dentry *oldent,
5132 + struct inode *newdir, struct dentry *newent)
5134 + struct fuse_conn *fc = INO_FC(olddir);
5135 + struct fuse_in in = FUSE_IN_INIT;
5136 + struct fuse_out out = FUSE_OUT_INIT;
5137 + struct fuse_rename_in inarg;
5139 + memset(&inarg, 0, sizeof(inarg));
5140 + inarg.newdir = newdir->i_ino;
5142 + in.h.opcode = FUSE_RENAME;
5143 + in.h.ino = olddir->i_ino;
5145 + in.args[0].size = sizeof(inarg);
5146 + in.args[0].value = &inarg;
5147 + in.args[1].size = oldent->d_name.len + 1;
5148 + in.args[1].value = oldent->d_name.name;
5149 + in.args[2].size = newent->d_name.len + 1;
5150 + in.args[2].value = newent->d_name.name;
5151 + request_send(fc, &in, &out);
5153 + if (!out.h.error) {
5154 + uncache_dir(olddir);
5155 + if (olddir != newdir)
5156 + uncache_dir(newdir);
5159 + return out.h.error;
5162 +static int fuse_link(struct dentry *entry, struct inode *newdir,
5163 + struct dentry *newent)
5165 + struct inode *inode = entry->d_inode;
5166 + struct fuse_conn *fc = INO_FC(inode);
5167 + struct fuse_in in = FUSE_IN_INIT;
5168 + struct fuse_out out = FUSE_OUT_INIT;
5169 + struct fuse_link_in inarg;
5171 + memset(&inarg, 0, sizeof(inarg));
5172 + inarg.newdir = newdir->i_ino;
5174 + in.h.opcode = FUSE_LINK;
5175 + in.h.ino = inode->i_ino;
5177 + in.args[0].size = sizeof(inarg);
5178 + in.args[0].value = &inarg;
5179 + in.args[1].size = newent->d_name.len + 1;
5180 + in.args[1].value = newent->d_name.name;
5181 + request_send(fc, &in, &out);
5183 + return out.h.error;
5185 + /* Invalidate old entry, so attributes are refreshed */
5186 + d_invalidate(entry);
5187 + return lookup_new_entry(newdir, newent);
5190 +int fuse_do_getattr(struct inode *inode)
5192 + struct fuse_conn *fc = INO_FC(inode);
5193 + struct fuse_in in = FUSE_IN_INIT;
5194 + struct fuse_out out = FUSE_OUT_INIT;
5195 + struct fuse_getattr_out arg;
5197 + in.h.opcode = FUSE_GETATTR;
5198 + in.h.ino = inode->i_ino;
5200 + out.args[0].size = sizeof(arg);
5201 + out.args[0].value = &arg;
5202 + request_send(fc, &in, &out);
5205 + change_attributes(inode, &arg.attr);
5207 + return out.h.error;
5210 +static int fuse_revalidate(struct dentry *entry)
5212 + struct inode *inode = entry->d_inode;
5213 + struct fuse_conn *fc = INO_FC(inode);
5215 + if(inode->i_ino == FUSE_ROOT_INO) {
5216 + if(!(fc->flags & FUSE_ALLOW_OTHER) &&
5217 + current->fsuid != fc->uid)
5219 + } else if(time_before_eq(jiffies, entry->d_time + FUSE_REVALIDATE_TIME))
5222 + return fuse_do_getattr(inode);
5225 +static int _fuse_permission(struct inode *inode, int mask)
5227 + struct fuse_conn *fc = INO_FC(inode);
5229 + if(!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid)
5231 + else if(fc->flags & FUSE_DEFAULT_PERMISSIONS) {
5232 + int err = generic_permission(inode, mask, NULL);
5234 + /* If permission is denied, try to refresh file
5235 + attributes. This is also needed, because the root
5236 + node will at first have no permissions */
5238 + if(err == -EACCES) {
5239 + err = fuse_do_getattr(inode);
5241 + err = generic_permission(inode, mask, NULL);
5244 + /* FIXME: Need some mechanism to revoke permissions:
5245 + currently if the filesystem suddenly changes the
5246 + file mode, we will not be informed abot that, and
5247 + continue to allow access to the file/directory.
5249 + This is actually not so grave, since the user can
5250 + simply keep access to the file/directory anyway by
5251 + keeping it open... */
5259 +static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
5260 + void *dstbuf, filldir_t filldir)
5262 + while(nbytes >= FUSE_NAME_OFFSET) {
5263 + struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
5264 + size_t reclen = FUSE_DIRENT_SIZE(dirent);
5267 + if(dirent->namelen > NAME_MAX) {
5268 + printk("fuse_readdir: name too long\n");
5271 + if(reclen > nbytes)
5274 + over = filldir(dstbuf, dirent->name, dirent->namelen,
5275 + file->f_pos, dirent->ino, dirent->type);
5280 + file->f_pos += reclen;
5287 +#ifndef CONFIG_COOPERATIVE
5289 +#define DIR_BUFSIZE 2048
5290 +static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
5292 + struct file *cfile = file->private_data;
5299 + buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL);
5303 + ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE);
5305 + printk("fuse_readdir: failed to read container file\n");
5307 + ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
5315 +#define DIR_BUFSIZE 4096
5318 + struct fuse_conn *fc;
5322 +static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
5324 + readdir_data_t *rd = file->private_data;
5325 + unsigned long flags;
5329 + buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL);
5333 + co_passage_page_assert_valid();
5335 + co_passage_page_acquire(&flags);
5336 + co_passage_page->operation = CO_OPERATION_DEVICE;
5337 + co_passage_page->params[0] = CO_DEVICE_FILESYSTEM;
5338 + co_passage_page->params[1] = rd->fc->cofs_unit;
5339 + co_passage_page->params[2] = FUSE_DIR_READ;
5340 + co_passage_page->params[3] = rd->inode;
5341 + co_passage_page->params[5] = DIR_BUFSIZE;
5342 + co_passage_page->params[6] = (unsigned long)buf;
5343 + co_passage_page->params[8] = file->f_pos;
5345 + co_switch_wrapper();
5347 + ret = co_passage_page->params[4];
5348 + size = co_passage_page->params[7];
5350 + co_passage_page_release(flags);
5353 + printk("fuse_readdir: host returned error: %x\n", ret);
5358 + parse_dirfile(buf, size, file, dstbuf, filldir);
5367 +static char *read_link(struct dentry *dentry)
5369 + struct inode *inode = dentry->d_inode;
5370 + struct fuse_conn *fc = INO_FC(inode);
5371 + struct fuse_in in = FUSE_IN_INIT;
5372 + struct fuse_out out = FUSE_OUT_INIT;
5375 + link = (char *) __get_free_page(GFP_KERNEL);
5377 + return ERR_PTR(-ENOMEM);
5379 + in.h.opcode = FUSE_READLINK;
5380 + in.h.ino = inode->i_ino;
5383 + out.args[0].size = PAGE_SIZE - 1;
5384 + out.args[0].value = link;
5385 + request_send(fc, &in, &out);
5387 + free_page((unsigned long) link);
5388 + return ERR_PTR(out.h.error);
5391 + link[out.args[0].size] = '\0';
5395 +static void free_link(char *link)
5398 + free_page((unsigned long) link);
5401 +static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen)
5406 + link = read_link(dentry);
5407 + ret = vfs_readlink(dentry, buffer, buflen, link);
5412 +static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
5417 + link = read_link(dentry);
5418 + ret = vfs_follow_link(nd, link);
5423 +#ifndef CONFIG_COOPERATIVE
5425 +static int fuse_dir_open(struct inode *inode, struct file *file)
5427 + struct fuse_conn *fc = INO_FC(inode);
5428 + struct fuse_in in = FUSE_IN_INIT;
5429 + struct fuse_out out = FUSE_OUT_INIT;
5430 + struct fuse_getdir_out outarg;
5432 + in.h.opcode = FUSE_GETDIR;
5433 + in.h.ino = inode->i_ino;
5435 + out.args[0].size = sizeof(outarg);
5436 + out.args[0].value = &outarg;
5437 + request_send(fc, &in, &out);
5438 + if(!out.h.error) {
5439 + struct file *cfile = outarg.file;
5440 + struct inode *inode;
5442 + printk("fuse_getdir: invalid file\n");
5445 + inode = cfile->f_dentry->d_inode;
5446 + if(!S_ISREG(inode->i_mode)) {
5447 + printk("fuse_getdir: not a regular file\n");
5452 + file->private_data = cfile;
5455 + return out.h.error;
5458 +static int fuse_dir_release(struct inode *inode, struct file *file)
5460 + struct file *cfile = file->private_data;
5470 +static int fuse_dir_open(struct inode *inode, struct file *file)
5472 + struct fuse_conn *fc = INO_FC(inode);
5473 + unsigned long flags;
5474 + readdir_data_t *rd;
5477 + rd = kmalloc(sizeof(*rd), GFP_KERNEL);
5482 + rd->inode = inode->i_ino;
5484 + co_passage_page_assert_valid();
5486 + co_passage_page_acquire(&flags);
5487 + co_passage_page->operation = CO_OPERATION_DEVICE;
5488 + co_passage_page->params[0] = CO_DEVICE_FILESYSTEM;
5489 + co_passage_page->params[1] = fc->cofs_unit;
5490 + co_passage_page->params[2] = FUSE_DIR_OPEN;
5491 + co_passage_page->params[3] = inode->i_ino;
5492 + co_passage_page->params[4] = 0;
5494 + co_switch_wrapper();
5496 + ret = co_passage_page->params[4];
5498 + co_passage_page_release(flags);
5501 + printk("fuse_readdir: host returned error: %x\n", ret);
5504 + file->private_data = (void *)rd;
5510 +static int fuse_dir_release(struct inode *inode, struct file *file)
5512 + readdir_data_t *rd = file->private_data;
5513 + unsigned long flags;
5516 + co_passage_page_assert_valid();
5518 + co_passage_page_acquire(&flags);
5519 + co_passage_page->operation = CO_OPERATION_DEVICE;
5520 + co_passage_page->params[0] = CO_DEVICE_FILESYSTEM;
5521 + co_passage_page->params[1] = rd->fc->cofs_unit;
5522 + co_passage_page->params[2] = FUSE_DIR_RELEASE;
5523 + co_passage_page->params[3] = rd->inode;
5524 + co_passage_page->params[4] = 0;
5526 + co_switch_wrapper();
5528 + ret = co_passage_page->params[4];
5530 + co_passage_page_release(flags);
5533 + printk("fuse_readdir: host returned error: %x\n", ret);
5543 +static unsigned int iattr_to_fattr(struct iattr *iattr,
5544 + struct fuse_attr *fattr)
5546 + unsigned int ivalid = iattr->ia_valid;
5547 + unsigned int fvalid = 0;
5549 + memset(fattr, 0, sizeof(*fattr));
5551 + if(ivalid & ATTR_MODE)
5552 + fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
5553 + if(ivalid & ATTR_UID)
5554 + fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
5555 + if(ivalid & ATTR_GID)
5556 + fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
5557 + if(ivalid & ATTR_SIZE)
5558 + fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
5559 + /* You can only _set_ these together (they may change by themselves) */
5560 + if((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
5561 + fvalid |= FATTR_UTIME;
5563 + fattr->atime = iattr->ia_atime.tv_sec;
5564 + fattr->mtime = iattr->ia_mtime.tv_sec;
5566 + fattr->atime = iattr->ia_atime;
5567 + fattr->mtime = iattr->ia_mtime;
5574 +static int fuse_setattr(struct dentry *entry, struct iattr *attr)
5576 + struct inode *inode = entry->d_inode;
5577 + struct fuse_conn *fc = INO_FC(inode);
5578 + struct fuse_in in = FUSE_IN_INIT;
5579 + struct fuse_out out = FUSE_OUT_INIT;
5580 + struct fuse_setattr_in inarg;
5581 + struct fuse_setattr_out outarg;
5583 + /* FIXME: need to fix race between truncate and writepage */
5584 + if (attr->ia_valid & ATTR_SIZE)
5585 + fuse_sync_inode(inode);
5587 + memset(&inarg, 0, sizeof(inarg));
5588 + inarg.valid = iattr_to_fattr(attr, &inarg.attr);
5590 + in.h.opcode = FUSE_SETATTR;
5591 + in.h.ino = inode->i_ino;
5593 + in.args[0].size = sizeof(inarg);
5594 + in.args[0].value = &inarg;
5596 + out.args[0].size = sizeof(outarg);
5597 + out.args[0].value = &outarg;
5598 + request_send(fc, &in, &out);
5600 + if(!out.h.error) {
5601 + if(attr->ia_valid & ATTR_SIZE &&
5602 + outarg.attr.size < i_size_read(inode))
5603 + vmtruncate(inode, outarg.attr.size);
5605 + change_attributes(inode, &outarg.attr);
5607 + return out.h.error;
5610 +static int _fuse_dentry_revalidate(struct dentry *entry)
5612 + if(!entry->d_inode)
5614 + else if(time_after(jiffies, entry->d_time + FUSE_REVALIDATE_TIME)) {
5615 + struct inode *inode = entry->d_inode;
5616 + struct fuse_lookup_out outarg;
5620 + ret = fuse_do_lookup(entry->d_parent->d_inode, entry, &outarg,
5625 + if(outarg.ino != inode->i_ino)
5628 + change_attributes(inode, &outarg.attr);
5629 + inode->i_version = version;
5630 + entry->d_time = jiffies;
5637 +#define fuse_mknod _fuse_mknod
5639 +static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
5640 + struct kstat *stat)
5642 + struct inode *inode = entry->d_inode;
5643 + int err = fuse_revalidate(entry);
5645 + generic_fillattr(inode, stat);
5650 +static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
5651 + struct nameidata *nd)
5653 + struct inode *inode;
5654 + int err = fuse_lookup_iget(dir, entry, &inode);
5656 + return ERR_PTR(err);
5657 + return d_splice_alias(inode, entry);
5660 +static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
5661 + struct nameidata *nd)
5663 + return _fuse_create(dir, entry, mode);
5666 +static int fuse_permission(struct inode *inode, int mask,
5667 + struct nameidata *nd)
5669 + return _fuse_permission(inode, mask);
5672 +static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
5674 + return _fuse_dentry_revalidate(entry);
5676 +#else /* KERNEL_2_6 */
5678 +#define fuse_create _fuse_create
5679 +#define fuse_permission _fuse_permission
5681 +static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
5683 + struct inode *inode;
5684 + struct dentry *alias;
5686 + int err = fuse_lookup_iget(dir, entry, &inode);
5688 + return ERR_PTR(err);
5690 + if(inode && S_ISDIR(inode->i_mode) &&
5691 + (alias = d_find_alias(inode)) != NULL) {
5694 + printk("fuse: cannot assign an existing directory\n");
5695 + return ERR_PTR(-EPROTO);
5698 + d_add(entry, inode);
5702 +static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
5705 + return _fuse_mknod(dir, entry, mode, rdev);
5708 +static int fuse_dentry_revalidate(struct dentry *entry, int flags)
5710 + return _fuse_dentry_revalidate(entry);
5712 +#endif /* KERNEL_2_6 */
5715 +static struct inode_operations fuse_dir_inode_operations =
5717 + .lookup = fuse_lookup,
5718 + .create = fuse_create,
5719 + .mknod = fuse_mknod,
5720 + .mkdir = fuse_mkdir,
5721 + .symlink = fuse_symlink,
5722 + .unlink = fuse_unlink,
5723 + .rmdir = fuse_rmdir,
5724 + .rename = fuse_rename,
5725 + .link = fuse_link,
5726 + .setattr = fuse_setattr,
5727 + .permission = fuse_permission,
5729 + .getattr = fuse_getattr,
5731 + .revalidate = fuse_revalidate,
5735 +static struct file_operations fuse_dir_operations = {
5736 + .read = generic_read_dir,
5737 + .readdir = fuse_readdir,
5738 + .open = fuse_dir_open,
5739 + .release = fuse_dir_release,
5742 +static struct inode_operations fuse_file_inode_operations = {
5743 + .setattr = fuse_setattr,
5744 + .permission = fuse_permission,
5746 + .getattr = fuse_getattr,
5748 + .revalidate = fuse_revalidate,
5752 +static struct inode_operations fuse_symlink_inode_operations =
5754 + .setattr = fuse_setattr,
5755 + .readlink = fuse_readlink,
5756 + .follow_link = fuse_follow_link,
5758 + .getattr = fuse_getattr,
5760 + .revalidate = fuse_revalidate,
5764 +static struct dentry_operations fuse_dentry_operations = {
5765 + .d_revalidate = fuse_dentry_revalidate,
5769 + * Local Variables:
5770 + * indent-tabs-mode: t
5771 + * c-basic-offset: 8
5774 diff -urN a/fs/cofusefs/file.c b/fs/cofusefs/file.c
5775 --- a/fs/cofusefs/file.c
5776 +++ b/fs/cofusefs/file.c
5779 + FUSE: Filesystem in Userspace
5780 + Copyright (C) 2001-2004 Miklos Szeredi <miklos@szeredi.hu>
5782 + This program can be distributed under the terms of the GNU GPL.
5783 + See the file COPYING.
5785 +#include "fuse_i.h"
5787 +#include <linux/pagemap.h>
5788 +#include <linux/slab.h>
5790 +#include <linux/backing-dev.h>
5791 +#include <linux/writeback.h>
5795 +#define PageUptodate(page) Page_Uptodate(page)
5798 +static int fuse_open(struct inode *inode, struct file *file)
5800 + struct fuse_conn *fc = INO_FC(inode);
5801 + struct fuse_in in = FUSE_IN_INIT;
5802 + struct fuse_out out = FUSE_OUT_INIT;
5803 + struct fuse_open_in inarg;
5806 + err = generic_file_open(inode, file);
5810 + /* If opening the root node, no lookup has been performed on
5811 + it, so the attributes must be refreshed */
5812 + if(inode->i_ino == FUSE_ROOT_INO) {
5813 + int err = fuse_do_getattr(inode);
5818 + memset(&inarg, 0, sizeof(inarg));
5819 + inarg.flags = file->f_flags & ~O_EXCL;
5821 + in.h.opcode = FUSE_OPEN;
5822 + in.h.ino = inode->i_ino;
5824 + in.args[0].size = sizeof(inarg);
5825 + in.args[0].value = &inarg;
5826 + request_send(fc, &in, &out);
5827 + if(!out.h.error && !(fc->flags & FUSE_KERNEL_CACHE)) {
5829 + invalidate_inode_pages(inode->i_mapping);
5831 + invalidate_inode_pages(inode);
5835 + return out.h.error;
5838 +void fuse_sync_inode(struct inode *inode)
5841 + filemap_fdatawrite(inode->i_mapping);
5842 + filemap_fdatawait(inode->i_mapping);
5845 + filemap_fdatasync(inode->i_mapping);
5846 + filemap_fdatawait(inode->i_mapping);
5851 +static int fuse_release_old(struct inode *inode, struct file *file)
5853 + struct fuse_conn *fc = INO_FC(inode);
5854 + struct fuse_in *in = NULL;
5855 + struct fuse_open_in *inarg = NULL;
5856 + unsigned int s = sizeof(struct fuse_in) + sizeof(struct fuse_open_in);
5858 + in = kmalloc(s, GFP_NOFS);
5862 + inarg = (struct fuse_open_in *) (in + 1);
5863 + inarg->flags = file->f_flags & ~O_EXCL;
5865 + in->h.opcode = FUSE_RELEASE;
5866 + in->h.ino = inode->i_ino;
5868 + in->args[0].size = sizeof(struct fuse_open_in);
5869 + in->args[0].value = inarg;
5870 + if(!request_send_noreply(fc, in))
5877 +static int fuse_release(struct inode *inode, struct file *file)
5879 + struct fuse_conn *fc = INO_FC(inode);
5880 + struct fuse_in in = FUSE_IN_INIT;
5881 + struct fuse_out out = FUSE_OUT_INIT;
5882 + struct fuse_open_in inarg;
5884 + if(file->f_mode & FMODE_WRITE)
5885 + fuse_sync_inode(inode);
5887 + if (fc->oldrelease)
5888 + return fuse_release_old(inode, file);
5890 + memset(&inarg, 0, sizeof(inarg));
5891 + inarg.flags = file->f_flags & ~O_EXCL;
5893 + in.h.opcode = FUSE_RELEASE2;
5894 + in.h.ino = inode->i_ino;
5896 + in.args[0].size = sizeof(inarg);
5897 + in.args[0].value = &inarg;
5898 + request_send(fc, &in, &out);
5899 + if (out.h.error == -ENOSYS) {
5900 + fc->oldrelease = 1;
5901 + return fuse_release_old(inode, file);
5906 +static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
5908 + struct inode *inode = de->d_inode;
5909 + struct fuse_conn *fc = INO_FC(inode);
5910 + struct fuse_in in = FUSE_IN_INIT;
5911 + struct fuse_out out = FUSE_OUT_INIT;
5912 + struct fuse_fsync_in inarg;
5914 + memset(&inarg, 0, sizeof(inarg));
5915 + inarg.datasync = datasync;
5917 + in.h.opcode = FUSE_FSYNC;
5918 + in.h.ino = inode->i_ino;
5920 + in.args[0].size = sizeof(inarg);
5921 + in.args[0].value = &inarg;
5922 + request_send(fc, &in, &out);
5923 + return out.h.error;
5925 + /* FIXME: need to ensure, that all write requests issued
5926 + before this request are completed. Should userspace take
5930 +static int fuse_readpage(struct file *file, struct page *page)
5932 + struct inode *inode = page->mapping->host;
5933 + struct fuse_conn *fc = INO_FC(inode);
5934 + struct fuse_in in = FUSE_IN_INIT;
5935 + struct fuse_out out = FUSE_OUT_INIT;
5936 + struct fuse_read_in inarg;
5939 + buffer = kmap(page);
5941 + memset(&inarg, 0, sizeof(inarg));
5942 + inarg.offset = (unsigned long long) page->index << PAGE_CACHE_SHIFT;
5943 + inarg.size = PAGE_CACHE_SIZE;
5945 + in.h.opcode = FUSE_READ;
5946 + in.h.ino = inode->i_ino;
5948 + in.args[0].size = sizeof(inarg);
5949 + in.args[0].value = &inarg;
5952 + out.args[0].size = PAGE_CACHE_SIZE;
5953 + out.args[0].value = buffer;
5955 + request_send(fc, &in, &out);
5956 + if(!out.h.error) {
5957 + size_t outsize = out.args[0].size;
5958 + if(outsize < PAGE_CACHE_SIZE)
5959 + memset(buffer + outsize, 0, PAGE_CACHE_SIZE - outsize);
5960 + flush_dcache_page(page);
5961 + SetPageUptodate(page);
5965 + unlock_page(page);
5967 + return out.h.error;
5970 +static int fuse_is_block_uptodate(struct address_space *mapping,
5971 + struct inode *inode, size_t bl_index)
5973 + size_t index = bl_index << FUSE_BLOCK_PAGE_SHIFT;
5974 + size_t end_index = ((bl_index + 1) << FUSE_BLOCK_PAGE_SHIFT) - 1;
5975 + size_t file_end_index = i_size_read(inode) >> PAGE_CACHE_SHIFT;
5977 + if (end_index > file_end_index)
5978 + end_index = file_end_index;
5980 + for (; index <= end_index; index++) {
5981 + struct page *page = find_get_page(mapping, index);
5986 + if (!PageUptodate(page)) {
5987 + page_cache_release(page);
5991 + page_cache_release(page);
5998 +static int fuse_cache_block(struct address_space *mapping,
5999 + struct inode *inode, char *bl_buf,
6002 + size_t start_index = bl_index << FUSE_BLOCK_PAGE_SHIFT;
6003 + size_t end_index = ((bl_index + 1) << FUSE_BLOCK_PAGE_SHIFT) - 1;
6004 + size_t file_end_index = i_size_read(inode) >> PAGE_CACHE_SHIFT;
6008 + if (end_index > file_end_index)
6009 + end_index = file_end_index;
6011 + for (i = 0; start_index + i <= end_index; i++) {
6012 + size_t index = start_index + i;
6013 + struct page *page;
6016 + page = grab_cache_page(mapping, index);
6020 + if (!PageUptodate(page)) {
6021 + buffer = kmap(page);
6022 + memcpy(buffer, bl_buf + i * PAGE_CACHE_SIZE,
6024 + flush_dcache_page(page);
6025 + SetPageUptodate(page);
6029 + unlock_page(page);
6030 + page_cache_release(page);
6036 +static int fuse_file_read_block(struct inode *inode, char *bl_buf,
6039 + struct fuse_conn *fc = INO_FC(inode);
6040 + struct fuse_in in = FUSE_IN_INIT;
6041 + struct fuse_out out = FUSE_OUT_INIT;
6042 + struct fuse_read_in inarg;
6044 + memset(&inarg, 0, sizeof(inarg));
6045 + inarg.offset = (unsigned long long) bl_index << FUSE_BLOCK_SHIFT;
6046 + inarg.size = FUSE_BLOCK_SIZE;
6048 + in.h.opcode = FUSE_READ;
6049 + in.h.ino = inode->i_ino;
6051 + in.args[0].size = sizeof(inarg);
6052 + in.args[0].value = &inarg;
6055 + out.args[0].size = FUSE_BLOCK_SIZE;
6056 + out.args[0].value = bl_buf;
6058 + request_send(fc, &in, &out);
6060 + if (!out.h.error) {
6061 + size_t outsize = out.args[0].size;
6062 + if (outsize < FUSE_BLOCK_SIZE)
6063 + memset(bl_buf + outsize, 0, FUSE_BLOCK_SIZE - outsize);
6066 + return out.h.error;
6069 +static void fuse_file_bigread(struct address_space *mapping,
6070 + struct inode *inode, loff_t pos, size_t count)
6072 + size_t bl_index = pos >> FUSE_BLOCK_SHIFT;
6073 + size_t bl_end_index = (pos + count) >> FUSE_BLOCK_SHIFT;
6074 + size_t bl_file_end_index = i_size_read(inode) >> FUSE_BLOCK_SHIFT;
6076 + if (bl_end_index > bl_file_end_index)
6077 + bl_end_index = bl_file_end_index;
6079 + while (bl_index <= bl_end_index) {
6081 + char *bl_buf = kmalloc(FUSE_BLOCK_SIZE, GFP_NOFS);
6084 + res = fuse_is_block_uptodate(mapping, inode, bl_index);
6086 + res = fuse_file_read_block(inode, bl_buf, bl_index);
6088 + fuse_cache_block(mapping, inode, bl_buf, bl_index);
6094 +static ssize_t fuse_file_read(struct file *filp, char *buf,
6095 + size_t count, loff_t * ppos)
6097 + struct address_space *mapping = filp->f_dentry->d_inode->i_mapping;
6098 + struct inode *inode = mapping->host;
6099 + struct fuse_conn *fc = INO_FC(inode);
6101 + if(fc->flags & FUSE_LARGE_READ) {
6102 + /* Don't allow this to get mixed up with writes */
6103 + down(&inode->i_sem);
6104 + fuse_file_bigread(mapping, inode, *ppos, count);
6105 + up(&inode->i_sem);
6108 + return generic_file_read(filp, buf, count, ppos);
6111 +static int write_buffer(struct inode *inode, struct page *page,
6112 + unsigned offset, size_t count)
6114 + struct fuse_conn *fc = INO_FC(inode);
6115 + struct fuse_in in = FUSE_IN_INIT;
6116 + struct fuse_out out = FUSE_OUT_INIT;
6117 + struct fuse_write_in inarg;
6120 + buffer = kmap(page);
6122 + memset(&inarg, 0, sizeof(inarg));
6123 + inarg.offset = ((unsigned long long) page->index << PAGE_CACHE_SHIFT) +
6125 + inarg.size = count;
6127 + in.h.opcode = FUSE_WRITE;
6128 + in.h.ino = inode->i_ino;
6130 + in.args[0].size = sizeof(inarg);
6131 + in.args[0].value = &inarg;
6132 + in.args[1].size = count;
6133 + in.args[1].value = buffer + offset;
6134 + request_send(fc, &in, &out);
6137 + SetPageError(page);
6139 + return out.h.error;
6142 +static int get_write_count(struct inode *inode, struct page *page)
6144 + unsigned long end_index;
6145 + loff_t size = i_size_read(inode);
6148 + end_index = size >> PAGE_CACHE_SHIFT;
6149 + if(page->index < end_index)
6150 + count = PAGE_CACHE_SIZE;
6152 + count = size & (PAGE_CACHE_SIZE - 1);
6153 + if(page->index > end_index || count == 0)
6161 +static void write_buffer_end(struct fuse_conn *fc, struct fuse_in *in,
6162 + struct fuse_out *out, void *_page)
6164 + struct page *page = (struct page *) _page;
6166 + if(out->h.error) {
6167 + SetPageError(page);
6168 + if(out->h.error == -ENOSPC)
6169 + set_bit(AS_ENOSPC, &page->mapping->flags);
6171 + set_bit(AS_EIO, &page->mapping->flags);
6173 + end_page_writeback(page);
6178 +static int write_buffer_nonblock(struct inode *inode, struct page *page,
6179 + unsigned offset, size_t count)
6182 + struct fuse_conn *fc = INO_FC(inode);
6183 + struct fuse_in *in = NULL;
6184 + struct fuse_out *out = NULL;
6185 + struct fuse_write_in *inarg = NULL;
6187 + unsigned int s = sizeof(struct fuse_in) + sizeof(struct fuse_out) +
6188 + sizeof(struct fuse_write_in);
6190 + in = kmalloc(s, GFP_NOFS);
6194 + out = (struct fuse_out *)(in + 1);
6195 + inarg = (struct fuse_write_in *)(out + 1);
6197 + buffer = kmap(page);
6199 + inarg->offset = ((unsigned long long) page->index << PAGE_CACHE_SHIFT) + offset;
6200 + inarg->size = count;
6202 + in->h.opcode = FUSE_WRITE;
6203 + in->h.ino = inode->i_ino;
6205 + in->args[0].size = sizeof(struct fuse_write_in);
6206 + in->args[0].value = inarg;
6207 + in->args[1].size = count;
6208 + in->args[1].value = buffer + offset;
6209 + err = request_send_nonblock(fc, in, out, write_buffer_end, page);
6211 + if(err != -EWOULDBLOCK)
6212 + SetPageError(page);
6219 +static int fuse_writepage(struct page *page, struct writeback_control *wbc)
6222 + struct inode *inode = page->mapping->host;
6223 + unsigned count = get_write_count(inode, page);
6227 + /* FIXME: check sync_mode, and wait for previous writes (or
6228 + signal userspace to do this) */
6229 + if(wbc->nonblocking) {
6230 + SetPageWriteback(page);
6231 + err = write_buffer_nonblock(inode, page, 0, count);
6233 + ClearPageWriteback(page);
6234 + if(err == -EWOULDBLOCK) {
6235 + __set_page_dirty_nobuffers(page);
6239 + err = write_buffer(inode, page, 0, count);
6242 + unlock_page(page);
6246 +static int fuse_writepage(struct page *page)
6249 + struct inode *inode = page->mapping->host;
6250 + int count = get_write_count(inode, page);
6253 + err = write_buffer(inode, page, 0, count);
6255 + unlock_page(page);
6260 +static int fuse_prepare_write(struct file *file, struct page *page,
6261 + unsigned offset, unsigned to)
6267 +static int fuse_commit_write(struct file *file, struct page *page,
6268 + unsigned offset, unsigned to)
6271 + struct inode *inode = page->mapping->host;
6273 + err = write_buffer(inode, page, offset, to - offset);
6275 + loff_t pos = (page->index << PAGE_CACHE_SHIFT) + to;
6276 + if(pos > i_size_read(inode))
6277 + i_size_write(inode, pos);
6282 +static struct file_operations fuse_file_operations = {
6283 + .read = fuse_file_read,
6284 + .write = generic_file_write,
6285 + .mmap = generic_file_mmap,
6286 + .open = fuse_open,
6287 + .release = fuse_release,
6288 + .fsync = fuse_fsync,
6290 + .sendfile = generic_file_sendfile,
6294 +static struct address_space_operations fuse_file_aops = {
6295 + .readpage = fuse_readpage,
6296 + .writepage = fuse_writepage,
6297 + .prepare_write = fuse_prepare_write,
6298 + .commit_write = fuse_commit_write,
6301 +void fuse_init_file_inode(struct inode *inode)
6304 + struct fuse_conn *fc = INO_FC(inode);
6305 + /* Readahead somehow defeats big reads on 2.6 (says Michael
6307 + if(fc->flags & FUSE_LARGE_READ)
6308 + inode->i_mapping->backing_dev_info->ra_pages = 0;
6310 + inode->i_fop = &fuse_file_operations;
6311 + inode->i_data.a_ops = &fuse_file_aops;
6315 + * Local Variables:
6316 + * indent-tabs-mode: t
6317 + * c-basic-offset: 8
6320 diff -urN a/fs/cofusefs/fuse_i.h b/fs/cofusefs/fuse_i.h
6321 --- a/fs/cofusefs/fuse_i.h
6322 +++ b/fs/cofusefs/fuse_i.h
6325 + COFUSE: Filesystem in an host of Cooperative Linux
6326 + Copyright (C) 2004 Dan Aloni <da-x@colinux.org>
6328 + based on FUSE: Filesystem in Userspace
6329 + Copyright (C) 2001-2004 Miklos Szeredi <miklos@szeredi.hu>
6331 + This program can be distributed under the terms of the GNU GPL.
6332 + See the file COPYING.
6336 +#include <linux/version.h>
6337 +#include <linux/config.h>
6339 +#ifndef CONFIG_COOPERATIVE
6340 +#include <linux/cofuse.h>
6342 +#include <linux/cooperative_internal.h>
6345 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
6346 +#error Kernel version 2.5.* not supported
6349 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
6354 +#include <linux/config.h>
6355 +#ifdef CONFIG_MODVERSIONS
6356 +#define MODVERSIONS
6357 +#include <linux/modversions.h>
6359 +#include <config.h>
6360 +#ifndef HAVE_I_SIZE_FUNC
6361 +#define i_size_read(inode) ((inode)->i_size)
6362 +#define i_size_write(inode, size) do { (inode)->i_size = size; } while(0)
6365 +#include <linux/kernel.h>
6366 +#include <linux/module.h>
6367 +#include <linux/fs.h>
6368 +#include <linux/list.h>
6369 +#include <linux/spinlock.h>
6371 +/** Read combining parameters */
6372 +#define FUSE_BLOCK_SHIFT 16
6373 +#define FUSE_BLOCK_SIZE 65536
6374 +#define FUSE_BLOCK_MASK 0xffff0000
6376 +#define FUSE_BLOCK_PAGE_SHIFT (FUSE_BLOCK_SHIFT - PAGE_CACHE_SHIFT)
6379 + * A Fuse connection.
6381 + * This structure is created, when the client device is opened, and is
6382 + * destroyed, when the client device is closed _and_ the filesystem is
6386 + /** The superblock of the mounted filesystem */
6387 + struct super_block *sb;
6389 +#ifndef CONFIG_COOPERATIVE
6390 + /** The opened client device */
6391 + struct file *file;
6395 + /** The user id for this mount */
6398 + /** The fuse mount flags for this mount */
6399 + unsigned int flags;
6401 + /** Is the new (synchronous) release not supported by
6403 + unsigned int oldrelease;
6405 + char opt_pathname[0x80];
6407 +#ifndef CONFIG_COOPERATIVE
6408 + /** Readers of the connection are waiting on this */
6409 + wait_queue_head_t waitq;
6411 + /** The list of pending requests */
6412 + struct list_head pending;
6414 + /** The list of requests being processed */
6415 + struct list_head processing;
6417 + /** Controls the maximum number of outstanding requests */
6418 + struct semaphore outstanding;
6420 + /** The next unique request id */
6425 +/** One input argument of a request */
6426 +struct fuse_in_arg {
6427 + unsigned int size;
6428 + const void *value;
6431 +/** The request input */
6433 + struct fuse_in_header h;
6434 + unsigned int numargs;
6435 + struct fuse_in_arg args[3];
6438 +/** One output argument of a request */
6439 +struct fuse_out_arg {
6440 + unsigned int size;
6444 +/** The request output */
6446 + struct fuse_out_header h;
6447 + unsigned int argvar;
6448 + unsigned int numargs;
6449 + struct fuse_out_arg args[3];
6452 +#define FUSE_IN_INIT { {0, 0, 0, current->fsuid, current->fsgid}, 0}
6453 +#define FUSE_OUT_INIT { {0, 0}, 0, 0}
6456 +typedef void (*fuse_reqend_t)(struct fuse_conn *, struct fuse_in *,
6457 + struct fuse_out *, void *data);
6460 + * A request to the client
6463 + /** The request list */
6464 + struct list_head list;
6466 + /** True if the request is synchronous */
6467 + unsigned int issync:1;
6469 + /** The request is locked */
6470 + unsigned int locked:1;
6472 + /** The request has been interrupted while it was locked */
6473 + unsigned int interrupted:1;
6475 + /* The request has been sent to the client */
6476 + unsigned int sent:1;
6478 + /* The request is finished */
6479 + unsigned int finished:1;
6481 + /** The request input */
6482 + struct fuse_in *in;
6484 + /** The request output */
6485 + struct fuse_out *out;
6487 + /** Used to wake up the task waiting for completion of request*/
6488 + wait_queue_head_t waitq;
6490 + /** Request completion callback */
6491 + fuse_reqend_t end;
6498 +#define SB_FC(sb) ((sb)->s_fs_info)
6500 +#define SB_FC(sb) ((sb)->u.generic_sbp)
6502 +#define INO_FC(inode) SB_FC((inode)->i_sb)
6503 +#define DEV_FC(file) ((struct fuse_conn *) (file)->private_data)
6507 + * The proc entry for the client device ("/proc/fs/fuse/dev")
6509 +extern struct proc_dir_entry *proc_fuse_dev;
6512 + * The lock to protect fuses structures
6514 +extern spinlock_t cofuse_lock;
6518 + * Get a filled in inode
6520 +struct inode *cofuse_iget(struct super_block *sb, ino_t ino,
6521 + struct fuse_attr *attr, int version);
6525 + * Initialise operations on regular file
6527 +void cofuse_init_file_inode(struct inode *inode);
6530 + * Check if the connection can be released, and if yes, then free the
6531 + * connection structure
6533 +void cofuse_release_conn(struct fuse_conn *fc);
6536 + * Initialize the client device
6538 +int cofuse_dev_init(void);
6541 + * Cleanup the client device
6543 +void cofuse_dev_cleanup(void);
6546 + * Initialize the fuse filesystem
6548 +int cofuse_fs_init(void);
6551 + * Cleanup the fuse filesystem
6553 +void cofuse_fs_cleanup(void);
6559 +void cofuse_request_send(struct fuse_conn *fc, struct fuse_in *in,
6560 + struct fuse_out *out);
6563 + * Send a request for which a reply is not expected
6565 +int cofuse_request_send_noreply(struct fuse_conn *fc, struct fuse_in *in);
6569 + * Send a synchronous request without blocking
6571 +int cofuse_request_send_nonblock(struct fuse_conn *fc, struct fuse_in *in,
6572 + struct fuse_out *out, fuse_reqend_t end, void *data);
6575 + * Get the attributes of a file
6577 +int cofuse_do_getattr(struct inode *inode);
6580 + * Write dirty pages
6582 +void cofuse_sync_inode(struct inode *inode);
6585 + * Local Variables:
6586 + * indent-tabs-mode: t
6587 + * c-basic-offset: 8
6591 +#define COFUSE_VERSION "0.1"
6592 +#define FUSE_VERSION COFUSE_VERSION
6594 +#define fuse_init_file_inode cofuse_init_file_inode
6595 +#define fuse_do_getattr cofuse_do_getattr
6596 +#define fuse_sync_inode cofuse_sync_inode
6597 +#define fuse_lock cofuse_lock
6599 +#define request_send cofuse_request_send
6600 +#define request_send_noreply cofuse_request_send_noreply
6601 +#define request_send_nonblock cofuse_request_send_nonblock
6602 +#define release_conn cofuse_release_conn
6603 +#define fuse_iget cofuse_iget
6604 +#define fuse_dev_init cofuse_dev_init
6605 +#define fuse_dev_cleanup cofuse_dev_cleanup
6606 +#define fuse_fs_init cofuse_fs_init
6607 +#define fuse_fs_cleanup cofuse_fs_cleanup
6609 +extern struct fuse_conn *cofs_volumes[CO_MODULE_MAX_COFS];
6611 +/** Data passed to mount */
6612 +struct cofuse_mount_data {
6613 + struct fuse_mount_data *fuse;
6616 + unsigned long file_mode;
6617 + unsigned long dir_mode;
6618 + unsigned long flags;
6621 diff -urN a/fs/cofusefs/inode.c b/fs/cofusefs/inode.c
6622 --- a/fs/cofusefs/inode.c
6623 +++ b/fs/cofusefs/inode.c
6626 + FUSE: Filesystem in Userspace
6627 + Copyright (C) 2001 Miklos Szeredi (miklos@szeredi.hu)
6629 + This program can be distributed under the terms of the GNU GPL.
6630 + See the file COPYING.
6633 +#include "fuse_i.h"
6635 +#include <linux/pagemap.h>
6636 +#include <linux/sched.h>
6637 +#include <linux/slab.h>
6638 +#include <linux/file.h>
6639 +#include <linux/ctype.h>
6640 +#include <linux/proc_fs.h>
6642 +#include <linux/statfs.h>
6645 +#define FUSE_SUPER_MAGIC 0x65735546
6648 +#define kstatfs statfs
6651 +#ifndef FS_BINARY_MOUNTDATA
6652 +#define FS_BINARY_MOUNTDATA 0
6655 +static void fuse_read_inode(struct inode *inode)
6660 +static void fuse_clear_inode(struct inode *inode)
6662 + unsigned long flags;
6663 + struct fuse_conn *fc = INO_FC(inode);
6665 +#ifndef CONFIG_COOPERATIVE
6666 + struct fuse_in *in = NULL;
6667 + struct fuse_forget_in *inarg = NULL;
6668 + unsigned int s = sizeof(struct fuse_in) + sizeof(struct fuse_forget_in);
6673 + in = kmalloc(s, GFP_NOFS);
6677 + inarg = (struct fuse_forget_in *) (in + 1);
6678 + inarg->version = inode->i_version;
6680 + in->h.opcode = FUSE_FORGET;
6681 + in->h.ino = inode->i_ino;
6683 + in->args[0].size = sizeof(struct fuse_forget_in);
6684 + in->args[0].value = inarg;
6686 + if(!request_send_noreply(fc, in))
6691 + if (FUSE_ROOT_INO == inode->i_ino)
6694 + co_passage_page_assert_valid();
6695 + co_passage_page_acquire(&flags);
6696 + co_passage_page->operation = CO_OPERATION_DEVICE;
6697 + co_passage_page->params[0] = CO_DEVICE_FILESYSTEM;
6698 + co_passage_page->params[1] = fc->cofs_unit;
6699 + co_passage_page->params[2] = FUSE_FORGET;
6700 + co_passage_page->params[3] = inode->i_ino;
6701 + co_switch_wrapper();
6702 + co_passage_page_release(flags);
6706 +static void fuse_put_super(struct super_block *sb)
6708 + struct fuse_conn *fc = SB_FC(sb);
6710 + spin_lock(&fuse_lock);
6714 + /* Flush all readers on this fs */
6715 +#ifndef CONFIG_COOPERATIVE
6716 + wake_up_all(&fc->waitq);
6720 + spin_unlock(&fuse_lock);
6723 +static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
6725 + stbuf->f_type = FUSE_SUPER_MAGIC;
6726 + stbuf->f_bsize = attr->block_size;
6727 + stbuf->f_blocks = attr->blocks;
6728 + stbuf->f_bfree = stbuf->f_bavail = attr->blocks_free;
6729 + stbuf->f_files = attr->files;
6730 + stbuf->f_ffree = attr->files_free;
6731 + /* Is this field necessary? Most filesystems ignore it...
6732 + stbuf->f_fsid.val[0] = (FUSE_SUPER_MAGIC>>16)&0xffff;
6733 + stbuf->f_fsid.val[1] = FUSE_SUPER_MAGIC &0xffff; */
6734 + stbuf->f_namelen = attr->namelen;
6737 +static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
6739 + struct fuse_conn *fc = SB_FC(sb);
6740 + struct fuse_in in = FUSE_IN_INIT;
6741 + struct fuse_out out = FUSE_OUT_INIT;
6742 + struct fuse_statfs_out outarg;
6745 + in.h.opcode = FUSE_STATFS;
6747 + out.args[0].size = sizeof(outarg);
6748 + out.args[0].value = &outarg;
6749 + request_send(fc, &in, &out);
6751 + convert_fuse_statfs(buf, &outarg.st);
6753 + return out.h.error;
6756 +#ifndef CONFIG_COOPERATIVE
6758 +static struct fuse_conn *get_conn(struct fuse_mount_data *d)
6760 + struct fuse_conn *fc = NULL;
6761 + struct file *file;
6762 + struct inode *ino;
6765 + printk("fuse_read_super: Bad mount data\n");
6769 + if(d->version != FUSE_KERNEL_VERSION) {
6770 + printk("fuse_read_super: Bad version: %i\n", d->version);
6774 + file = fget(d->fd);
6777 + ino = file->f_dentry->d_inode;
6779 + if(!ino || !proc_fuse_dev || proc_fuse_dev->low_ino != ino->i_ino) {
6780 + printk("fuse_read_super: Bad file: %i\n", d->fd);
6784 + fc = file->private_data;
6793 +static int _atoi(const char *s, const char **out)
6795 + /* lib/spprintf.h */
6799 + while (isdigit(*s))
6800 + i = i*10 + *(s++) - '0';
6807 +static struct fuse_conn *co_get_conn(struct cofuse_mount_data *d)
6811 + unsigned long flags;
6812 + struct fuse_conn *conn = NULL;
6813 + const char *name, *next;
6816 + printk("cofuse_read_super: Bad mount data\n");
6822 + if (strncmp("cofs", name, 4) == 0)
6825 + index = _atoi(name, &next);
6826 + if (index < 0 || index >= CO_MODULE_MAX_COFS) {
6827 + printk("cofuse_read_super: Invalid index %d\n", index);
6831 + if (cofs_volumes[index])
6832 + return cofs_volumes[index];
6834 + conn = kmalloc(sizeof(struct fuse_conn), GFP_KERNEL);
6838 + memset(conn, 0, sizeof(*conn));
6840 + if (*next == ':') {
6841 + snprintf(conn->opt_pathname, sizeof(conn->opt_pathname), "%s", next+1);
6844 + conn->cofs_unit = index;
6846 + co_passage_page_assert_valid();
6847 + co_passage_page_acquire(&flags);
6848 + co_passage_page->operation = CO_OPERATION_DEVICE;
6849 + co_passage_page->params[0] = CO_DEVICE_FILESYSTEM;
6850 + co_passage_page->params[1] = conn->cofs_unit;
6851 + co_passage_page->params[2] = FUSE_MOUNT;
6852 + co_passage_page->params[5] = d->uid;
6853 + co_passage_page->params[6] = d->gid;
6854 + co_passage_page->params[7] = d->dir_mode;
6855 + co_passage_page->params[8] = d->file_mode;
6856 + memcpy(&co_passage_page->params[30], conn->opt_pathname, strlen(conn->opt_pathname) + 1);
6857 + co_switch_wrapper();
6858 + ret = co_passage_page->params[4];
6859 + co_passage_page_release(flags);
6871 +static struct inode *get_root_inode(struct super_block *sb, unsigned int mode)
6873 + struct fuse_attr attr;
6874 + memset(&attr, 0, sizeof(attr));
6877 + return fuse_iget(sb, 1, &attr, 0);
6883 +static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp)
6885 + __u32 *objp = vobjp;
6886 + unsigned long ino = objp[0];
6887 + /* __u32 generation = objp[1]; */
6888 + struct inode *inode;
6889 + struct dentry *entry;
6892 + return ERR_PTR(-ESTALE);
6894 + inode = ilookup(sb, ino);
6896 + return ERR_PTR(-ESTALE);
6898 + entry = d_alloc_anon(inode);
6901 + return ERR_PTR(-ENOMEM);
6907 +static struct export_operations fuse_export_operations = {
6908 + .get_dentry = fuse_get_dentry,
6912 +static struct super_operations fuse_super_operations = {
6913 + .read_inode = fuse_read_inode,
6914 + .clear_inode = fuse_clear_inode,
6915 + .put_super = fuse_put_super,
6916 + .statfs = fuse_statfs,
6919 +static int fuse_read_super(struct super_block *sb, void *data, int silent)
6921 + struct fuse_conn *fc;
6922 + struct inode *root;
6923 +#ifndef CONFIG_COOPERATIVE
6924 + struct fuse_mount_data *d = data;
6926 + struct cofuse_mount_data *co_d = data;
6927 + struct fuse_mount_data *d = co_d->fuse;
6929 + sb->s_blocksize = PAGE_CACHE_SIZE;
6930 + sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
6931 + sb->s_magic = FUSE_SUPER_MAGIC;
6932 + sb->s_op = &fuse_super_operations;
6933 + sb->s_maxbytes = MAX_LFS_FILESIZE;
6935 + sb->s_export_op = &fuse_export_operations;
6938 +#ifndef CONFIG_COOPERATIVE
6941 + fc = co_get_conn(co_d);
6945 + spin_lock(&fuse_lock);
6946 + if(fc->sb != NULL) {
6947 + printk("fuse_read_super: connection already mounted\n");
6948 + spin_unlock(&fuse_lock);
6952 + fc->flags = d->flags;
6954 + spin_unlock(&fuse_lock);
6956 + /* fc is needed in fuse_init_file_inode which could be called
6957 + from get_root_inode */
6960 + root = get_root_inode(sb, d->rootmode);
6961 + if(root == NULL) {
6962 + printk("fuse_read_super: failed to get root inode\n");
6966 + sb->s_root = d_alloc_root(root);
6968 + printk("fuse_read_super: failed to allocate root\n");
6975 +#ifdef CONFIG_COOPERATIVE
6977 + * cofuse_getopt and cofuse_parse_options were
6978 + * addopted from smb
6983 + unsigned long flag;
6988 + * cofuse_getopt - option parser
6989 + * based on smb_getopt from fs/smbfs
6991 + * @caller: name of the caller, for error messages
6992 + * @options: the options string
6993 + * @opts: an array of &struct option entries controlling parser operations
6994 + * @optopt: output; will contain the current option
6995 + * @optarg: output; will contain the value (if one exists)
6996 + * @flag: output; may be NULL; should point to a long for or'ing flags
6997 + * @value: output; may be NULL; will be overwritten with the integer value
6998 + * of the current argument.
7000 + * Helper to parse options on the format used by mount ("a=b,c=d,e,f").
7001 + * Returns opts->val if a matching entry in the 'opts' array is found,
7002 + * 0 when no more tokens are found, -1 if an error is encountered.
7004 +static int cofuse_getopt(char *caller, char **options, struct option *opts,
7005 + char **optopt, char **optarg, unsigned long *flag,
7006 + unsigned long *value)
7013 + if ((token = strsep(options, ",")) == NULL)
7015 + } while (*token == '\0');
7019 + if ((val = strchr (token, '=')) != NULL) {
7022 + *value = simple_strtoul(val, NULL, 0);
7026 + for (i = 0; opts[i].name != NULL; i++) {
7027 + if (!strcmp(opts[i].name, token)) {
7028 + if (!opts[i].flag && (!val || !*val)) {
7029 + printk("%s: the %s option requires an argument\n",
7034 + if (flag && opts[i].flag)
7035 + *flag |= opts[i].flag;
7037 + return opts[i].val;
7040 + printk("%s: Unrecognized mount option %s\n", caller, token);
7044 +static struct option opts[] = {
7045 + { "uid", 0, 'u' },
7046 + { "gid", 0, 'g' },
7047 + { "fmask", 0, 'f' },
7048 + { "dmask", 0, 'd' },
7053 + * parse_options - based on parse_options from fs/smbfs
7055 +static int parse_options(struct cofuse_mount_data *mnt, char *options)
7058 + unsigned long flags;
7059 + unsigned long value;
7064 + while ((c = cofuse_getopt("cofuse", &options, opts,
7065 + &optopt, &optarg, &flags, &value)) > 0)
7069 + /* got a "flag" option */
7078 + mnt->file_mode = (value & S_IRWXUGO) | S_IFREG;
7081 + mnt->dir_mode = (value & S_IRWXUGO) | S_IFDIR;
7084 + printk("cofs: Unrecognized mount option %s\n", optopt);
7089 + mnt->flags = flags;
7095 +static struct super_block *fuse_get_sb(struct file_system_type *fs_type,
7096 + int flags, const char *dev_name,
7099 +#ifdef CONFIG_COOPERATIVE
7100 + struct cofuse_mount_data co_md = {0, };
7101 + struct fuse_mount_data md = {0, };
7104 + co_md.uid = current->uid;
7105 + co_md.gid = current->gid;
7106 + co_md.dir_mode = FUSE_S_IRWXU | FUSE_S_IRGRP | FUSE_S_IXGRP |
7107 + FUSE_S_IROTH | FUSE_S_IXOTH | S_IFDIR;
7108 + co_md.file_mode = FUSE_S_IRWXU | FUSE_S_IRGRP | FUSE_S_IXGRP |
7109 + FUSE_S_IROTH | FUSE_S_IXOTH | S_IFREG;
7111 + ret = parse_options(&co_md, raw_data);
7113 + return ERR_PTR(-EINVAL);
7115 + md.rootmode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
7116 + md.flags = FUSE_ALLOW_OTHER | FUSE_DEFAULT_PERMISSIONS;
7119 + snprintf(co_md.name, sizeof(co_md.name), "%s", dev_name);
7121 + return get_sb_nodev(fs_type, flags, &co_md, fuse_read_super);
7123 + return get_sb_nodev(fs_type, flags, raw_data, fuse_read_super);
7127 +static struct file_system_type fuse_fs_type = {
7128 + .owner = THIS_MODULE,
7130 + .get_sb = fuse_get_sb,
7131 + .kill_sb = kill_anon_super,
7132 + .fs_flags = FS_BINARY_MOUNTDATA,
7135 +static struct super_block *fuse_read_super_compat(struct super_block *sb,
7136 + void *data, int silent)
7138 + int err = fuse_read_super(sb, data, silent);
7145 +static DECLARE_FSTYPE(fuse_fs_type, "cofs", fuse_read_super_compat, 0);
7152 + res = register_filesystem(&fuse_fs_type);
7154 + printk("fuse: failed to register filesystem\n");
7159 +void fuse_fs_cleanup()
7161 + unregister_filesystem(&fuse_fs_type);
7165 + * Local Variables:
7166 + * indent-tabs-mode: t
7167 + * c-basic-offset: 8
7170 diff -urN a/fs/cofusefs/util.c b/fs/cofusefs/util.c
7171 --- a/fs/cofusefs/util.c
7172 +++ b/fs/cofusefs/util.c
7175 + FUSE: Filesystem in Userspace
7176 + Copyright (C) 2001-2004 Miklos Szeredi <miklos@szeredi.hu>
7178 + This program can be distributed under the terms of the GNU GPL.
7179 + See the file COPYING.
7182 +#include "fuse_i.h"
7184 +#include <linux/init.h>
7185 +#include <linux/slab.h>
7187 +MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
7188 +MODULE_DESCRIPTION("Filesystem in Userspace");
7189 +#ifdef MODULE_LICENSE
7190 +MODULE_LICENSE("GPL");
7193 +spinlock_t fuse_lock = SPIN_LOCK_UNLOCKED;
7195 +/* Must be called with the fuse lock held */
7196 +void release_conn(struct fuse_conn *fc)
7198 +#ifdef CONFIG_COOPERATIVE
7199 + if (cooperative_mode_enabled()) {
7200 + cofs_volumes[fc->cofs_unit] = NULL;
7205 + if(fc->sb == NULL && fc->file == NULL) {
7211 +int __init cofuse_init(void)
7215 + printk(KERN_DEBUG "cofuse init %s (API version %i.%i)\n",
7217 + FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
7219 + res = fuse_fs_init();
7223 + res = fuse_dev_init();
7225 + goto err_fs_cleanup;
7230 + fuse_fs_cleanup();
7235 +void __exit cofuse_exit(void)
7237 + printk(KERN_DEBUG "cofuse exit\n");
7239 + fuse_fs_cleanup();
7240 + fuse_dev_cleanup();
7243 +module_init(cofuse_init);
7244 +module_exit(cofuse_exit);
7247 + * Local Variables:
7248 + * indent-tabs-mode: t
7249 + * c-basic-offset: 8
7252 diff -urN a/fs/namespace.c b/fs/namespace.c
7253 --- a/fs/namespace.c
7254 +++ b/fs/namespace.c
7255 @@ -1015,7 +1015,7 @@
7257 if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
7258 flags &= ~MS_MGC_MSK;
7261 /* Basic sanity checks */
7263 if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE))
7264 diff -urN a/include/asm-i386/bug.h b/include/asm-i386/bug.h
7265 --- a/include/asm-i386/bug.h
7266 +++ b/include/asm-i386/bug.h
7270 #if 1 /* Set to zero for a slightly smaller kernel */
7271 +#ifdef CONFIG_COOPERATIVE
7272 +#include <linux/cooperative.h>
7273 +extern void co_terminate(co_termination_reason_t reason);
7274 +#define BUG() do { co_terminate(CO_TERMINATE_BUG); } while(0)
7277 __asm__ __volatile__( "ud2\n" \
7280 : : "i" (__LINE__), "i" (__FILE__))
7283 #define BUG() __asm__ __volatile__("ud2\n")
7285 diff -urN a/include/asm-i386/cooperative.h b/include/asm-i386/cooperative.h
7286 --- a/include/asm-i386/cooperative.h
7287 +++ b/include/asm-i386/cooperative.h
7290 + * linux/include/asm/cooperative.h
7292 + * Copyright (C) 2004 Dan Aloni
7294 + * This file defines the lower level interfaces between the Cooperative Linux
7295 + * kernel and the host OS driver. It's for both external inclusion from the
7296 + * and internal inclusion in the kernel sources.
7299 +#ifndef __LINUX_ASM_COOPERATIVE_H__
7300 +#define __LINUX_ASM_COOPERATIVE_H__
7303 + unsigned short size;
7304 + struct x86_idt_entry *table;
7305 +} __attribute__((packed)) x86_idt_t;
7308 + unsigned short limit;
7309 + struct x86_dt_entry *base;
7310 +} __attribute__((packed)) x86_gdt_t;
7313 + unsigned char border2[0x4];
7316 + #define CO_ARCH_STATE_STACK_CS "0x04"
7319 + #define CO_ARCH_STATE_STACK_DS "0x08"
7322 + #define CO_ARCH_STATE_STACK_ES "0x0C"
7324 + unsigned long cr3;
7325 + #define CO_ARCH_STATE_STACK_CR3 "0x10"
7327 + unsigned long cr4;
7328 + #define CO_ARCH_STATE_STACK_CR4 "0x14"
7330 + unsigned long cr2;
7331 + #define CO_ARCH_STATE_STACK_CR2 "0x18"
7333 + unsigned long cr0;
7334 + #define CO_ARCH_STATE_STACK_CR0 "0x1C"
7337 + #define CO_ARCH_STATE_STACK_GDT "0x20"
7340 + #define CO_ARCH_STATE_STACK_FS "0x26"
7343 + #define CO_ARCH_STATE_STACK_GS "0x2A"
7345 + unsigned short ldt;
7346 + #define CO_ARCH_STATE_STACK_LDT "0x2E"
7349 + #define CO_ARCH_STATE_STACK_IDT "0x30"
7351 + unsigned short tr;
7352 + #define CO_ARCH_STATE_STACK_TR "0x36"
7354 + unsigned long return_eip;
7355 + #define CO_ARCH_STATE_STACK_RETURN_EIP "0x38"
7357 + unsigned long flags;
7358 + #define CO_ARCH_STATE_STACK_FLAGS "0x3C"
7360 + unsigned long esp;
7361 + #define CO_ARCH_STATE_STACK_ESP "0x40"
7364 + #define CO_ARCH_STATE_STACK_SS "0x44"
7366 + unsigned long dr0;
7367 + #define CO_ARCH_STATE_STACK_DR0 "0x48"
7369 + unsigned long dr1;
7370 + #define CO_ARCH_STATE_STACK_DR1 "0x4C"
7372 + unsigned long dr2;
7373 + #define CO_ARCH_STATE_STACK_DR2 "0x50"
7375 + unsigned long dr3;
7376 + #define CO_ARCH_STATE_STACK_DR3 "0x54"
7378 + unsigned long dr6;
7379 + #define CO_ARCH_STATE_STACK_DR6 "0x58"
7381 + unsigned long dr7;
7382 + #define CO_ARCH_STATE_STACK_DR7 "0x5C"
7384 + unsigned long temp_cr3;
7385 + #define CO_ARCH_STATE_STACK_TEMP_CR3 "0x60"
7387 + unsigned long relocate_eip;
7388 + #define CO_ARCH_STATE_STACK_RELOCATE_EIP "0x64"
7390 + unsigned long pad1;
7391 + #define CO_ARCH_STATE_STACK_RELOCATE_EIP_AFTER "0x68"
7394 + #define CO_ARCH_STATE_STACK_VA "0x6C"
7396 + unsigned char fxstate[0x200];
7397 + #define CO_ARCH_STATE_STACK_FXSTATE "0x70"
7398 +} __attribute__((packed)) co_arch_state_stack_t;
7400 +#define CO_MAX_PARAM_SIZE 0x400
7402 +typedef struct co_arch_passage_page_normal_address_space {
7403 + unsigned long pgd[0x400];
7404 + unsigned long pte[2][0x400];
7405 +} co_arch_passage_page_normal_address_space_t;
7407 +typedef struct co_arch_passage_page_pae_address_space {
7408 + unsigned long long main[0x200];
7409 + unsigned long long pgd[2][0x200];
7410 + unsigned long long pte[2][0x200];
7411 +} co_arch_passage_page_pae_address_space_t;
7413 +typedef struct co_arch_passage_page {
7418 + unsigned long self_physical_address;
7419 + unsigned long dr0;
7420 + unsigned long dr1;
7421 + unsigned long dr2;
7422 + unsigned long dr3;
7423 + unsigned long dr6;
7424 + unsigned long dr7;
7425 + unsigned char code[0x230];
7426 + } __attribute__((packed));
7427 + unsigned char pad[0x250]; /* Be careful! see NOTE below */
7428 + } __attribute__((packed));
7430 + /* Machine states */
7433 + * NOTE: *_state fields must be aligned at 16 bytes boundary since
7434 + * the fxsave/fxload instructions expect an aligned arugment.
7437 + co_arch_state_stack_t host_state;
7438 + co_arch_state_stack_t linuxvm_state;
7440 + /* Control parameters */
7441 + unsigned long operation;
7442 + unsigned long params[];
7443 + } __attribute__((packed));
7444 + unsigned char first_page[0x1000];
7447 + /* page tables for passage address spaces */
7448 + co_arch_passage_page_normal_address_space_t guest_normal;
7450 + co_arch_passage_page_normal_address_space_t host_normal;
7451 + co_arch_passage_page_pae_address_space_t host_pae;
7452 + } __attribute__((packed));
7453 +} co_arch_passage_page_t;
7456 + * Address space layout:
7459 +#define CO_VPTR_BASE (0xffc00000)
7460 +#define CO_VPTR_PHYSICAL_TO_PSEUDO_PFN_MAP (CO_VPTR_BASE - 0x1000000)
7461 +#define CO_VPTR_PSEUDO_RAM_PAGE_TABLES (CO_VPTR_BASE - 0x1100000)
7462 +#define CO_VPTR_PASSAGE_PAGE (CO_VPTR_BASE - 0x1101000)
7463 +#define CO_VPTR_IO_AREA_SIZE (0x10000)
7464 +#define CO_VPTR_IO_AREA_START (CO_VPTR_BASE - 0x1200000)
7465 +#define CO_VPTR_SELF_MAP (CO_VPTR_BASE - 0x1400000)
7468 + unsigned long kernel_cs;
7469 + unsigned long kernel_ds;
7470 +} __attribute__((packed)) co_arch_info_t;
7473 diff -urN a/include/asm-i386/cooperative_internal.h b/include/asm-i386/cooperative_internal.h
7474 --- a/include/asm-i386/cooperative_internal.h
7475 +++ b/include/asm-i386/cooperative_internal.h
7478 + * linux/include/asm/cooperative_internal.h
7480 + * Copyright (C) 2004 Dan Aloni
7483 +#ifndef __LINUX_ASM_COOPERATIVE_INTERNAL_H__
7484 +#define __LINUX_ASM_COOPERATIVE_INTERNAL_H__
7486 +#include <linux/config.h>
7487 +#include <asm/ptrace.h>
7489 +#ifdef CONFIG_COOPERATIVE
7491 +extern void co_kernel_breakpoint(struct pt_regs * regs);
7492 +extern int co_kernel_debug(struct pt_regs * regs, long error_code, unsigned int condition);
7494 +fastcall unsigned int do_IRQ(struct pt_regs *regs);
7498 +static inline void co_kernel_breakpoint(struct pt_regs * regs)
7502 +static inline int co_kernel_debug(struct pt_regs * regs, long error_code, unsigned int condition)
7510 diff -urN a/include/asm-i386/dma.h b/include/asm-i386/dma.h
7511 --- a/include/asm-i386/dma.h
7512 +++ b/include/asm-i386/dma.h
7515 * Assumes DMA flip-flop is clear.
7517 +#ifndef CONFIG_COOPERATIVE
7518 static __inline__ int get_dma_residue(unsigned int dmanr)
7520 unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
7523 return (dmanr<=3)? count : (count<<1);
7528 /* These are in kernel/dma.c: */
7529 diff -urN a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h
7530 --- a/include/asm-i386/fixmap.h
7531 +++ b/include/asm-i386/fixmap.h
7533 #include <linux/threads.h>
7534 #include <asm/kmap_types.h>
7536 +#include <asm/cooperative.h>
7539 * Here we define all the compile-time 'special' virtual
7540 diff -urN a/include/asm-i386/io.h b/include/asm-i386/io.h
7541 --- a/include/asm-i386/io.h
7542 +++ b/include/asm-i386/io.h
7543 @@ -104,12 +104,15 @@
7547 -static inline void __iomem * ioremap(unsigned long offset, unsigned long size)
7548 +static inline void * __iomem ioremap (unsigned long offset, unsigned long size)
7550 +#ifdef CONFIG_COOPERATIVE
7551 + panic("ioremap %ld:%ld\n", offset, size);
7553 return __ioremap(offset, size, 0);
7556 -extern void __iomem * ioremap_nocache(unsigned long offset, unsigned long size);
7557 +extern void * __iomem ioremap_nocache (unsigned long offset, unsigned long size);
7558 extern void iounmap(volatile void __iomem *addr);
7563 #endif /* __KERNEL__ */
7565 -#ifdef SLOW_IO_BY_JUMPING
7566 +#if SLOW_IO_BY_JUMPING || CONFIG_COOPERATIVE
7567 #define __SLOW_DOWN_IO "jmp 1f; 1: jmp 1f; 1:"
7569 #define __SLOW_DOWN_IO "outb %%al,$0x80;"
7570 diff -urN a/include/asm-i386/mach-default/irq_vectors.h b/include/asm-i386/mach-default/irq_vectors.h
7571 --- a/include/asm-i386/mach-default/irq_vectors.h
7572 +++ b/include/asm-i386/mach-default/irq_vectors.h
7577 +#ifdef CONFIG_COOPERATIVE
7578 +#define KEYBOARD_IRQ 1
7579 +#define NETWORK_IRQ 2
7583 * 16 8259A IRQ's, 208 potential APIC interrupt sources.
7584 * Right now the APIC is mostly only used for SMP.
7585 diff -urN a/include/asm-i386/mach-default/irq_vectors_limits.h b/include/asm-i386/mach-default/irq_vectors_limits.h
7586 --- a/include/asm-i386/mach-default/irq_vectors_limits.h
7587 +++ b/include/asm-i386/mach-default/irq_vectors_limits.h
7589 #define NR_IRQS FIRST_SYSTEM_VECTOR
7590 #define NR_IRQ_VECTORS NR_IRQS
7592 -#ifdef CONFIG_X86_IO_APIC
7593 +#if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_X86_UP_COPIC)
7595 # if (224 >= 32 * NR_CPUS)
7596 # define NR_IRQ_VECTORS NR_IRQS
7597 diff -urN a/include/asm-i386/mc146818rtc.h b/include/asm-i386/mc146818rtc.h
7598 --- a/include/asm-i386/mc146818rtc.h
7599 +++ b/include/asm-i386/mc146818rtc.h
7601 #ifndef _ASM_MC146818RTC_H
7602 #define _ASM_MC146818RTC_H
7604 +#include <linux/config.h>
7609 #define RTC_ALWAYS_BCD 1 /* RTC operates in binary mode */
7612 +#ifndef CONFIG_COOPERATIVE
7615 * The yet supported machines all access the RTC index register via
7616 * an ISA port access but the way to access the date register differs ...
7618 outb_p((val),RTC_PORT(1)); \
7622 +#define CMOS_READ(addr) (0)
7623 +#define CMOS_WRITE(val, addr) do {} while(0)
7628 #endif /* _ASM_MC146818RTC_H */
7629 diff -urN a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h
7630 --- a/include/asm-i386/mmzone.h
7631 +++ b/include/asm-i386/mmzone.h
7633 #ifndef _ASM_MMZONE_H_
7634 #define _ASM_MMZONE_H_
7636 +#include <linux/config.h>
7637 #include <asm/smp.h>
7638 +#include <asm/cooperative.h>
7640 #ifdef CONFIG_DISCONTIGMEM
7643 (unsigned long)(__page - __zone->zone_mem_map) \
7644 + __zone->zone_start_pfn; \
7646 -#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
7648 +#define pmd_page(pmd) (pfn_to_page(CO_P_TO_PP(pmd_val(pmd)) >> PAGE_SHIFT))
7650 #ifdef CONFIG_X86_NUMAQ /* we have contiguous memory on NUMA-Q */
7651 #define pfn_valid(pfn) ((pfn) < num_physpages)
7652 diff -urN a/include/asm-i386/page.h b/include/asm-i386/page.h
7653 --- a/include/asm-i386/page.h
7654 +++ b/include/asm-i386/page.h
7656 #ifndef __ASSEMBLY__
7658 #include <linux/config.h>
7659 +#include <asm/cooperative.h>
7661 #ifdef CONFIG_X86_USE_3DNOW
7663 @@ -126,6 +127,19 @@
7664 #define __PAGE_OFFSET (0xC0000000UL)
7667 +#ifdef CONFIG_COOPERATIVE
7668 +#define CO_PA(pfn) (((unsigned long *)CO_VPTR_PSEUDO_RAM_PAGE_TABLES)[pfn])
7669 +#define CO_VA_PFN(pa) (((unsigned long *)CO_VPTR_PHYSICAL_TO_PSEUDO_PFN_MAP)[((pa) >> PAGE_SHIFT)])
7670 +#define CO_PFN_PP_TO_P(pfn) (CO_PA(pfn) >> PAGE_SHIFT)
7671 +#define CO_PFN_P_TO_PP(pfn) (CO_VA_PFN(pfn << PAGE_SHIFT))
7672 +#define CO_PP_TO_P(pa) ((CO_PFN_PP_TO_P(pa >> PAGE_SHIFT) << PAGE_SHIFT) | (pa & ~PAGE_MASK))
7673 +#define CO_P_TO_PP(pa) ((CO_PFN_P_TO_PP(pa >> PAGE_SHIFT) << PAGE_SHIFT) | (pa & ~PAGE_MASK))
7675 +#define CO_PFN_P_TO_PP(pfn) pfn
7676 +#define CO_PFN_PP_TO_P(pfn) pfn
7677 +#define CO_PP_TO_P(pa) pa
7678 +#define CO_P_TO_PP(pa) pa
7681 #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
7682 #define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE)
7683 diff -urN a/include/asm-i386/param.h b/include/asm-i386/param.h
7684 --- a/include/asm-i386/param.h
7685 +++ b/include/asm-i386/param.h
7687 #define _ASMi386_PARAM_H
7690 +# include <linux/config.h>
7691 +# ifndef CONFIG_COOPERATIVE
7692 # define HZ 1000 /* Internal kernel timer frequency */
7694 # define USER_HZ 100 /* .. some user interfaces are in "ticks" */
7696 # define CLOCKS_PER_SEC (USER_HZ) /* like times() */
7699 diff -urN a/include/asm-i386/pgalloc.h b/include/asm-i386/pgalloc.h
7700 --- a/include/asm-i386/pgalloc.h
7701 +++ b/include/asm-i386/pgalloc.h
7703 #include <asm/fixmap.h>
7704 #include <linux/threads.h>
7705 #include <linux/mm.h> /* for struct page */
7706 +#include <asm/cooperative.h>
7708 #define pmd_populate_kernel(mm, pmd, pte) \
7709 - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
7710 + set_pmd(pmd, __pmd(_PAGE_TABLE + CO_PP_TO_P(__pa(pte))))
7712 static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte)
7714 set_pmd(pmd, __pmd(_PAGE_TABLE +
7715 - ((unsigned long long)page_to_pfn(pte) <<
7716 - (unsigned long long) PAGE_SHIFT)));
7717 + ((CO_PFN_PP_TO_P((unsigned long long)page_to_pfn(pte))) <<
7718 + (unsigned long long) PAGE_SHIFT)));
7721 * Allocate and free page tables.
7722 diff -urN a/include/asm-i386/pgtable-2level.h b/include/asm-i386/pgtable-2level.h
7723 --- a/include/asm-i386/pgtable-2level.h
7724 +++ b/include/asm-i386/pgtable-2level.h
7726 #define pgd_ERROR(e) \
7727 printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
7729 +#include <linux/config.h>
7730 +#include <asm/cooperative.h>
7733 * The "pgd_xxx()" functions here are trivial for a folded two-level
7734 * setup: the pgd is never bad, and a pmd always exists (as it's folded
7736 #define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval)
7738 #define pgd_page(pgd) \
7739 -((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
7740 + ((unsigned long) __va(CO_P_TO_PP(pgd_val(pgd)) & PAGE_MASK))
7742 static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
7744 return (pmd_t *) dir;
7747 #define ptep_get_and_clear(xp) __pte(xchg(&(xp)->pte_low, 0))
7748 #define pte_same(a, b) ((a).pte_low == (b).pte_low)
7750 #define pte_page(x) pfn_to_page(pte_pfn(x))
7751 +#define pte_pfn(x) CO_PFN_P_TO_PP((unsigned long)(((x).pte_low >> PAGE_SHIFT)))
7752 +#define pfn_pte(pfn, prot) __pte((CO_PFN_PP_TO_P(pfn) << PAGE_SHIFT) | pgprot_val(prot))
7753 +#define pfn_pmd(pfn, prot) __pmd((CO_PFN_PP_TO_P(pfn) << PAGE_SHIFT) | pgprot_val(prot))
7754 #define pte_none(x) (!(x).pte_low)
7755 -#define pte_pfn(x) ((unsigned long)(((x).pte_low >> PAGE_SHIFT)))
7756 -#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
7757 -#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
7760 * All present user pages are user-executable:
7761 diff -urN a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
7762 --- a/include/asm-i386/pgtable.h
7763 +++ b/include/asm-i386/pgtable.h
7765 #include <linux/list.h>
7766 #include <linux/spinlock.h>
7768 +#include <asm/cooperative.h>
7771 * ZERO_PAGE is a global shared page that is always zero: used
7772 * for zero-mapped memory areas etc..
7773 @@ -294,10 +296,10 @@
7774 #define page_pte(page) page_pte_prot(page, __pgprot(0))
7776 #define pmd_page_kernel(pmd) \
7777 -((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
7778 +((unsigned long) __va(CO_P_TO_PP(pmd_val(pmd)) & PAGE_MASK))
7780 #ifndef CONFIG_DISCONTIGMEM
7781 -#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
7782 +#define pmd_page(pmd) (pfn_to_page(CO_PFN_P_TO_PP(pmd_val(pmd) >> PAGE_SHIFT)))
7783 #endif /* !CONFIG_DISCONTIGMEM */
7785 #define pmd_large(pmd) \
7786 diff -urN a/include/asm-i386/processor.h b/include/asm-i386/processor.h
7787 --- a/include/asm-i386/processor.h
7788 +++ b/include/asm-i386/processor.h
7792 #define load_cr3(pgdir) \
7793 - asm volatile("movl %0,%%cr3": :"r" (__pa(pgdir)))
7795 + asm volatile("movl %0,%%cr3": :"r" (CO_PP_TO_P(__pa(pgdir))))
7798 * Intel CPU features in CR4
7799 diff -urN a/include/asm-i386/timer.h b/include/asm-i386/timer.h
7800 --- a/include/asm-i386/timer.h
7801 +++ b/include/asm-i386/timer.h
7805 void (*mark_offset)(void);
7806 - unsigned long (*get_offset)(void);
7807 + long (*get_offset)(void);
7808 unsigned long long (*monotonic_clock)(void);
7809 void (*delay)(unsigned long);
7812 #ifdef CONFIG_X86_CYCLONE_TIMER
7813 extern struct init_timer_opts timer_cyclone_init;
7815 +#ifdef CONFIG_COOPERATIVE
7816 +extern struct init_timer_opts timer_cooperative_init;
7819 extern unsigned long calibrate_tsc(void);
7820 extern void init_cpu_khz(void);
7821 diff -urN a/include/linux/console.h b/include/linux/console.h
7822 --- a/include/linux/console.h
7823 +++ b/include/linux/console.h
7825 extern const struct consw dummy_con; /* dummy console buffer */
7826 extern const struct consw fb_con; /* frame buffer based console */
7827 extern const struct consw vga_con; /* VGA text console */
7828 +extern const struct consw colinux_con; /* coLinux Mode text console */
7829 extern const struct consw newport_con; /* SGI Newport console */
7830 extern const struct consw prom_con; /* SPARC PROM console */
7832 diff -urN a/include/linux/cooperative.h b/include/linux/cooperative.h
7833 --- a/include/linux/cooperative.h
7834 +++ b/include/linux/cooperative.h
7837 + * linux/include/linux/cooperative.h
7839 + * Copyright (C) 2004 Dan Aloni
7841 + * This file defines the interfaces between the Cooperative Linux kernel
7842 + * and the host OS driver. It's for both external inclusion from the
7843 + * and internal inclusion in the kernel sources.
7846 +#ifndef __LINUX_COOPERATIVE_H__
7847 +#define __LINUX_COOPERATIVE_H__
7851 +#define CO_COLINUX_KERNEL
7856 +#include <asm/cooperative.h>
7858 +#define CO_LINUX_API_VERSION 8
7862 +#define CO_BOOTPARAM_STRING_LENGTH 0x100
7865 + CO_OPERATION_EMPTY=0,
7866 + CO_OPERATION_START,
7867 + CO_OPERATION_IDLE,
7868 + CO_OPERATION_TERMINATE,
7869 + CO_OPERATION_MESSAGE_TO_MONITOR,
7870 + CO_OPERATION_MESSAGE_FROM_MONITOR,
7871 + CO_OPERATION_FORWARD_INTERRUPT,
7872 + CO_OPERATION_DEVICE,
7873 + CO_OPERATION_GET_TIME,
7874 + CO_OPERATION_DEBUG_LINE,
7875 + CO_OPERATION_GET_HIGH_PREC_TIME,
7876 + CO_OPERATION_TRACE_POINT,
7877 + CO_OPERATION_FREE_PAGES,
7878 + CO_OPERATION_ALLOC_PAGES,
7881 +#define CO_MODULE_MAX_CONET 16
7882 +#define CO_MODULE_MAX_COBD 32
7883 +#define CO_MODULE_MAX_COFS 32
7884 +#define CO_MODULE_MAX_SERIAL 64
7888 + CO_MODULE_MONITOR,
7891 + CO_MODULE_KERNEL_SWITCH,
7892 + CO_MODULE_USER_SWITCH,
7893 + CO_MODULE_CONSOLE,
7897 + CO_MODULE_CONET_END=CO_MODULE_CONET0+CO_MODULE_MAX_CONET-1,
7900 + CO_MODULE_COBD_END=CO_MODULE_COBD0+CO_MODULE_MAX_COBD-1,
7903 + CO_MODULE_COFS_END=CO_MODULE_COFS0+CO_MODULE_MAX_COFS-1,
7905 + CO_MODULE_SERIAL0,
7906 + CO_MODULE_SERIAL_END=CO_MODULE_SERIAL0+CO_MODULE_MAX_SERIAL-1,
7910 + CO_PRIORITY_DISCARDABLE=0,
7911 + CO_PRIORITY_IMPORTANT,
7915 + CO_MESSAGE_TYPE_STRING=0,
7916 + CO_MESSAGE_TYPE_OTHER=1,
7917 +} co_message_type_t;
7922 + co_priority_t priority;
7923 + co_message_type_t type;
7924 + unsigned long size;
7926 +} __attribute__((packed)) co_message_t;
7929 + CO_DEVICE_BLOCK=0,
7930 + CO_DEVICE_CONSOLE,
7931 + CO_DEVICE_KEYBOARD,
7932 + CO_DEVICE_NETWORK,
7936 + CO_DEVICE_FILESYSTEM,
7942 + unsigned char code;
7947 + CO_LINUX_MESSAGE_POWER_ALT_CTRL_DEL=0,
7948 +} co_linux_message_power_type_t;
7951 + co_linux_message_power_type_t type;
7952 +} __attribute__((packed)) co_linux_message_power_t;
7955 + unsigned long tick_count;
7956 +} __attribute__((packed)) co_linux_message_idle_t;
7959 + co_device_t device;
7960 + unsigned long unit;
7961 + unsigned long size;
7963 +} __attribute__((packed)) co_linux_message_t;
7966 + CO_TERMINATE_END=0,
7967 + CO_TERMINATE_REBOOT,
7968 + CO_TERMINATE_POWEROFF,
7969 + CO_TERMINATE_PANIC,
7970 + CO_TERMINATE_HALT,
7971 + CO_TERMINATE_FORCED_OFF,
7972 + CO_TERMINATE_FORCED_END,
7973 + CO_TERMINATE_INVALID_OPERATION,
7974 + CO_TERMINATE_STACK_OVERFLOW,
7976 +} co_termination_reason_t;
7978 +typedef void (*co_switcher_t)(co_arch_passage_page_t *page,
7979 + unsigned char *from,
7980 + unsigned char *to);
7982 +#define co_passage_page_func_low(_from_,_to_) \
7983 + (((co_switcher_t)(co_passage_page->code)) \
7984 + (co_passage_page, \
7985 + (char *)&_from_.border2, \
7986 + (char *)&_to_.border2))
7988 +#define co_passage_page_func(_from_,_to_) \
7989 + co_passage_page_func_low(co_passage_page->_from_, co_passage_page->_to_)
7992 +# ifdef CO_COLINUX_KERNEL
7993 +# define co_passage_page ((co_arch_passage_page_t *)(CO_VPTR_PASSAGE_PAGE))
7994 +# define co_current (co_passage_page->linuxvm_state)
7995 +# define co_other (co_passage_page->host_state)
7997 +# define co_passage_page (cmon->passage_page)
7998 +# define co_other (co_passage_page->linuxvm_state)
7999 +# define co_current (co_passage_page->host_state)
8002 +# define co_switch() co_passage_page_func_low(co_current, co_other)
8006 + * Defines operations on various virtual devices.
8010 + CO_OPERATION_CONSOLE_STARTUP=0,
8011 + CO_OPERATION_CONSOLE_INIT=1,
8012 + CO_OPERATION_CONSOLE_DEINIT,
8013 + CO_OPERATION_CONSOLE_CLEAR,
8014 + CO_OPERATION_CONSOLE_PUTC,
8015 + CO_OPERATION_CONSOLE_PUTCS,
8016 + CO_OPERATION_CONSOLE_CURSOR_DRAW,
8017 + CO_OPERATION_CONSOLE_CURSOR_ERASE,
8018 + CO_OPERATION_CONSOLE_CURSOR_MOVE,
8019 + CO_OPERATION_CONSOLE_SCROLL_UP,
8020 + CO_OPERATION_CONSOLE_SCROLL_DOWN,
8021 + CO_OPERATION_CONSOLE_BMOVE,
8022 + CO_OPERATION_CONSOLE_SWITCH,
8023 + CO_OPERATION_CONSOLE_BLANK,
8024 + CO_OPERATION_CONSOLE_FONT_OP,
8025 + CO_OPERATION_CONSOLE_SET_PALETTE,
8026 + CO_OPERATION_CONSOLE_SCROLLDELTA,
8027 + CO_OPERATION_CONSOLE_SET_ORIGIN,
8028 + CO_OPERATION_CONSOLE_SAVE_SCREEN,
8029 + CO_OPERATION_CONSOLE_INVERT_REGION,
8030 +} co_operation_console_t;
8033 +typedef char co_console_code;
8034 +typedef unsigned short co_console_character;
8035 +typedef unsigned short co_console_unit;
8038 + co_console_unit x;
8039 + co_console_unit y;
8040 + co_console_unit height;
8041 +} __attribute__((packed)) co_cursor_pos_t;
8044 + co_operation_console_t type;
8047 + co_console_unit top;
8048 + co_console_unit bottom;
8049 + co_console_unit lines;
8052 + co_console_unit y;
8053 + co_console_unit x;
8054 + co_console_unit count;
8055 + co_console_character data[];
8058 + co_console_unit x;
8059 + co_console_unit y;
8060 + co_console_character charattr;
8063 + co_console_unit top;
8064 + co_console_unit left;
8065 + co_console_unit bottom;
8066 + co_console_unit right;
8067 + co_console_character charattr;
8070 + co_console_unit y;
8071 + co_console_unit x;
8072 + co_console_unit count;
8075 + co_console_unit row;
8076 + co_console_unit column;
8077 + co_console_unit top;
8078 + co_console_unit left;
8079 + co_console_unit bottom;
8080 + co_console_unit right;
8082 + co_cursor_pos_t cursor;
8084 +} __attribute__((packed)) co_console_message_t;
8087 + unsigned long index;
8088 + unsigned long flags;
8089 + unsigned long func;
8090 + unsigned long pid;
8091 +} __attribute__((packed)) co_trace_point_info_t;
8099 + CO_BLOCK_GET_ALIAS,
8100 +} co_block_request_type_t;
8103 + CO_NETWORK_GET_MAC=0,
8104 +} co_network_request_type_t;
8107 +/* If we are compiling kernel code (Linux or Host Driver) */
8108 +# ifdef CO_COLINUX_KERNEL
8109 +/* Inside Linux, vm_ptr_t considered a valid pointer in its virtual address space */
8110 +typedef void *vm_ptr_t;
8112 +/* But inside the host, the type is considered not to be a pointer in its own address space */
8113 +typedef unsigned long vm_ptr_t;
8117 + co_block_request_type_t type;
8121 + unsigned long long offset;
8122 + unsigned long long size;
8123 + unsigned long long disk_size;
8130 +} __attribute__((packed)) co_block_request_t;
8133 + co_network_request_type_t type;
8134 + unsigned long unit;
8135 + char mac_address[6];
8138 +} __attribute__((packed)) co_network_request_t;
8143 + unsigned long api_version;
8144 + unsigned long compiler_major;
8145 + unsigned long compiler_minor;
8146 +} __attribute__((packed)) co_info_t;
8148 +#ifndef COLINUX_TRACE
8149 +#define CO_TRACE_STOP
8150 +#define CO_TRACE_CONTINUE
8155 +#include "cooperative_fs.h"
8158 diff -urN a/include/linux/cooperative_fs.h b/include/linux/cooperative_fs.h
8159 --- a/include/linux/cooperative_fs.h
8160 +++ b/include/linux/cooperative_fs.h
8163 + FUSE: Filesystem in Userspace
8164 + Copyright (C) 2001-2004 Miklos Szeredi <miklos@szeredi.hu>
8166 + This program can be distributed under the terms of the GNU GPL.
8167 + See the file COPYING.
8170 +/* This file defines the kernel interface of FUSE */
8174 +/** Version number of this interface */
8175 +#define FUSE_KERNEL_VERSION 2
8177 +/** Minor version number of this interface */
8178 +#define FUSE_KERNEL_MINOR_VERSION 2
8180 +/** The inode number of the root inode */
8181 +#define FUSE_ROOT_INO 1
8183 +/** Data passed to mount */
8184 +struct fuse_mount_data {
8185 + /** The file type of the root inode */
8186 + unsigned int rootmode;
8188 + /** The user ID of the user initiating this mount */
8191 + /** FUSE specific mount flags */
8192 + unsigned int flags;
8195 +/* FUSE mount flags: */
8197 +/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem
8198 +module will check permissions based on the file mode. Otherwise no
8199 +permission checking is done in the kernel */
8200 +#define FUSE_DEFAULT_PERMISSIONS (1 << 0)
8202 +/** If the FUSE_ALLOW_OTHER flag is given, then not only the user
8203 + doing the mount will be allowed to access the filesystem */
8204 +#define FUSE_ALLOW_OTHER (1 << 1)
8206 +/** If the FUSE_KERNEL_CACHE flag is given, then files will be cached
8207 + until the INVALIDATE operation is invoked */
8208 +#define FUSE_KERNEL_CACHE (1 << 2)
8210 +/** Allow FUSE to combine reads into 64k chunks. This is useful if
8211 + the filesystem is better at handling large chunks. NOTE: in
8212 + current implementation the raw throughput is worse for large reads
8213 + than for small. */
8214 +#define FUSE_LARGE_READ (1 << 3)
8217 + unsigned long long size;
8218 + unsigned int mode;
8219 + unsigned int nlink;
8222 + unsigned int rdev;
8223 + unsigned long _dummy;
8224 + unsigned long blocks;
8225 + unsigned long atime;
8226 + unsigned long mtime;
8227 + unsigned long ctime;
8230 +struct fuse_kstatfs {
8239 +#define FATTR_MODE (1 << 0)
8240 +#define FATTR_UID (1 << 1)
8241 +#define FATTR_GID (1 << 2)
8242 +#define FATTR_SIZE (1 << 3)
8243 +#define FATTR_UTIME (1 << 4)
8247 + FUSE_FORGET = 2, /* no reply */
8250 + FUSE_READLINK = 5,
8263 + FUSE_RELEASE = 18, /* no reply */
8264 + FUSE_INVALIDATE = 19, /* user initiated */
8266 + FUSE_RELEASE2 = 21, /* reply needed after all */
8268 + /* Cooperative Linux does things a little differently: */
8269 + FUSE_DIR_OPEN = 22,
8270 + FUSE_DIR_READ = 23,
8271 + FUSE_DIR_RELEASE = 24,
8276 +/* Conservative buffer size for the client */
8277 +#define FUSE_MAX_IN 8192
8279 +#define FUSE_NAME_MAX 1024
8280 +#define FUSE_SYMLINK_MAX 4096
8282 +struct fuse_lookup_out {
8283 + struct fuse_attr attr;
8284 + unsigned long ino;
8287 +struct fuse_forget_in {
8291 +struct fuse_getattr_out {
8292 + struct fuse_attr attr;
8295 +struct fuse_getdir_out {
8297 + void *file; /* Used by kernel only */
8300 +/* FIXME: 2.6 needs 32 bit rdev */
8301 +struct fuse_mknod_in {
8302 + unsigned short mode;
8303 + unsigned short rdev;
8306 +struct fuse_mknod_out {
8307 + struct fuse_attr attr;
8308 + unsigned long ino;
8311 +struct fuse_mkdir_in {
8312 + unsigned short mode;
8315 +struct fuse_rename_in {
8316 + unsigned long newdir;
8319 +struct fuse_link_in {
8320 + unsigned long newdir;
8323 +struct fuse_setattr_in {
8324 + struct fuse_attr attr;
8325 + unsigned int valid;
8328 +struct fuse_setattr_out {
8329 + struct fuse_attr attr;
8332 +struct fuse_open_in {
8333 + unsigned int flags;
8336 +struct fuse_read_in {
8337 + unsigned long long offset;
8338 + unsigned int size;
8341 +struct fuse_write_in {
8342 + unsigned long long offset;
8343 + unsigned int size;
8346 +struct fuse_statfs_out {
8347 + struct fuse_kstatfs st;
8350 +struct fuse_fsync_in {
8354 +struct fuse_in_header {
8356 + enum fuse_opcode opcode;
8357 + unsigned long ino;
8362 +struct fuse_out_header {
8367 +struct fuse_user_header {
8368 + int unique; /* zero */
8369 + enum fuse_opcode opcode;
8370 + unsigned long ino;
8373 +struct fuse_dirent {
8374 + unsigned long ino;
8375 + unsigned short namelen;
8376 + unsigned char type;
8380 +#define FUSE_S_IFMT 00170000
8381 +#define FUSE_S_IFSOCK 0140000
8382 +#define FUSE_S_IFLNK 0120000
8383 +#define FUSE_S_IFREG 0100000
8384 +#define FUSE_S_IFBLK 0060000
8385 +#define FUSE_S_IFDIR 0040000
8386 +#define FUSE_S_IFCHR 0020000
8387 +#define FUSE_S_IFIFO 0010000
8388 +#define FUSE_S_ISUID 0004000
8389 +#define FUSE_S_ISGID 0002000
8390 +#define FUSE_S_ISVTX 0001000
8392 +#define FUSE_S_IRWXU 00700
8393 +#define FUSE_S_IRUSR 00400
8394 +#define FUSE_S_IWUSR 00200
8395 +#define FUSE_S_IXUSR 00100
8397 +#define FUSE_S_IRWXG 00070
8398 +#define FUSE_S_IRGRP 00040
8399 +#define FUSE_S_IWGRP 00020
8400 +#define FUSE_S_IXGRP 00010
8402 +#define FUSE_S_IRWXO 00007
8403 +#define FUSE_S_IROTH 00004
8404 +#define FUSE_S_IWOTH 00002
8405 +#define FUSE_S_IXOTH 00001
8407 +#define FUSE_DT_UNKNOWN 0
8408 +#define FUSE_DT_FIFO 1
8409 +#define FUSE_DT_CHR 2
8410 +#define FUSE_DT_DIR 4
8411 +#define FUSE_DT_BLK 6
8412 +#define FUSE_DT_REG 8
8413 +#define FUSE_DT_LNK 10
8414 +#define FUSE_DT_SOCK 12
8415 +#define FUSE_DT_WHT 14
8417 +#define FUSE_NAME_OFFSET ((unsigned int) ((struct fuse_dirent *) 0)->name)
8418 +#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(long) - 1) & ~(sizeof(long) - 1))
8419 +#define FUSE_DIRENT_SIZE(d) \
8420 + FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
8424 + * Local Variables:
8425 + * indent-tabs-mode: t
8426 + * c-basic-offset: 8
8429 diff -urN a/include/linux/cooperative_internal.h b/include/linux/cooperative_internal.h
8430 --- a/include/linux/cooperative_internal.h
8431 +++ b/include/linux/cooperative_internal.h
8434 + * linux/include/linux/cooperative.h
8436 + * Copyright (C) 2004 Dan Aloni
8438 + * This header gathers the functions and variables in Cooperative Mode
8439 + * when CONFIG_COOPERATIVE is defined.
8441 +#ifndef __LINUX_COOPERATIVE_LINUX_H__
8442 +#define __LINUX_COOPERATIVE_LINUX_H__
8444 +#include <linux/config.h>
8445 +#include <linux/cooperative.h>
8446 +#include <linux/list.h>
8448 +#ifdef CONFIG_COOPERATIVE
8451 + struct list_head node;
8453 +} co_message_node_t;
8455 +extern void co_debug(const char *fmt, ...);
8456 +extern void co_printk(const char *line);
8458 +extern void co_callback(unsigned long flags);
8459 +extern void co_switch_wrapper(void);
8460 +extern void co_idle_processor(void);
8461 +extern void co_terminate(co_termination_reason_t reason);
8462 +extern void co_free_pages(unsigned long vaddr, int order);
8463 +extern int co_alloc_pages(unsigned long vaddr, int order);
8464 +extern void co_start_kernel(void);
8465 +extern void co_arch_start_kernel(void);
8466 +extern void co_handle_jiffies(long count);
8468 +extern void co_send_message(co_module_t from,
8470 + co_priority_t priority,
8471 + co_message_type_t type,
8472 + unsigned long size,
8473 + const char *data);
8474 +extern unsigned long co_get_host_time(void);
8475 +extern co_message_t *co_send_message_save(unsigned long *flags);
8476 +extern co_message_t *co_get_message_save(unsigned long *flags);
8477 +extern void co_send_message_restore(unsigned long flags);
8479 +extern void cocd_interrupt(void);
8481 +extern void co_handle_incoming_messages(void);
8482 +extern void co_handle_incoming_message(co_message_node_t *message);
8483 +extern void co_queue_incoming_message(co_message_node_t *message);
8484 +extern int co_get_message(co_message_node_t **message, co_device_t device);
8485 +extern void co_free_message(co_message_node_t *message);
8487 +extern int co_passage_page_held(void);
8488 +extern void co_passage_page_acquire(unsigned long *flags);
8489 +extern void co_passage_page_release(unsigned long flags);
8491 +#define co_passage_page_assert_valid() do { \
8492 + if (co_passage_page_held()) \
8496 +extern char co_boot_parameters[CO_BOOTPARAM_STRING_LENGTH];
8497 +extern unsigned long co_core_end;
8498 +extern unsigned long co_memory_size;
8499 +extern void *co_initrd;
8500 +extern unsigned long co_initrd_size;
8502 +#define cooperative_mode_enabled() 1
8506 +#define co_printk(line) do {} while (0)
8507 +#define co_terminate(reason) do {} while (0)
8508 +#define cooperative_mode_enabled() 0
8513 diff -urN a/include/linux/major.h b/include/linux/major.h
8514 --- a/include/linux/major.h
8515 +++ b/include/linux/major.h
8517 #define VIOCD_MAJOR 113
8519 #define ATARAID_MAJOR 114
8520 +#define COLINUX_MAJOR 117
8522 #define SCSI_DISK8_MAJOR 128
8523 #define SCSI_DISK9_MAJOR 129
8524 diff -urN a/init/do_mounts.c b/init/do_mounts.c
8525 --- a/init/do_mounts.c
8526 +++ b/init/do_mounts.c
8528 for (p = s; *p; p++)
8532 res = try_name(s, 0);
8535 diff -urN a/init/main.c b/init/main.c
8539 panic(panic_later, panic_param);
8543 #ifdef CONFIG_BLK_DEV_INITRD
8544 if (initrd_start && !initrd_below_start_ok &&
8545 initrd_start < min_low_pfn << PAGE_SHIFT) {
8546 diff -urN a/kernel/Makefile b/kernel/Makefile
8547 --- a/kernel/Makefile
8548 +++ b/kernel/Makefile
8550 obj-$(CONFIG_KPROBES) += kprobes.o
8551 obj-$(CONFIG_SYSFS) += ksysfs.o
8552 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
8553 +obj-$(CONFIG_COOPERATIVE) += cooperative.o
8555 ifneq ($(CONFIG_IA64),y)
8556 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
8557 diff -urN a/kernel/cooperative.c b/kernel/cooperative.c
8558 --- a/kernel/cooperative.c
8559 +++ b/kernel/cooperative.c
8562 + * linux/kernel/cooperative.c
8564 + * Cooperative mode (coLinux) support routines.
8566 + * Dan Aloni <da-x@colinux.org>, 2003-2004 (C).
8570 +#include <linux/kernel.h>
8571 +#include <linux/module.h>
8572 +#include <linux/string.h>
8573 +#include <linux/interrupt.h>
8574 +#include <linux/mm.h>
8575 +#include <linux/slab.h>
8576 +#include <linux/cooperative_internal.h>
8580 +void start_kernel(void);
8581 +extern char _kernel_start, _end;
8584 +unsigned long co_core_end = 0;
8585 +unsigned long co_memory_size = 0;
8586 +void *co_initrd = NULL;
8587 +unsigned long co_initrd_size = 0;
8588 +char co_boot_parameters[CO_BOOTPARAM_STRING_LENGTH];
8592 + struct list_head list;
8594 +} co_message_queue_t;
8596 +int co_messages_active = 0;
8597 +co_message_queue_t co_outgoing_messages;
8598 +co_message_queue_t co_incoming_messages;
8599 +co_message_queue_t *co_incoming_queued_messages;
8601 +void co_start_kernel(void)
8603 + co_core_end = co_passage_page->params[0];
8604 + co_memory_size = co_passage_page->params[1];
8605 + co_initrd = (void *)co_passage_page->params[2];
8606 + co_initrd_size = co_passage_page->params[3];
8608 + memcpy(co_boot_parameters, &co_passage_page->params[10],
8609 + sizeof(co_boot_parameters));
8611 + co_arch_start_kernel();
8613 + /* should never be reached */
8614 + co_terminate(CO_TERMINATE_END);
8617 +co_message_t *co_send_message_save(unsigned long *flags)
8619 + co_passage_page_assert_valid();
8620 + co_passage_page_acquire(flags);
8621 + co_passage_page->operation = CO_OPERATION_MESSAGE_TO_MONITOR;
8622 + return ((co_message_t *)CO_VPTR_IO_AREA_START);
8625 +void co_send_message_restore(unsigned long flags)
8627 + co_switch_wrapper();
8628 + co_passage_page_release(flags);
8631 +void co_send_message_s(co_message_t *message, const char *data)
8633 + if ((sizeof(co_message_t) + message->size) > CO_VPTR_IO_AREA_SIZE)
8636 + if (co_passage_page_held())
8639 + unsigned long flags;
8640 + co_message_t *buffer = ((co_message_t *)CO_VPTR_IO_AREA_START);
8642 + co_passage_page_acquire(&flags);
8643 + co_passage_page->operation = CO_OPERATION_MESSAGE_TO_MONITOR;
8644 + *buffer = *message;
8645 + memcpy(buffer->data, data, message->size);
8646 + co_switch_wrapper();
8647 + co_passage_page_release(flags);
8650 +void co_send_message(co_module_t from,
8652 + co_priority_t priority,
8653 + co_message_type_t type,
8654 + unsigned long size,
8657 + co_message_t params;
8659 + params.from = from;
8661 + params.priority = priority;
8662 + params.type = type;
8663 + params.size = size;
8665 + co_send_message_s(¶ms, data);
8668 +static void co_message_add_to_incoming(co_message_t *message, unsigned long size)
8670 + co_message_node_t *message_copy;
8672 + message_copy = kmalloc(size + sizeof(co_message_node_t) - sizeof(co_message_t),
8674 + if (!message_copy)
8677 + memcpy(&message_copy->msg, message, size);
8678 + list_add_tail(&message_copy->node, &co_incoming_messages.list);
8681 +void co_callback(unsigned long flags)
8683 + if (co_passage_page->operation != CO_OPERATION_MESSAGE_FROM_MONITOR) {
8684 + co_passage_page_release(flags);
8688 + long io_size = co_passage_page->params[0];
8689 + unsigned long new_jiffies = co_passage_page->params[1];
8691 + if (co_messages_active && io_size > 0) {
8692 + unsigned char *io_buffer = (char *)CO_VPTR_IO_AREA_START;
8693 + unsigned char *io_buffer_end = io_buffer + io_size;
8694 + if (!(io_size > CO_VPTR_IO_AREA_SIZE)) {
8695 + while (io_buffer < io_buffer_end) {
8696 + co_message_t *message = (co_message_t *)io_buffer;
8697 + unsigned long size = message->size + sizeof(*message);
8699 + co_message_add_to_incoming(message, size);
8700 + io_buffer += size;
8705 + co_passage_page_release(flags);
8707 + co_handle_jiffies(new_jiffies);
8708 + co_handle_incoming_messages();
8711 +void co_handle_incoming_messages(void)
8713 + if (!co_messages_active)
8716 + if (list_empty(&co_incoming_messages.list))
8720 + unsigned long flags;
8721 + co_message_node_t *message = NULL;
8724 + * Pop a message from the incoming queue.
8726 + local_irq_save(flags);
8727 + if (!list_empty(&co_incoming_messages.list)) {
8728 + message = list_entry(co_incoming_messages.list.next,
8729 + co_message_node_t, node);
8730 + list_del(&message->node);
8732 + local_irq_restore(flags);
8738 + * Let the interrupt routine of the arch dependant code
8739 + * handle the message, and be responsible to free it.
8741 + co_handle_incoming_message(message);
8745 +void co_idle_processor(void)
8747 + unsigned long flags;
8749 + co_passage_page_assert_valid();
8751 + co_passage_page_acquire(&flags);
8752 + co_passage_page->operation = CO_OPERATION_IDLE;
8753 + co_switch_wrapper();
8754 + co_callback(flags);
8757 +void co_printk(const char *line)
8759 + co_send_message(CO_MODULE_LINUX,
8761 + CO_PRIORITY_DISCARDABLE,
8762 + CO_MESSAGE_TYPE_STRING,
8767 +void co_debug_line(char *line)
8771 +void co_terminate(co_termination_reason_t reason)
8773 + unsigned long flags;
8775 + co_passage_page_acquire(&flags);
8776 + co_passage_page->operation = CO_OPERATION_TERMINATE;
8777 + co_passage_page->params[0] = reason;
8778 + co_switch_wrapper();
8779 + /* This doesn't really return. This code shouldn't be running. */
8780 + co_passage_page_release(flags);
8783 +unsigned long co_get_host_time(void)
8785 + unsigned long flags;
8786 + unsigned long time;
8788 + co_passage_page_assert_valid();
8790 + co_passage_page_acquire(&flags);
8791 + co_passage_page->operation = CO_OPERATION_GET_TIME;
8792 + co_switch_wrapper();
8793 + time = co_passage_page->params[0];
8794 + co_passage_page_release(flags);
8799 +void co_queue_incoming_message(co_message_node_t *node_message)
8801 + if (!co_messages_active)
8804 + co_linux_message_t *message = (co_linux_message_t *)&node_message->msg.data;
8805 + if (message->device < 0 || (message->device >= CO_DEVICES_TOTAL))
8808 + co_message_queue_t *queue;
8809 + queue = &co_incoming_queued_messages[message->device];
8811 + /* Add to the queue */
8812 + unsigned long flags;
8813 + local_irq_save(flags);
8814 + list_add(&node_message->node, &queue->list);
8815 + queue->num_messages++;
8816 + local_irq_restore(flags);
8819 +int co_get_message(co_message_node_t **message, co_device_t device)
8821 + co_message_queue_t *queue;
8822 + co_message_node_t *node;
8823 + unsigned long flags;
8825 + if (!co_messages_active)
8828 + local_irq_save(flags);
8829 + queue = &co_incoming_queued_messages[device];
8830 + if (list_empty(&queue->list)) {
8831 + local_irq_restore(flags);
8835 + node = list_entry(queue->list.prev, co_message_node_t, node);
8836 + list_del(&node->node);
8837 + queue->num_messages--;
8838 + local_irq_restore(flags);
8844 +void co_free_message(co_message_node_t *message)
8849 +co_info_t co_info = {
8850 + .api_version = CO_LINUX_API_VERSION,
8851 + .compiler_major = __GNUC__,
8852 + .compiler_minor = __GNUC_MINOR__,
8855 +static int __init initcall_message_queues(void)
8859 + INIT_LIST_HEAD(&co_outgoing_messages.list);
8860 + INIT_LIST_HEAD(&co_incoming_messages.list);
8862 + co_incoming_queued_messages = kmalloc(sizeof(co_message_queue_t) * CO_DEVICES_TOTAL,
8864 + if (!co_incoming_queued_messages)
8865 + panic("unable to allocate message queues\n");
8867 + for (queue_index=0; queue_index < CO_DEVICES_TOTAL; queue_index++) {
8868 + co_message_queue_t *queue = &co_incoming_queued_messages[queue_index];
8869 + queue->num_messages = 0;
8870 + INIT_LIST_HEAD(&queue->list);
8873 + co_messages_active = 1;
8879 +void co_free_pages(unsigned long vaddr, int order)
8881 + unsigned long flags;
8883 + co_passage_page_acquire(&flags);
8884 + co_passage_page->operation = CO_OPERATION_FREE_PAGES;
8885 + co_passage_page->params[0] = vaddr;
8886 + co_passage_page->params[1] = order;
8887 + co_switch_wrapper();
8888 + co_passage_page_release(flags);
8891 +int co_alloc_pages(unsigned long vaddr, int order)
8893 + unsigned long flags;
8896 + co_passage_page_acquire(&flags);
8897 + co_passage_page->operation = CO_OPERATION_ALLOC_PAGES;
8898 + co_passage_page->params[0] = vaddr;
8899 + co_passage_page->params[1] = order;
8900 + co_switch_wrapper();
8901 + result = (long)co_passage_page->params[4];
8902 + co_passage_page_release(flags);
8910 +__initcall(initcall_message_queues);
8912 +EXPORT_SYMBOL(co_terminate);
8915 diff -urN a/kernel/panic.c b/kernel/panic.c
8916 --- a/kernel/panic.c
8917 +++ b/kernel/panic.c
8919 #include <linux/sysrq.h>
8920 #include <linux/interrupt.h>
8921 #include <linux/nmi.h>
8922 +#include <linux/cooperative_internal.h>
8927 printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
8930 + if (cooperative_mode_enabled()) {
8931 + co_terminate(CO_TERMINATE_PANIC);
8937 diff -urN a/kernel/printk.c b/kernel/printk.c
8938 --- a/kernel/printk.c
8939 +++ b/kernel/printk.c
8942 #include <asm/uaccess.h>
8944 +#include <linux/cooperative_internal.h>
8946 #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
8948 /* printk's without a loglevel use this.. */
8950 /* Emit the output into the temporary buffer */
8951 printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
8953 + co_printk(printk_buf);
8956 * Copy the output into log_buf. If the caller didn't provide
8957 * appropriate log level tags, we insert them here
8958 diff -urN a/localversion-cooperative b/localversion-cooperative
8959 --- a/localversion-cooperative
8960 +++ b/localversion-cooperative
8963 diff -urN a/mm/bootmem.c b/mm/bootmem.c
8967 #include <linux/bootmem.h>
8968 #include <linux/mmzone.h>
8969 #include <linux/module.h>
8970 +#include <linux/cooperative_internal.h>
8971 #include <asm/dma.h>
8974 @@ -248,6 +249,23 @@
8975 for (i = start; i < start+areasize; i++)
8976 if (unlikely(test_and_set_bit(i, bdata->node_bootmem_map)))
8979 + if (cooperative_mode_enabled()) {
8980 + unsigned long alloc_address = (unsigned long)ret;
8981 + unsigned long alloc_size = size;
8984 + alloc_size += (alloc_address & (~PAGE_MASK));
8985 + alloc_address &= PAGE_MASK;
8986 + alloc_size = (alloc_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
8988 + result = co_alloc_pages(alloc_address, alloc_size);
8990 + free_bootmem((unsigned long)ret, size);
8995 memset(ret, 0, size);
8998 diff -urN a/mm/page_alloc.c b/mm/page_alloc.c
8999 --- a/mm/page_alloc.c
9000 +++ b/mm/page_alloc.c
9002 #include <linux/sysctl.h>
9003 #include <linux/cpu.h>
9004 #include <linux/nodemask.h>
9006 +#include <linux/cooperative_internal.h>
9007 #include <asm/tlbflush.h>
9009 nodemask_t node_online_map = NODE_MASK_NONE;
9012 unsigned long page_idx, index, mask;
9014 + if (cooperative_mode_enabled())
9015 + co_free_pages((unsigned long)page_address(page), 1 << order);
9018 destroy_compound_page(page, order);
9019 mask = (~0UL) << order;
9020 @@ -738,6 +741,37 @@
9022 zone_statistics(zonelist, z);
9023 kernel_map_pages(page, 1 << order, 1);
9025 + if (cooperative_mode_enabled()) {
9026 + int result, retries_left;
9028 + retries_left = 10;
9030 + while (retries_left > 0) {
9031 + result = co_alloc_pages((unsigned long)page_address(page), 1 << order);
9033 + unsigned long cache_size;
9035 + * Whoops, we have allocated too much of the
9036 + * host OS's memory, time to free some cache.
9039 + cache_size = get_page_cache_size()-total_swapcache_pages;
9041 + if (cache_size < ((1 << order)*2))
9042 + cache_size = (1 << order)*2;
9043 + shrink_all_memory(cache_size);
9050 + __free_pages(page, order);
9058 diff -urN a/mm/vmscan.c b/mm/vmscan.c
9061 @@ -1180,7 +1180,7 @@
9062 wake_up_interruptible(&zone->zone_pgdat->kswapd_wait);
9066 +#if defined(CONFIG_PM) || defined(CONFIG_COOPERATIVE)
9068 * Try to free `nr_pages' of memory, system-wide. Returns the number of freed