From 1c11f6a65c0bf8be5961689cf8910e0e96e89cfe Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 10 Jan 2004 21:06:46 +0000 Subject: [PATCH] - series against second suse 2.4.21 kernel b2505 --- .../configurable-x86-stack-2.4.21-suse2.patch | 330 ++++ .../patches/ext3-ea-in-inode-2.4.21-suse2.patch | 759 ++++++++ .../patches/ext3-map_inode_page-2.4.21-suse2.patch | 114 ++ .../patches/ext3-noread-2.4.21-suse2.patch | 218 +++ .../patches/extN-wantedi-2.4.21-suse2.patch | 226 +++ .../patches/linux-2.4.21-xattr-0.8.54-suse2.patch | 258 +++ .../patches/nfs_export_kernel-2.4.21-suse2.patch | 746 ++++++++ .../patches/tcp-zero-copy-2.4.21-suse2.patch | 468 +++++ .../patches/vfs_intent-2.4.21-suse2.patch | 1839 ++++++++++++++++++++ lustre/kernel_patches/series/suse-2.4.21-2 | 30 + 10 files changed, 4988 insertions(+) create mode 100644 lustre/kernel_patches/patches/configurable-x86-stack-2.4.21-suse2.patch create mode 100644 lustre/kernel_patches/patches/ext3-ea-in-inode-2.4.21-suse2.patch create mode 100644 lustre/kernel_patches/patches/ext3-map_inode_page-2.4.21-suse2.patch create mode 100644 lustre/kernel_patches/patches/ext3-noread-2.4.21-suse2.patch create mode 100644 lustre/kernel_patches/patches/extN-wantedi-2.4.21-suse2.patch create mode 100644 lustre/kernel_patches/patches/linux-2.4.21-xattr-0.8.54-suse2.patch create mode 100644 lustre/kernel_patches/patches/nfs_export_kernel-2.4.21-suse2.patch create mode 100644 lustre/kernel_patches/patches/tcp-zero-copy-2.4.21-suse2.patch create mode 100644 lustre/kernel_patches/patches/vfs_intent-2.4.21-suse2.patch create mode 100644 lustre/kernel_patches/series/suse-2.4.21-2 diff --git a/lustre/kernel_patches/patches/configurable-x86-stack-2.4.21-suse2.patch b/lustre/kernel_patches/patches/configurable-x86-stack-2.4.21-suse2.patch new file mode 100644 index 0000000..f682a00 --- /dev/null +++ b/lustre/kernel_patches/patches/configurable-x86-stack-2.4.21-suse2.patch @@ -0,0 +1,330 @@ +Index: kernel-2.4.21/arch/i386/kernel/entry.S +=================================================================== +--- kernel-2.4.21.orig/arch/i386/kernel/entry.S 2003-06-13 07:51:29.000000000 -0700 ++++ kernel-2.4.21/arch/i386/kernel/entry.S 2003-12-04 11:57:01.000000000 -0800 +@@ -45,6 +45,7 @@ + #include + #include + #include ++#include + + EBX = 0x00 + ECX = 0x04 +@@ -130,10 +131,6 @@ + .long 3b,6b; \ + .previous + +-#define GET_CURRENT(reg) \ +- movl $-8192, reg; \ +- andl %esp, reg +- + ENTRY(lcall7) + pushfl # We get a different stack layout with call gates, + pushl %eax # which has to be cleaned up later.. +@@ -149,7 +146,7 @@ + movl %ecx,CS(%esp) # + movl %esp,%ebx + pushl %ebx +- andl $-8192,%ebx # GET_CURRENT ++ andl $-THREAD_SIZE,%ebx # GET_CURRENT + movl exec_domain(%ebx),%edx # Get the execution domain + movl 4(%edx),%edx # Get the lcall7 handler for the domain + pushl $0x7 +@@ -173,7 +170,7 @@ + movl %ecx,CS(%esp) # + movl %esp,%ebx + pushl %ebx +- andl $-8192,%ebx # GET_CURRENT ++ andl $-THREAD_SIZE,%ebx # GET_CURRENT + movl exec_domain(%ebx),%edx # Get the execution domain + movl 4(%edx),%edx # Get the lcall7 handler for the domain + pushl $0x27 +Index: kernel-2.4.21/arch/i386/kernel/smpboot.c +=================================================================== +--- kernel-2.4.21.orig/arch/i386/kernel/smpboot.c 2003-06-13 07:51:29.000000000 -0700 ++++ kernel-2.4.21/arch/i386/kernel/smpboot.c 2003-12-04 11:57:01.000000000 -0800 +@@ -819,7 +819,7 @@ + + /* So we see what's up */ + printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip); +- stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle); ++ stack_start.esp = (void *)idle->thread.esp; + + /* + * This grunge runs the startup process for +@@ -892,7 +892,7 @@ + Dprintk("CPU has booted.\n"); + } else { + boot_error= 1; +- if (*((volatile unsigned char *)phys_to_virt(8192)) ++ if (*((volatile unsigned char *)phys_to_virt(THREAD_SIZE)) + == 0xA5) + /* trampoline started but...? */ + printk("Stuck ??\n"); +@@ -915,7 +915,7 @@ + } + + /* mark "stuck" area as not stuck */ +- *((volatile unsigned long *)phys_to_virt(8192)) = 0; ++ *((volatile unsigned long *)phys_to_virt(THREAD_SIZE)) = 0; + + if(clustered_apic_mode == CLUSTERED_APIC_NUMAQ) { + printk("Restoring NMI vector\n"); +Index: kernel-2.4.21/arch/i386/kernel/traps.c +=================================================================== +--- kernel-2.4.21.orig/arch/i386/kernel/traps.c 2002-11-28 15:53:09.000000000 -0800 ++++ kernel-2.4.21/arch/i386/kernel/traps.c 2003-12-04 11:57:01.000000000 -0800 +@@ -158,7 +158,7 @@ + unsigned long esp = tsk->thread.esp; + + /* User space on another CPU? */ +- if ((esp ^ (unsigned long)tsk) & (PAGE_MASK<<1)) ++ if ((esp ^ (unsigned long)tsk) & ~(THREAD_SIZE - 1)) + return; + show_trace((unsigned long *)esp); + } +Index: kernel-2.4.21/arch/i386/kernel/head.S +=================================================================== +--- kernel-2.4.21.orig/arch/i386/kernel/head.S 2003-06-13 07:51:29.000000000 -0700 ++++ kernel-2.4.21/arch/i386/kernel/head.S 2003-12-04 11:57:01.000000000 -0800 +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + #define OLD_CL_MAGIC_ADDR 0x90020 + #define OLD_CL_MAGIC 0xA33F +@@ -320,7 +321,7 @@ + ret + + ENTRY(stack_start) +- .long SYMBOL_NAME(init_task_union)+8192 ++ .long SYMBOL_NAME(init_task_union)+THREAD_SIZE + .long __KERNEL_DS + + /* This is the default interrupt "handler" :-) */ +Index: kernel-2.4.21/arch/i386/kernel/irq.c +=================================================================== +--- kernel-2.4.21.orig/arch/i386/kernel/irq.c 2002-11-28 15:53:09.000000000 -0800 ++++ kernel-2.4.21/arch/i386/kernel/irq.c 2003-12-04 11:57:01.000000000 -0800 +@@ -581,7 +581,10 @@ + long esp; + + /* Debugging check for stack overflow: is there less than 1KB free? */ +- __asm__ __volatile__("andl %%esp,%0" : "=r" (esp) : "0" (8191)); ++ __asm__ __volatile__( ++ "andl %%esp,%0" ++ : "=r" (esp) : "0" (THREAD_SIZE-1)); ++ + if (unlikely(esp < (sizeof(struct task_struct) + 1024))) { + extern void show_stack(unsigned long *); + +Index: kernel-2.4.21/arch/i386/lib/getuser.S +=================================================================== +--- kernel-2.4.21.orig/arch/i386/lib/getuser.S 1998-01-12 13:42:52.000000000 -0800 ++++ kernel-2.4.21/arch/i386/lib/getuser.S 2003-12-04 11:57:01.000000000 -0800 +@@ -21,6 +21,10 @@ + * as they get called from within inline assembly. + */ + ++/* Duplicated from asm/processor.h */ ++#include ++#include ++ + addr_limit = 12 + + .text +@@ -28,7 +32,7 @@ + .globl __get_user_1 + __get_user_1: + movl %esp,%edx +- andl $0xffffe000,%edx ++ andl $~(THREAD_SIZE - 1),%edx + cmpl addr_limit(%edx),%eax + jae bad_get_user + 1: movzbl (%eax),%edx +@@ -41,7 +45,7 @@ + addl $1,%eax + movl %esp,%edx + jc bad_get_user +- andl $0xffffe000,%edx ++ andl $~(THREAD_SIZE - 1),%edx + cmpl addr_limit(%edx),%eax + jae bad_get_user + 2: movzwl -1(%eax),%edx +@@ -54,7 +58,7 @@ + addl $3,%eax + movl %esp,%edx + jc bad_get_user +- andl $0xffffe000,%edx ++ andl $~(THREAD_SIZE - 1),%edx + cmpl addr_limit(%edx),%eax + jae bad_get_user + 3: movl -3(%eax),%edx +Index: kernel-2.4.21/arch/i386/config.in +=================================================================== +--- kernel-2.4.21.orig/arch/i386/config.in 2003-06-13 07:51:29.000000000 -0700 ++++ kernel-2.4.21/arch/i386/config.in 2003-12-04 11:57:01.000000000 -0800 +@@ -256,6 +256,29 @@ + if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then + define_bool CONFIG_HAVE_DEC_LOCK y + fi ++ ++choice 'Bigger Stack Size Support' \ ++ "off CONFIG_NOBIGSTACK \ ++ 16KB CONFIG_STACK_SIZE_16KB \ ++ 32KB CONFIG_STACK_SIZE_32KB \ ++ 64KB CONFIG_STACK_SIZE_64KB" off ++ ++if [ "$CONFIG_NOBIGSTACK" = "y" ]; then ++ define_int CONFIG_STACK_SIZE_SHIFT 1 ++else ++ if [ "$CONFIG_STACK_SIZE_16KB" = "y" ]; then ++ define_int CONFIG_STACK_SIZE_SHIFT 2 ++ else ++ if [ "$CONFIG_STACK_SIZE_32KB" = "y" ]; then ++ define_int CONFIG_STACK_SIZE_SHIFT 3 ++ else ++ if [ "$CONFIG_STACK_SIZE_64KB" = "y" ]; then ++ define_int CONFIG_STACK_SIZE_SHIFT 4 ++ fi ++ fi ++ fi ++fi ++ + endmenu + + mainmenu_option next_comment +Index: kernel-2.4.21/arch/i386/vmlinux.lds +=================================================================== +--- kernel-2.4.21.orig/arch/i386/vmlinux.lds.S 2002-02-25 11:37:53.000000000 -0800 ++++ kernel-2.4.21/arch/i386/vmlinux.lds.S 2003-12-04 11:57:01.000000000 -0800 +@@ -35,7 +35,8 @@ + + _edata = .; /* End of data section */ + +- . = ALIGN(8192); /* init_task */ ++/* chose the biggest of the possible stack sizes here? */ ++ . = ALIGN(65536); /* init_task */ + .data.init_task : { *(.data.init_task) } + + . = ALIGN(4096); /* Init code and data */ +Index: kernel-2.4.21/include/asm-i386/current.h +=================================================================== +--- kernel-2.4.21.orig/include/asm-i386/current.h 1998-08-14 16:35:22.000000000 -0700 ++++ kernel-2.4.21/include/asm-i386/current.h 2003-12-04 11:57:01.000000000 -0800 +@@ -1,15 +1,43 @@ + #ifndef _I386_CURRENT_H + #define _I386_CURRENT_H ++#include ++ ++/* ++ * Configurable page sizes on i386, mainly for debugging purposes. ++ * (c) Balbir Singh ++ */ ++ ++#ifdef __ASSEMBLY__ ++ ++#define PAGE_SIZE 4096 /* as cannot handle 1UL << 12 */ ++#define THREAD_SIZE ((1 << CONFIG_STACK_SIZE_SHIFT) * PAGE_SIZE) ++ ++#define GET_CURRENT(reg) \ ++ movl $-THREAD_SIZE, reg; \ ++ andl %esp, reg ++ ++#else /* __ASSEMBLY__ */ ++ ++#define THREAD_SIZE ((1 << CONFIG_STACK_SIZE_SHIFT) * PAGE_SIZE) ++#define alloc_task_struct() \ ++ ((struct task_struct *) __get_free_pages(GFP_KERNEL,CONFIG_STACK_SIZE_SHIFT)) ++ ++#define free_task_struct(p) \ ++ free_pages((unsigned long) (p), CONFIG_STACK_SIZE_SHIFT) ++ ++#define INIT_TASK_SIZE THREAD_SIZE + + struct task_struct; + + static inline struct task_struct * get_current(void) + { + struct task_struct *current; +- __asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL)); ++ __asm__("andl %%esp,%0; ":"=r" (current) : "0" (~(THREAD_SIZE - 1))); + return current; + } + + #define current get_current() + ++#endif /* __ASSEMBLY__ */ ++ + #endif /* !(_I386_CURRENT_H) */ +Index: kernel-2.4.21/include/asm-i386/hw_irq.h +=================================================================== +--- kernel-2.4.21.orig/include/asm-i386/hw_irq.h 2001-11-22 11:46:18.000000000 -0800 ++++ kernel-2.4.21/include/asm-i386/hw_irq.h 2003-12-04 11:57:01.000000000 -0800 +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + /* + * IDT vectors usable for external interrupt sources start +@@ -113,10 +114,6 @@ + #define IRQ_NAME2(nr) nr##_interrupt(void) + #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) + +-#define GET_CURRENT \ +- "movl %esp, %ebx\n\t" \ +- "andl $-8192, %ebx\n\t" +- + /* + * SMP has a few special interrupts for IPI messages + */ +Index: kernel-2.4.21/include/asm-i386/processor.h +=================================================================== +--- kernel-2.4.21.orig/include/asm-i386/processor.h 2003-06-13 07:51:38.000000000 -0700 ++++ kernel-2.4.21/include/asm-i386/processor.h 2003-12-04 11:57:01.000000000 -0800 +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -453,9 +454,6 @@ + #define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1019]) + #define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022]) + +-#define THREAD_SIZE (2*PAGE_SIZE) +-#define alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1)) +-#define free_task_struct(p) free_pages((unsigned long) (p), 1) + #define get_task_struct(tsk) atomic_inc(&virt_to_page(tsk)->count) + + #define init_task (init_task_union.task) +Index: kernel-2.4.21/include/linux/sched.h +=================================================================== +--- kernel-2.4.21.orig/include/linux/sched.h 2003-06-13 15:26:52.000000000 -0700 ++++ kernel-2.4.21/include/linux/sched.h 2003-12-04 12:00:14.000000000 -0800 +@@ -2,6 +2,7 @@ + #define _LINUX_SCHED_H + + #include /* for HZ */ ++#include /* maybe for INIT_TASK_SIZE */ + + extern unsigned long event; + +Index: kernel-2.4.21/include/asm-x86_64/current.h +=================================================================== +--- kernel-2.4.21.orig/include/asm-x86_64/current.h 2003-06-13 15:26:52.000000000 -0700 ++++ kernel-2.4.21/include/asm-x86_64/current.h 2003-12-04 12:00:13.000000000 -0800 +@@ -5,6 +5,7 @@ + struct task_struct; + + #include ++#include + + static inline struct task_struct *get_current(void) + { diff --git a/lustre/kernel_patches/patches/ext3-ea-in-inode-2.4.21-suse2.patch b/lustre/kernel_patches/patches/ext3-ea-in-inode-2.4.21-suse2.patch new file mode 100644 index 0000000..e1dab00 --- /dev/null +++ b/lustre/kernel_patches/patches/ext3-ea-in-inode-2.4.21-suse2.patch @@ -0,0 +1,759 @@ + fs/ext3/ialloc.c | 6 + fs/ext3/inode.c | 12 + fs/ext3/super.c | 6 + fs/ext3/xattr.c | 597 +++++++++++++++++++++++++++++++++++++++++++++- + include/linux/ext3_fs.h | 2 + include/linux/ext3_fs_i.h | 3 + 6 files changed, 615 insertions(+), 11 deletions(-) + +Index: linux-2.4.21-chaos/fs/ext3/ialloc.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/ext3/ialloc.c 2003-12-12 17:39:10.000000000 +0300 ++++ linux-2.4.21-chaos/fs/ext3/ialloc.c 2003-12-12 17:39:55.000000000 +0300 +@@ -580,6 +580,12 @@ + insert_inode_hash(inode); + inode->i_generation = sbi->s_next_generation++; + ++ if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) { ++ EXT3_I(inode)->i_extra_isize = sizeof(__u16) /* i_extra_isize */ ++ + sizeof(__u16); /* i_pad1 */ ++ } else ++ EXT3_I(inode)->i_extra_isize = 0; ++ + inode->u.ext3_i.i_state = EXT3_STATE_NEW; + err = ext3_get_inode_loc_new(inode, &iloc, 1); + if (err) goto fail; +Index: linux-2.4.21-chaos/fs/ext3/inode.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/ext3/inode.c 2003-12-12 17:39:11.000000000 +0300 ++++ linux-2.4.21-chaos/fs/ext3/inode.c 2003-12-12 17:39:55.000000000 +0300 +@@ -2502,6 +2502,12 @@ + ei->i_data[block] = iloc.raw_inode->i_block[block]; + INIT_LIST_HEAD(&ei->i_orphan); + ++ if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) ++ EXT3_I(inode)->i_extra_isize = ++ le16_to_cpu(raw_inode->i_extra_isize); ++ else ++ EXT3_I(inode)->i_extra_isize = 0; ++ + if (S_ISREG(inode->i_mode)) { + inode->i_op = &ext3_file_inode_operations; + inode->i_fop = &ext3_file_operations; +@@ -2564,6 +2570,8 @@ + if (err) + goto out_brelse; + } ++ if (EXT3_I(inode)->i_state & EXT3_STATE_NEW) ++ memset(raw_inode, 0, EXT3_INODE_SIZE(inode->i_sb)); + raw_inode->i_mode = cpu_to_le16(inode->i_mode); + if(!(test_opt(inode->i_sb, NO_UID32))) { + raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid)); +@@ -2646,6 +2654,10 @@ + else for (block = 0; block < EXT3_N_BLOCKS; block++) + raw_inode->i_block[block] = ei->i_data[block]; + ++ if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) ++ raw_inode->i_extra_isize = ++ cpu_to_le16(EXT3_I(inode)->i_extra_isize); ++ + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + rc = ext3_journal_dirty_metadata(handle, bh); + if (!err) +Index: linux-2.4.21-chaos/fs/ext3/xattr.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/ext3/xattr.c 2003-12-12 17:38:44.000000000 +0300 ++++ linux-2.4.21-chaos/fs/ext3/xattr.c 2003-12-12 17:42:58.000000000 +0300 +@@ -88,6 +88,9 @@ + struct buffer_head *, + struct ext3_xattr_header *); + ++int ext3_xattr_block_set(handle_t *, struct inode *, int, const char *, ++ const void *, size_t, int); ++ + #ifdef CONFIG_EXT3_FS_XATTR_SHARING + + static int ext3_xattr_cache_insert(struct buffer_head *); +@@ -256,17 +259,12 @@ + } + + /* +- * ext3_xattr_get() +- * +- * Copy an extended attribute into the buffer +- * provided, or compute the buffer size required. +- * Buffer is NULL to compute the size of the buffer required. ++ * ext3_xattr_block_get() + * +- * Returns a negative error number on failure, or the number of bytes +- * used / required on success. ++ * routine looks for attribute in EA block and returns it's value and size + */ + int +-ext3_xattr_get(struct inode *inode, int name_index, const char *name, ++ext3_xattr_block_get(struct inode *inode, int name_index, const char *name, + void *buffer, size_t buffer_size) + { + struct buffer_head *bh = NULL; +@@ -359,6 +357,94 @@ + } + + /* ++ * ext3_xattr_ibode_get() ++ * ++ * routine looks for attribute in inode body and returns it's value and size ++ */ ++int ++ext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name, ++ void *buffer, size_t buffer_size) ++{ ++ int size, name_len = strlen(name), storage_size; ++ struct ext3_xattr_entry *last; ++ struct ext3_inode *raw_inode; ++ struct ext3_iloc iloc; ++ char *start, *end; ++ int ret = -ENOENT; ++ ++ if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE) ++ return -ENOENT; ++ ++ ret = ext3_get_inode_loc(inode, &iloc); ++ if (ret) ++ return ret; ++ raw_inode = iloc.raw_inode; ++ ++ storage_size = EXT3_SB(inode->i_sb)->s_inode_size - ++ EXT3_GOOD_OLD_INODE_SIZE - ++ EXT3_I(inode)->i_extra_isize - ++ sizeof(__u32); ++ start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE + ++ EXT3_I(inode)->i_extra_isize; ++ if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) { ++ brelse(iloc.bh); ++ return -ENOENT; ++ } ++ start += sizeof(__u32); ++ end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; ++ ++ last = (struct ext3_xattr_entry *) start; ++ while (!IS_LAST_ENTRY(last)) { ++ struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last); ++ if (le32_to_cpu(last->e_value_size) > storage_size || ++ (char *) next >= end) { ++ ext3_error(inode->i_sb, "ext3_xattr_ibody_get", ++ "inode %ld", inode->i_ino); ++ brelse(iloc.bh); ++ return -EIO; ++ } ++ if (name_index == last->e_name_index && ++ name_len == last->e_name_len && ++ !memcmp(name, last->e_name, name_len)) ++ goto found; ++ last = next; ++ } ++ ++ /* can't find EA */ ++ brelse(iloc.bh); ++ return -ENOENT; ++ ++found: ++ size = le32_to_cpu(last->e_value_size); ++ if (buffer) { ++ ret = -ERANGE; ++ if (buffer_size >= size) { ++ memcpy(buffer, start + le16_to_cpu(last->e_value_offs), ++ size); ++ ret = size; ++ } ++ } else ++ ret = size; ++ brelse(iloc.bh); ++ return ret; ++} ++ ++int ext3_xattr_get(struct inode *inode, int name_index, const char *name, ++ void *buffer, size_t buffer_size) ++{ ++ int err; ++ ++ /* try to find attribute in inode body */ ++ err = ext3_xattr_ibody_get(inode, name_index, name, ++ buffer, buffer_size); ++ if (err < 0) ++ /* search was unsuccessful, try to find EA in dedicated block */ ++ err = ext3_xattr_block_get(inode, name_index, name, ++ buffer, buffer_size); ++ return err; ++} ++ ++/* + * ext3_xattr_list() + * + * Copy a list of attribute names into the buffer +@@ -369,7 +455,7 @@ + * used / required on success. + */ + int +-ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) ++ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size) + { + struct buffer_head *bh = NULL; + struct ext3_xattr_entry *entry; +@@ -446,6 +532,131 @@ + return error; + } + ++/* ext3_xattr_ibody_list() ++ * ++ * generate list of attributes stored in inode body ++ */ ++int ++ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size) ++{ ++ struct ext3_xattr_entry *last; ++ struct ext3_inode *raw_inode; ++ char *start, *end, *buf; ++ struct ext3_iloc iloc; ++ int storage_size; ++ int ret; ++ int size = 0; ++ ++ if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE) ++ return 0; ++ ++ ret = ext3_get_inode_loc(inode, &iloc); ++ if (ret) ++ return ret; ++ raw_inode = iloc.raw_inode; ++ ++ storage_size = EXT3_SB(inode->i_sb)->s_inode_size - ++ EXT3_GOOD_OLD_INODE_SIZE - ++ EXT3_I(inode)->i_extra_isize - ++ sizeof(__u32); ++ start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE + ++ EXT3_I(inode)->i_extra_isize; ++ if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) { ++ brelse(iloc.bh); ++ return 0; ++ } ++ start += sizeof(__u32); ++ end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; ++ ++ last = (struct ext3_xattr_entry *) start; ++ while (!IS_LAST_ENTRY(last)) { ++ struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last); ++ struct ext3_xattr_handler *handler; ++ if (le32_to_cpu(last->e_value_size) > storage_size || ++ (char *) next >= end) { ++ ext3_error(inode->i_sb, "ext3_xattr_ibody_list", ++ "inode %ld", inode->i_ino); ++ brelse(iloc.bh); ++ return -EIO; ++ } ++ handler = ext3_xattr_handler(last->e_name_index); ++ if (handler) ++ size += handler->list(NULL, inode, last->e_name, ++ last->e_name_len); ++ last = next; ++ } ++ ++ if (!buffer) { ++ ret = size; ++ goto cleanup; ++ } else { ++ ret = -ERANGE; ++ if (size > buffer_size) ++ goto cleanup; ++ } ++ ++ last = (struct ext3_xattr_entry *) start; ++ buf = buffer; ++ while (!IS_LAST_ENTRY(last)) { ++ struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last); ++ struct ext3_xattr_handler *handler; ++ handler = ext3_xattr_handler(last->e_name_index); ++ if (handler) ++ buf += handler->list(buf, inode, last->e_name, ++ last->e_name_len); ++ last = next; ++ } ++ ret = size; ++cleanup: ++ brelse(iloc.bh); ++ return ret; ++} ++ ++/* ++ * ext3_xattr_list() ++ * ++ * Copy a list of attribute names into the buffer ++ * provided, or compute the buffer size required. ++ * Buffer is NULL to compute the size of the buffer required. ++ * ++ * Returns a negative error number on failure, or the number of bytes ++ * used / required on success. ++ */ ++int ++ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) ++{ ++ int error; ++ int size = buffer_size; ++ ++ /* get list of attributes stored in inode body */ ++ error = ext3_xattr_ibody_list(inode, buffer, buffer_size); ++ if (error < 0) { ++ /* some error occured while collecting ++ * attributes in inode body */ ++ size = 0; ++ goto cleanup; ++ } ++ size = error; ++ ++ /* get list of attributes stored in dedicated block */ ++ if (buffer) { ++ buffer_size -= error; ++ if (buffer_size <= 0) { ++ buffer = NULL; ++ buffer_size = 0; ++ } else ++ buffer += error; ++ } ++ ++ error = ext3_xattr_block_list(inode, buffer, buffer_size); ++ if (error < 0) ++ /* listing was successful, so we return len */ ++ size = 0; ++ ++cleanup: ++ return error + size; ++} ++ + /* + * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is + * not set, set it. +@@ -480,6 +691,101 @@ + */ + int + ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, ++ const char *name, const void *value, size_t value_len, ++ int flags) ++{ ++ struct ext3_xattr_entry entry; ++ int err, where = 0, found = 0, total; ++ int free1 = -1, free2 = -1; ++ int name_len; ++ ++ ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", ++ name_index, name, value, (long)value_len); ++ ++ if (IS_RDONLY(inode)) ++ return -EROFS; ++ if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) ++ return -EPERM; ++ if (value == NULL) ++ value_len = 0; ++ if (name == NULL) ++ return -EINVAL; ++ name_len = strlen(name); ++ if (name_len > 255 || value_len > inode->i_sb->s_blocksize) ++ return -ERANGE; ++ ++ /* try to find attribute in inode body */ ++ err = ext3_xattr_ibody_find(inode, name_index, name, &entry, &free1); ++ if (err == 0) { ++ /* found EA in inode */ ++ found = 1; ++ where = 0; ++ } else if (err == -ENOENT) { ++ /* there is no such attribute in inode body */ ++ /* try to find attribute in dedicated block */ ++ err = ext3_xattr_block_find(inode, name_index, name, ++ &entry, &free2); ++ if (err != 0 && err != -ENOENT) { ++ /* not found EA in block */ ++ goto finish; ++ } ++ /* found EA in block */ ++ where = 1; ++ found = 1; ++ } else ++ goto finish; ++ ++ /* check flags: may replace? may create ? */ ++ if (found && (flags & XATTR_CREATE)) { ++ err = -EEXIST; ++ goto finish; ++ } else if (!found && (flags & XATTR_REPLACE)) { ++ err = -ENODATA; ++ goto finish; ++ } ++ ++ /* check if we have enough space to store attribute */ ++ total = EXT3_XATTR_LEN(strlen(name)) + value_len; ++ if (free1 >= 0 && total > free1 && free2 >= 0 && total > free2) { ++ /* have no enough space */ ++ err = -ENOSPC; ++ goto finish; ++ } ++ ++ /* time to remove attribute */ ++ if (found) { ++ if (where == 0) { ++ /* EA is stored in inode body */ ++ ext3_xattr_ibody_set(handle, inode, name_index, name, ++ NULL, 0, flags); ++ } else { ++ /* EA is stored in separated block */ ++ ext3_xattr_block_set(handle, inode, name_index, name, ++ NULL, 0, flags); ++ } ++ } ++ ++ /* try to store EA in inode body */ ++ err = ext3_xattr_ibody_set(handle, inode, name_index, name, ++ value, value_len, flags); ++ if (err) { ++ /* can't store EA in inode body */ ++ /* try to store in block */ ++ err = ext3_xattr_block_set(handle, inode, name_index, ++ name, value, value_len, flags); ++ } ++ ++finish: ++ return err; ++} ++ ++/* ++ * ext3_xattr_block_set() ++ * ++ * this routine add/remove/replace attribute in EA block ++ */ ++int ++ext3_xattr_block_set(handle_t *handle, struct inode *inode, int name_index, + const char *name, const void *value, size_t value_len, + int flags) + { +@@ -868,6 +1174,279 @@ + } + + /* ++ * ext3_xattr_ibody_find() ++ * ++ * search attribute and calculate free space in inode body ++ * NOTE: free space includes space our attribute hold ++ */ ++int ++ext3_xattr_ibody_find(struct inode *inode, int name_index, ++ const char *name, struct ext3_xattr_entry *rentry, int *free) ++{ ++ struct ext3_xattr_entry *last; ++ struct ext3_inode *raw_inode; ++ int name_len = strlen(name); ++ int err, storage_size; ++ struct ext3_iloc iloc; ++ char *start, *end; ++ int ret = -ENOENT; ++ ++ if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE) ++ return ret; ++ ++ err = ext3_get_inode_loc(inode, &iloc); ++ if (err) ++ return -EIO; ++ raw_inode = iloc.raw_inode; ++ ++ storage_size = EXT3_SB(inode->i_sb)->s_inode_size - ++ EXT3_GOOD_OLD_INODE_SIZE - ++ EXT3_I(inode)->i_extra_isize - ++ sizeof(__u32); ++ *free = storage_size - sizeof(__u32); ++ start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE + ++ EXT3_I(inode)->i_extra_isize; ++ if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) { ++ brelse(iloc.bh); ++ return -ENOENT; ++ } ++ start += sizeof(__u32); ++ end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; ++ ++ last = (struct ext3_xattr_entry *) start; ++ while (!IS_LAST_ENTRY(last)) { ++ struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last); ++ if (le32_to_cpu(last->e_value_size) > storage_size || ++ (char *) next >= end) { ++ ext3_error(inode->i_sb, "ext3_xattr_ibody_find", ++ "inode %ld", inode->i_ino); ++ brelse(iloc.bh); ++ return -EIO; ++ } ++ ++ if (name_index == last->e_name_index && ++ name_len == last->e_name_len && ++ !memcmp(name, last->e_name, name_len)) { ++ memcpy(rentry, last, sizeof(struct ext3_xattr_entry)); ++ ret = 0; ++ } else { ++ *free -= EXT3_XATTR_LEN(last->e_name_len); ++ *free -= le32_to_cpu(last->e_value_size); ++ } ++ last = next; ++ } ++ ++ brelse(iloc.bh); ++ return ret; ++} ++ ++/* ++ * ext3_xattr_block_find() ++ * ++ * search attribute and calculate free space in EA block (if it allocated) ++ * NOTE: free space includes space our attribute hold ++ */ ++int ++ext3_xattr_block_find(struct inode *inode, int name_index, const char *name, ++ struct ext3_xattr_entry *rentry, int *free) ++{ ++ struct buffer_head *bh = NULL; ++ struct ext3_xattr_entry *entry; ++ char *end; ++ int name_len, error = -ENOENT; ++ ++ if (!EXT3_I(inode)->i_file_acl) { ++ *free = inode->i_sb->s_blocksize - ++ sizeof(struct ext3_xattr_header) - ++ sizeof(__u32); ++ return -ENOENT; ++ } ++ ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl); ++ bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); ++ if (!bh) ++ return -EIO; ++ ea_bdebug(bh, "b_count=%d, refcount=%d", ++ atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); ++ end = bh->b_data + bh->b_size; ++ if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || ++ HDR(bh)->h_blocks != cpu_to_le32(1)) { ++bad_block: ext3_error(inode->i_sb, "ext3_xattr_get", ++ "inode %ld: bad block %d", inode->i_ino, ++ EXT3_I(inode)->i_file_acl); ++ brelse(bh); ++ return -EIO; ++ } ++ /* find named attribute */ ++ name_len = strlen(name); ++ *free = bh->b_size - sizeof(__u32); ++ ++ entry = FIRST_ENTRY(bh); ++ while (!IS_LAST_ENTRY(entry)) { ++ struct ext3_xattr_entry *next = ++ EXT3_XATTR_NEXT(entry); ++ if ((char *)next >= end) ++ goto bad_block; ++ if (name_index == entry->e_name_index && ++ name_len == entry->e_name_len && ++ memcmp(name, entry->e_name, name_len) == 0) { ++ memcpy(rentry, entry, sizeof(struct ext3_xattr_entry)); ++ error = 0; ++ } else { ++ *free -= EXT3_XATTR_LEN(entry->e_name_len); ++ *free -= le32_to_cpu(entry->e_value_size); ++ } ++ entry = next; ++ } ++ brelse(bh); ++ ++ return error; ++} ++ ++/* ++ * ext3_xattr_inode_set() ++ * ++ * this routine add/remove/replace attribute in inode body ++ */ ++int ++ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, int name_index, ++ const char *name, const void *value, size_t value_len, ++ int flags) ++{ ++ struct ext3_xattr_entry *last, *next, *here = NULL; ++ struct ext3_inode *raw_inode; ++ int name_len = strlen(name); ++ int esize = EXT3_XATTR_LEN(name_len); ++ struct buffer_head *bh; ++ int err, storage_size; ++ struct ext3_iloc iloc; ++ int free, min_offs; ++ char *start, *end; ++ ++ if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE) ++ return -ENOSPC; ++ ++ err = ext3_get_inode_loc(inode, &iloc); ++ if (err) ++ return err; ++ raw_inode = iloc.raw_inode; ++ bh = iloc.bh; ++ ++ storage_size = EXT3_SB(inode->i_sb)->s_inode_size - ++ EXT3_GOOD_OLD_INODE_SIZE - ++ EXT3_I(inode)->i_extra_isize - ++ sizeof(__u32); ++ start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE + ++ EXT3_I(inode)->i_extra_isize; ++ if ((*(__u32*) start) != EXT3_XATTR_MAGIC) { ++ /* inode had no attributes before */ ++ *((__u32*) start) = cpu_to_le32(EXT3_XATTR_MAGIC); ++ } ++ start += sizeof(__u32); ++ end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; ++ min_offs = storage_size; ++ free = storage_size - sizeof(__u32); ++ ++ last = (struct ext3_xattr_entry *) start; ++ while (!IS_LAST_ENTRY(last)) { ++ next = EXT3_XATTR_NEXT(last); ++ if (le32_to_cpu(last->e_value_size) > storage_size || ++ (char *) next >= end) { ++ ext3_error(inode->i_sb, "ext3_xattr_ibody_set", ++ "inode %ld", inode->i_ino); ++ brelse(bh); ++ return -EIO; ++ } ++ ++ if (last->e_value_size) { ++ int offs = le16_to_cpu(last->e_value_offs); ++ if (offs < min_offs) ++ min_offs = offs; ++ } ++ if (name_index == last->e_name_index && ++ name_len == last->e_name_len && ++ !memcmp(name, last->e_name, name_len)) ++ here = last; ++ else { ++ /* we calculate all but our attribute ++ * because it will be removed before changing */ ++ free -= EXT3_XATTR_LEN(last->e_name_len); ++ free -= le32_to_cpu(last->e_value_size); ++ } ++ last = next; ++ } ++ ++ if (value && (esize + value_len > free)) { ++ brelse(bh); ++ return -ENOSPC; ++ } ++ ++ err = ext3_reserve_inode_write(handle, inode, &iloc); ++ if (err) { ++ brelse(bh); ++ return err; ++ } ++ ++ if (here) { ++ /* time to remove old value */ ++ struct ext3_xattr_entry *e; ++ int size = le32_to_cpu(here->e_value_size); ++ int border = le16_to_cpu(here->e_value_offs); ++ char *src; ++ ++ /* move tail */ ++ memmove(start + min_offs + size, start + min_offs, ++ border - min_offs); ++ ++ /* recalculate offsets */ ++ e = (struct ext3_xattr_entry *) start; ++ while (!IS_LAST_ENTRY(e)) { ++ struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(e); ++ int offs = le16_to_cpu(e->e_value_offs); ++ if (offs < border) ++ e->e_value_offs = ++ cpu_to_le16(offs + size); ++ e = next; ++ } ++ min_offs += size; ++ ++ /* remove entry */ ++ border = EXT3_XATTR_LEN(here->e_name_len); ++ src = (char *) here + EXT3_XATTR_LEN(here->e_name_len); ++ size = (char *) last - src; ++ if ((char *) here + size > end) ++ printk("ALERT at %s:%d: 0x%p + %d > 0x%p\n", ++ __FILE__, __LINE__, here, size, end); ++ memmove(here, src, size); ++ last = (struct ext3_xattr_entry *) ((char *) last - border); ++ *((__u32 *) last) = 0; ++ } ++ ++ if (value) { ++ int offs = min_offs - value_len; ++ /* use last to create new entry */ ++ last->e_name_len = strlen(name); ++ last->e_name_index = name_index; ++ last->e_value_offs = cpu_to_le16(offs); ++ last->e_value_size = cpu_to_le32(value_len); ++ last->e_hash = last->e_value_block = 0; ++ memset(last->e_name, 0, esize); ++ memcpy(last->e_name, name, last->e_name_len); ++ if (start + offs + value_len > end) ++ printk("ALERT at %s:%d: 0x%p + %d + %d > 0x%p\n", ++ __FILE__, __LINE__, start, offs, ++ value_len, end); ++ memcpy(start + offs, value, value_len); ++ last = EXT3_XATTR_NEXT(last); ++ *((__u32 *) last) = 0; ++ } ++ ++ ext3_mark_iloc_dirty(handle, inode, &iloc); ++ brelse(bh); ++ ++ return 0; ++} ++ ++/* + * ext3_xattr_set_trans() + * + * Like ext3_xattr_set_handle, but start from an inode. This extended +Index: linux-2.4.21-chaos/fs/ext3/super.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/ext3/super.c 2003-12-12 17:39:11.000000000 +0300 ++++ linux-2.4.21-chaos/fs/ext3/super.c 2003-12-12 17:39:55.000000000 +0300 +@@ -1354,8 +1354,10 @@ + } else { + sbi->s_inode_size = le16_to_cpu(es->s_inode_size); + sbi->s_first_ino = le32_to_cpu(es->s_first_ino); +- if (sbi->s_inode_size != EXT3_GOOD_OLD_INODE_SIZE) { +- printk (KERN_ERR ++ if ((sbi->s_inode_size < EXT3_GOOD_OLD_INODE_SIZE) || ++ (sbi->s_inode_size & (sbi->s_inode_size - 1)) || ++ (sbi->s_inode_size > blocksize)) { ++ printk (KERN_ERR + "EXT3-fs: unsupported inode size: %d\n", + sbi->s_inode_size); + goto failed_mount; +Index: linux-2.4.21-chaos/include/linux/ext3_fs.h +=================================================================== +--- linux-2.4.21-chaos.orig/include/linux/ext3_fs.h 2003-12-12 17:39:10.000000000 +0300 ++++ linux-2.4.21-chaos/include/linux/ext3_fs.h 2003-12-12 17:39:55.000000000 +0300 +@@ -268,6 +268,8 @@ + __u32 m_i_reserved2[2]; + } masix2; + } osd2; /* OS dependent 2 */ ++ __u16 i_extra_isize; ++ __u16 i_pad1; + }; + + #define i_size_high i_dir_acl +Index: linux-2.4.21-chaos/include/linux/ext3_fs_i.h +=================================================================== +--- linux-2.4.21-chaos.orig/include/linux/ext3_fs_i.h 2003-12-05 16:54:33.000000000 +0300 ++++ linux-2.4.21-chaos/include/linux/ext3_fs_i.h 2003-12-12 17:39:55.000000000 +0300 +@@ -76,6 +76,9 @@ + */ + loff_t i_disksize; + ++ /* on-disk additional lenght */ ++ __u16 i_extra_isize; ++ + /* + * truncate_sem is for serialising ext3_truncate() against + * ext3_getblock(). In the 2.4 ext2 design, great chunks of inode's diff --git a/lustre/kernel_patches/patches/ext3-map_inode_page-2.4.21-suse2.patch b/lustre/kernel_patches/patches/ext3-map_inode_page-2.4.21-suse2.patch new file mode 100644 index 0000000..f952079 --- /dev/null +++ b/lustre/kernel_patches/patches/ext3-map_inode_page-2.4.21-suse2.patch @@ -0,0 +1,114 @@ + + + + fs/ext3/ext3-exports.c | 3 ++ + fs/ext3/inode.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 58 insertions(+) + +Index: linux-2.4.21-suse2/fs/ext3/inode.c +=================================================================== +--- linux-2.4.21-suse2.orig/fs/ext3/inode.c 2004-01-10 15:38:24.000000000 +0300 ++++ linux-2.4.21-suse2/fs/ext3/inode.c 2004-01-10 16:22:45.000000000 +0300 +@@ -3084,7 +3084,7 @@ + /* alloc blocks one by one */ + for (i = 0; i < nblocks; i++) { + ret = ext3_get_block_handle(handle, inode, blocks[i], +- &bh_tmp, 1); ++ &bh_tmp, 1, 1); + if (ret) + break; + +@@ -3105,3 +3105,75 @@ + ret = ret2; + return ret; + } ++ ++/* copied from fs/buffer.c */ ++static void unmap_underlying_metadata(struct buffer_head * bh) ++{ ++ struct buffer_head *old_bh; ++ ++ old_bh = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size); ++ if (old_bh) { ++ mark_buffer_clean(old_bh); ++ wait_on_buffer(old_bh); ++ clear_bit(BH_Req, &old_bh->b_state); ++ __brelse(old_bh); ++ } ++} ++ ++int ext3_map_inode_page(struct inode *inode, struct page *page, ++ unsigned long *blocks, int *created, int create) ++{ ++ unsigned int blocksize, blocks_per_page; ++ unsigned long iblock; ++ void *handle; ++ int i, rc = 0, failed = 0, needed_blocks; ++ ++ blocksize = inode->i_sb->s_blocksize; ++ blocks_per_page = PAGE_SIZE >> inode->i_sb->s_blocksize_bits; ++ iblock = page->index * blocks_per_page; ++ ++ for (i = 0; i < blocks_per_page; i++, iblock++) { ++ blocks[i] = ext3_bmap(inode->i_mapping, iblock); ++ if (blocks[i] == 0) { ++ failed++; ++ created[i] = -1; ++ } else { ++ created[i] = 0; ++ } ++ } ++ ++ if (failed == 0 || create == 0) ++ return 0; ++ ++ needed_blocks = ext3_writepage_trans_blocks(inode); ++ lock_kernel(); ++ handle = ext3_journal_start(inode, needed_blocks); ++ unlock_kernel(); ++ if (IS_ERR(handle)) ++ return PTR_ERR(handle); ++ ++ iblock = page->index * blocks_per_page; ++ for (i = 0; i < blocks_per_page; i++, iblock++) { ++ struct buffer_head bh; ++ ++ if (blocks[i] != 0) ++ continue; ++ ++ rc = ext3_get_block_handle(handle, inode, iblock, &bh, 1, 1); ++ if (rc) { ++ printk(KERN_INFO "ext3_map_inode_page: error %d " ++ "allocating block %ld\n", rc, iblock); ++ goto out; ++ } ++ if (buffer_new(&bh)) ++ unmap_underlying_metadata(&bh); ++ blocks[i] = bh.b_blocknr; ++ created[i] = 1; ++ } ++ ++ out: ++ lock_kernel(); ++ ext3_journal_stop(handle, inode); ++ unlock_kernel(); ++ return rc; ++} +Index: linux-2.4.21-suse2/fs/ext3/ext3-exports.c +=================================================================== +--- linux-2.4.21-suse2.orig/fs/ext3/ext3-exports.c 2004-01-10 15:38:24.000000000 +0300 ++++ linux-2.4.21-suse2/fs/ext3/ext3-exports.c 2004-01-10 16:22:09.000000000 +0300 +@@ -9,6 +9,8 @@ + + int ext3_prep_san_write(struct inode *inode, long *blocks, + int nblocks, loff_t newsize); ++int ext3_map_inode_page(struct inode *inode, struct page *page, ++ unsigned long *block, int *created, int create); + + EXPORT_SYMBOL(ext3_force_commit); + EXPORT_SYMBOL(ext3_bread); +@@ -19,3 +21,4 @@ + EXPORT_SYMBOL(ext3_xattr_list); + EXPORT_SYMBOL(ext3_xattr_set); + EXPORT_SYMBOL(ext3_prep_san_write); ++EXPORT_SYMBOL(ext3_map_inode_page); diff --git a/lustre/kernel_patches/patches/ext3-noread-2.4.21-suse2.patch b/lustre/kernel_patches/patches/ext3-noread-2.4.21-suse2.patch new file mode 100644 index 0000000..b4b5048 --- /dev/null +++ b/lustre/kernel_patches/patches/ext3-noread-2.4.21-suse2.patch @@ -0,0 +1,218 @@ + fs/ext3/ialloc.c | 47 ++++++++++++++++++++++- + fs/ext3/inode.c | 96 +++++++++++++++++++++++++++++++++++++----------- + include/linux/ext3_fs.h | 2 + + 3 files changed, 121 insertions(+), 24 deletions(-) + +--- linux-2.4.20/fs/ext3/ialloc.c~ext3-noread-2.4.20 2003-05-16 12:21:39.000000000 +0800 ++++ linux-2.4.20-root/fs/ext3/ialloc.c 2003-05-16 12:21:46.000000000 +0800 +@@ -289,6 +289,37 @@ error_return: + } + + /* ++ * @block_group: block group of inode ++ * @offset: relative offset of inode within @block_group ++ * ++ * Check whether any of the inodes in this disk block are in use. ++ * ++ * Caller must be holding superblock lock (group/bitmap read lock in future). ++ */ ++int ext3_itable_block_used(struct super_block *sb, unsigned int block_group, ++ int offset) ++{ ++ int bitmap_nr = load_inode_bitmap(sb, block_group); ++ int inodes_per_block; ++ unsigned long inum, iend; ++ struct buffer_head *ibitmap; ++ ++ if (bitmap_nr < 0) ++ return 1; ++ ++ inodes_per_block = sb->s_blocksize / EXT3_SB(sb)->s_inode_size; ++ inum = offset & ~(inodes_per_block - 1); ++ iend = inum + inodes_per_block; ++ ibitmap = EXT3_SB(sb)->s_inode_bitmap[bitmap_nr]; ++ for (; inum < iend; inum++) { ++ if (inum != offset && ext3_test_bit(inum, ibitmap->b_data)) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* + * There are two policies for allocating an inode. If the new inode is + * a directory, then a forward search is made for a block group with both + * free space and a low directory-to-inode ratio; if that fails, then of +@@ -310,6 +341,7 @@ struct inode * ext3_new_inode (handle_t + struct ext3_group_desc * gdp; + struct ext3_group_desc * tmp; + struct ext3_super_block * es; ++ struct ext3_iloc iloc; + int err = 0; + + /* Cannot create files in a deleted directory */ +@@ -510,8 +542,19 @@ repeat: + inode->i_generation = sb->u.ext3_sb.s_next_generation++; + + inode->u.ext3_i.i_state = EXT3_STATE_NEW; +- err = ext3_mark_inode_dirty(handle, inode); +- if (err) goto fail; ++ err = ext3_get_inode_loc_new(inode, &iloc, 1); ++ if (err) goto fail; ++ BUFFER_TRACE(iloc->bh, "get_write_access"); ++ err = ext3_journal_get_write_access(handle, iloc.bh); ++ if (err) { ++ brelse(iloc.bh); ++ iloc.bh = NULL; ++ goto fail; ++ } ++ err = ext3_mark_iloc_dirty(handle, inode, &iloc); ++ if (err) goto fail; ++ ++ + + #ifdef CONFIG_EXT3_FS_XATTR + init_rwsem(&inode->u.ext3_i.xattr_sem); +--- linux-2.4.20/fs/ext3/inode.c~ext3-noread-2.4.20 2003-05-16 12:21:41.000000000 +0800 ++++ linux-2.4.20-root/fs/ext3/inode.c 2003-05-16 12:22:15.000000000 +0800 +@@ -2013,14 +2013,19 @@ out_stop: + ext3_journal_stop(handle, inode); + } + +-/* +- * ext3_get_inode_loc returns with an extra refcount against the +- * inode's underlying buffer_head on success. +- */ +- +-int ext3_get_inode_loc (struct inode *inode, struct ext3_iloc *iloc) ++#define NUM_INODE_PREREAD 16 ++ ++/* ++ * ext3_get_inode_loc returns with an extra refcount against the inode's ++ * underlying buffer_head on success. If this is for a new inode allocation ++ * (new is non-zero) then we may be able to optimize away the read if there ++ * are no other in-use inodes in this inode table block. If we need to do ++ * a read, then read in a whole chunk of blocks to avoid blocking again soon ++ * if we are doing lots of creates/updates. ++ */ ++int ext3_get_inode_loc_new(struct inode *inode, struct ext3_iloc *iloc, int new) + { +- struct buffer_head *bh = 0; ++ struct buffer_head *bh[NUM_INODE_PREREAD]; + unsigned long block; + unsigned long block_group; + unsigned long group_desc; +@@ -2045,31 +2050,73 @@ int ext3_get_inode_loc (struct inode *in + } + group_desc = block_group >> EXT3_DESC_PER_BLOCK_BITS(inode->i_sb); + desc = block_group & (EXT3_DESC_PER_BLOCK(inode->i_sb) - 1); +- bh = inode->i_sb->u.ext3_sb.s_group_desc[group_desc]; +- if (!bh) { ++ if (!(inode->i_sb->u.ext3_sb.s_group_desc[group_desc])) { + ext3_error (inode->i_sb, "ext3_get_inode_loc", + "Descriptor not loaded"); + goto bad_inode; + } + +- gdp = (struct ext3_group_desc *) bh->b_data; ++ gdp = (struct ext3_group_desc *)(inode->i_sb->u.ext3_sb.s_group_desc[group_desc]->b_data); + /* + * Figure out the offset within the block group inode table + */ +- offset = ((inode->i_ino - 1) % EXT3_INODES_PER_GROUP(inode->i_sb)) * +- EXT3_INODE_SIZE(inode->i_sb); ++ offset = ((inode->i_ino - 1) % EXT3_INODES_PER_GROUP(inode->i_sb)); ++ + block = le32_to_cpu(gdp[desc].bg_inode_table) + +- (offset >> EXT3_BLOCK_SIZE_BITS(inode->i_sb)); +- if (!(bh = sb_bread(inode->i_sb, block))) { +- ext3_error (inode->i_sb, "ext3_get_inode_loc", +- "unable to read inode block - " +- "inode=%lu, block=%lu", inode->i_ino, block); +- goto bad_inode; +- } +- offset &= (EXT3_BLOCK_SIZE(inode->i_sb) - 1); ++ (offset * EXT3_INODE_SIZE(inode->i_sb) >> EXT3_BLOCK_SIZE_BITS(inode->i_sb)); + +- iloc->bh = bh; +- iloc->raw_inode = (struct ext3_inode *) (bh->b_data + offset); ++ bh[0] = sb_getblk(inode->i_sb, block); ++ if (buffer_uptodate(bh[0])) ++ goto done; ++ ++ /* If we don't really need to read this block, and it isn't already ++ * in memory, then we just zero it out. Otherwise, we keep the ++ * current block contents (deleted inode data) for posterity. ++ */ ++ if (new && !ext3_itable_block_used(inode->i_sb, block_group, offset)) { ++ lock_buffer(bh[0]); ++ memset(bh[0]->b_data, 0, bh[0]->b_size); ++ mark_buffer_uptodate(bh[0], 1); ++ unlock_buffer(bh[0]); ++ } else { ++ unsigned long block_end, itable_end; ++ int count = 1; ++ ++ itable_end = le32_to_cpu(gdp[desc].bg_inode_table) + ++ inode->i_sb->u.ext3_sb.s_itb_per_group; ++ block_end = block + NUM_INODE_PREREAD; ++ if (block_end > itable_end) ++ block_end = itable_end; ++ ++ for (++block; block < block_end; block++) { ++ bh[count] = sb_getblk(inode->i_sb, block); ++ if (count && (buffer_uptodate(bh[count]) || ++ buffer_locked(bh[count]))) { ++ __brelse(bh[count]); ++ } else ++ count++; ++ } ++ ++ ll_rw_block(READ, count, bh); ++ ++ /* Release all but the block we actually need (bh[0]) */ ++ while (--count > 0) ++ __brelse(bh[count]); ++ ++ wait_on_buffer(bh[0]); ++ if (!buffer_uptodate(bh[0])) { ++ ext3_error(inode->i_sb, __FUNCTION__, ++ "unable to read inode block - " ++ "inode=%lu, block=%lu", inode->i_ino, ++ bh[0]->b_blocknr); ++ goto bad_inode; ++ } ++ } ++ done: ++ offset = (offset * EXT3_INODE_SIZE(inode->i_sb)) & (EXT3_BLOCK_SIZE(inode->i_sb) - 1); ++ ++ iloc->bh = bh[0]; ++ iloc->raw_inode = (struct ext3_inode *)(bh[0]->b_data + offset); + iloc->block_group = block_group; + + return 0; +@@ -2078,6 +2125,11 @@ int ext3_get_inode_loc (struct inode *in + return -EIO; + } + ++int ext3_get_inode_loc(struct inode *inode, struct ext3_iloc *iloc) ++{ ++ return ext3_get_inode_loc_new(inode, iloc, 0); ++} ++ + void ext3_read_inode(struct inode * inode) + { + struct ext3_iloc iloc; +--- linux-2.4.20/include/linux/ext3_fs.h~ext3-noread-2.4.20 2003-05-16 12:21:39.000000000 +0800 ++++ linux-2.4.20-root/include/linux/ext3_fs.h 2003-05-16 12:21:46.000000000 +0800 +@@ -683,6 +683,8 @@ extern int ext3_forget(handle_t *, int, + extern struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *); + extern struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *); + ++extern int ext3_itable_block_used(struct super_block *sb, unsigned int, int); ++extern int ext3_get_inode_loc_new(struct inode *, struct ext3_iloc *, int); + extern int ext3_get_inode_loc (struct inode *, struct ext3_iloc *); + extern void ext3_read_inode (struct inode *); + extern void ext3_write_inode (struct inode *, int); + +_ diff --git a/lustre/kernel_patches/patches/extN-wantedi-2.4.21-suse2.patch b/lustre/kernel_patches/patches/extN-wantedi-2.4.21-suse2.patch new file mode 100644 index 0000000..400f7a8 --- /dev/null +++ b/lustre/kernel_patches/patches/extN-wantedi-2.4.21-suse2.patch @@ -0,0 +1,226 @@ + fs/ext3/ialloc.c | 40 ++++++++++++++++++++++++++++++++++++++-- + fs/ext3/inode.c | 2 +- + fs/ext3/ioctl.c | 25 +++++++++++++++++++++++++ + fs/ext3/namei.c | 21 +++++++++++++++++---- + include/linux/dcache.h | 5 +++++ + include/linux/ext3_fs.h | 5 ++++- + 6 files changed, 90 insertions(+), 8 deletions(-) + +Index: linux-2.4.21-chaos/fs/ext3/namei.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/ext3/namei.c 2003-12-12 16:18:41.000000000 +0300 ++++ linux-2.4.21-chaos/fs/ext3/namei.c 2003-12-12 16:18:53.000000000 +0300 +@@ -1534,6 +1534,19 @@ + return err; + } + ++static struct inode * ext3_new_inode_wantedi(handle_t *handle, struct inode *dir, ++ int mode, struct dentry *dentry) ++{ ++ unsigned long inum = 0; ++ ++ if (dentry->d_fsdata != NULL) { ++ struct dentry_params *param = ++ (struct dentry_params *) dentry->d_fsdata; ++ inum = param->p_inum; ++ } ++ return ext3_new_inode(handle, dir, mode, inum); ++} ++ + /* + * By the time this is called, we already have created + * the directory cache entry for the new file, but it +@@ -1557,7 +1570,7 @@ + if (IS_SYNC(dir)) + handle->h_sync = 1; + +- inode = ext3_new_inode (handle, dir, mode); ++ inode = ext3_new_inode_wantedi (handle, dir, mode, dentry); + err = PTR_ERR(inode); + if (!IS_ERR(inode)) { + inode->i_op = &ext3_file_inode_operations; +@@ -1585,7 +1598,7 @@ + if (IS_SYNC(dir)) + handle->h_sync = 1; + +- inode = ext3_new_inode (handle, dir, mode); ++ inode = ext3_new_inode_wantedi (handle, dir, mode, dentry); + err = PTR_ERR(inode); + if (!IS_ERR(inode)) { + init_special_inode(inode, inode->i_mode, rdev); +@@ -1618,7 +1631,7 @@ + if (IS_SYNC(dir)) + handle->h_sync = 1; + +- inode = ext3_new_inode (handle, dir, S_IFDIR | mode); ++ inode = ext3_new_inode_wantedi (handle, dir, S_IFDIR | mode, dentry); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out_stop; +@@ -2012,7 +2025,7 @@ + if (IS_SYNC(dir)) + handle->h_sync = 1; + +- inode = ext3_new_inode (handle, dir, S_IFLNK|S_IRWXUGO); ++ inode = ext3_new_inode_wantedi (handle, dir, S_IFLNK|S_IRWXUGO, dentry); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out_stop; +Index: linux-2.4.21-chaos/fs/ext3/ialloc.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/ext3/ialloc.c 2003-12-12 16:18:52.000000000 +0300 ++++ linux-2.4.21-chaos/fs/ext3/ialloc.c 2003-12-12 16:18:53.000000000 +0300 +@@ -330,7 +330,8 @@ + * For other inodes, search forward from the parent directory's block + * group to find a free inode. + */ +-struct inode * ext3_new_inode (handle_t *handle, struct inode * dir, int mode) ++struct inode * ext3_new_inode(handle_t *handle, const struct inode * dir, ++ int mode, unsigned long goal) + { + struct super_block * sb; + struct buffer_head * bh; +@@ -359,7 +360,41 @@ + init_rwsem(&ei->truncate_sem); + + lock_super (sb); +- es = sb->u.ext3_sb.s_es; ++ es = EXT3_SB(sb)->s_es; ++ ++ if (goal) { ++ i = (goal - 1) / EXT3_INODES_PER_GROUP(sb); ++ j = (goal - 1) % EXT3_INODES_PER_GROUP(sb); ++ gdp = ext3_get_group_desc(sb, i, &bh2); ++ ++ bitmap_nr = load_inode_bitmap (sb, i); ++ if (bitmap_nr < 0) { ++ err = bitmap_nr; ++ goto fail; ++ } ++ ++ bh = EXT3_SB(sb)->s_inode_bitmap[bitmap_nr]; ++ ++ BUFFER_TRACE(bh, "get_write_access"); ++ err = ext3_journal_get_write_access(handle, bh); ++ if (err) goto fail; ++ ++ if (ext3_set_bit(j, bh->b_data)) { ++ printk(KERN_ERR "goal inode %lu unavailable\n", goal); ++ /* Oh well, we tried. */ ++ goto repeat; ++ } ++ ++ BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); ++ err = ext3_journal_dirty_metadata(handle, bh); ++ if (err) goto fail; ++ ++ /* We've shortcircuited the allocation system successfully, ++ * now finish filling in the inode. ++ */ ++ goto have_bit_and_group; ++ } ++ + repeat: + gdp = NULL; + i = 0; +@@ -474,6 +509,7 @@ + } + goto repeat; + } ++ have_bit_and_group: + j += i * EXT3_INODES_PER_GROUP(sb) + 1; + if (j < EXT3_FIRST_INO(sb) || j > le32_to_cpu(es->s_inodes_count)) { + ext3_error (sb, "ext3_new_inode", +Index: linux-2.4.21-chaos/fs/ext3/inode.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/ext3/inode.c 2003-12-12 16:18:52.000000000 +0300 ++++ linux-2.4.21-chaos/fs/ext3/inode.c 2003-12-12 16:18:53.000000000 +0300 +@@ -2233,7 +2233,7 @@ + if (IS_ERR(handle)) + goto out_truncate; + +- new_inode = ext3_new_inode(handle, old_inode, old_inode->i_mode); ++ new_inode = ext3_new_inode(handle, old_inode, old_inode->i_mode, 0); + if (IS_ERR(new_inode)) { + ext3_debug("truncate inode %lu directly (no new inodes)\n", + old_inode->i_ino); +Index: linux-2.4.21-chaos/fs/ext3/ioctl.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/ext3/ioctl.c 2003-12-12 16:18:40.000000000 +0300 ++++ linux-2.4.21-chaos/fs/ext3/ioctl.c 2003-12-12 16:18:53.000000000 +0300 +@@ -24,6 +24,31 @@ + ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg); + + switch (cmd) { ++ case EXT3_IOC_CREATE_INUM: { ++ char name[32]; ++ struct dentry *dchild, *dparent; ++ int rc = 0; ++ ++ dparent = list_entry(inode->i_dentry.next, struct dentry, ++ d_alias); ++ snprintf(name, sizeof name, "%lu", arg); ++ dchild = lookup_one_len(name, dparent, strlen(name)); ++ if (dchild->d_inode) { ++ printk(KERN_ERR "%*s/%lu already exists (ino %lu)\n", ++ dparent->d_name.len, dparent->d_name.name, arg, ++ dchild->d_inode->i_ino); ++ rc = -EEXIST; ++ } else { ++ dchild->d_fsdata = (void *)arg; ++ rc = vfs_create(inode, dchild, 0644); ++ if (rc) ++ printk(KERN_ERR "vfs_create: %d\n", rc); ++ else if (dchild->d_inode->i_ino != arg) ++ rc = -EEXIST; ++ } ++ dput(dchild); ++ return rc; ++ } + case EXT3_IOC_GETFLAGS: + flags = ei->i_flags & EXT3_FL_USER_VISIBLE; + return put_user(flags, (int *) arg); +Index: linux-2.4.21-chaos/include/linux/ext3_fs.h +=================================================================== +--- linux-2.4.21-chaos.orig/include/linux/ext3_fs.h 2003-12-12 16:18:52.000000000 +0300 ++++ linux-2.4.21-chaos/include/linux/ext3_fs.h 2003-12-12 16:18:53.000000000 +0300 +@@ -204,6 +204,7 @@ + #define EXT3_IOC_SETFLAGS _IOW('f', 2, long) + #define EXT3_IOC_GETVERSION _IOR('f', 3, long) + #define EXT3_IOC_SETVERSION _IOW('f', 4, long) ++/* EXT3_IOC_CREATE_INUM at bottom of file (visible to kernel and user). */ + #define EXT3_IOC_GETVERSION_OLD _IOR('v', 1, long) + #define EXT3_IOC_SETVERSION_OLD _IOW('v', 2, long) + #ifdef CONFIG_JBD_DEBUG +@@ -671,7 +672,8 @@ + dx_hash_info *hinfo); + + /* ialloc.c */ +-extern struct inode * ext3_new_inode (handle_t *, struct inode *, int); ++extern struct inode * ext3_new_inode (handle_t *, const struct inode *, int, ++ unsigned long); + extern void ext3_free_inode (handle_t *, struct inode *); + extern struct inode * ext3_orphan_get (struct super_block *, unsigned long); + extern unsigned long ext3_count_free_inodes (struct super_block *); +@@ -763,4 +765,5 @@ + + #endif /* __KERNEL__ */ + ++#define EXT3_IOC_CREATE_INUM _IOW('f', 5, long) + #endif /* _LINUX_EXT3_FS_H */ +Index: linux-2.4.21-chaos/include/linux/dcache.h +=================================================================== +--- linux-2.4.21-chaos.orig/include/linux/dcache.h 2003-12-12 16:18:06.000000000 +0300 ++++ linux-2.4.21-chaos/include/linux/dcache.h 2003-12-12 16:18:53.000000000 +0300 +@@ -63,6 +63,11 @@ + + #define IS_ROOT(x) ((x) == (x)->d_parent) + ++struct dentry_params { ++ unsigned long p_inum; ++ void *p_ptr; ++}; ++ + /* + * "quick string" -- eases parameter passing, but more importantly + * saves "metadata" about the string (ie length and the hash). diff --git a/lustre/kernel_patches/patches/linux-2.4.21-xattr-0.8.54-suse2.patch b/lustre/kernel_patches/patches/linux-2.4.21-xattr-0.8.54-suse2.patch new file mode 100644 index 0000000..0a8891f --- /dev/null +++ b/lustre/kernel_patches/patches/linux-2.4.21-xattr-0.8.54-suse2.patch @@ -0,0 +1,258 @@ + Documentation/Configure.help | 66 ++ + arch/alpha/defconfig | 7 + arch/alpha/kernel/entry.S | 12 + arch/arm/defconfig | 7 + arch/arm/kernel/calls.S | 24 + arch/i386/defconfig | 7 + arch/ia64/defconfig | 7 + arch/ia64/kernel/entry.S | 24 + arch/m68k/defconfig | 7 + arch/mips/defconfig | 7 + arch/mips64/defconfig | 7 + arch/ppc/defconfig | 14 + arch/ppc64/kernel/misc.S | 2 + arch/s390/defconfig | 7 + arch/s390/kernel/entry.S | 24 + arch/s390x/defconfig | 7 + arch/s390x/kernel/entry.S | 24 + arch/s390x/kernel/wrapper32.S | 92 +++ + arch/sparc/defconfig | 7 + arch/sparc/kernel/systbls.S | 10 + arch/sparc64/defconfig | 7 + arch/sparc64/kernel/systbls.S | 20 + fs/Config.in | 14 + fs/Makefile | 3 + fs/ext2/Makefile | 4 + fs/ext2/file.c | 5 + fs/ext2/ialloc.c | 2 + fs/ext2/inode.c | 34 - + fs/ext2/namei.c | 14 + fs/ext2/super.c | 29 + fs/ext2/symlink.c | 14 + fs/ext2/xattr.c | 1212 +++++++++++++++++++++++++++++++++++++++++ + fs/ext2/xattr_user.c | 103 +++ + fs/ext3/Makefile | 10 + fs/ext3/file.c | 5 + fs/ext3/ialloc.c | 2 + fs/ext3/inode.c | 35 - + fs/ext3/namei.c | 21 + fs/ext3/super.c | 36 + + fs/ext3/symlink.c | 14 + fs/ext3/xattr.c | 1225 ++++++++++++++++++++++++++++++++++++++++++ + fs/ext3/xattr_user.c | 111 +++ + fs/jfs/jfs_xattr.h | 6 + fs/jfs/xattr.c | 6 + fs/mbcache.c | 648 ++++++++++++++++++++++ + include/asm-arm/unistd.h | 2 + include/asm-ia64/unistd.h | 13 + include/asm-ppc64/unistd.h | 2 + include/asm-s390/unistd.h | 15 + include/asm-s390x/unistd.h | 15 + include/asm-sparc/unistd.h | 24 + include/asm-sparc64/unistd.h | 24 + include/linux/cache_def.h | 15 + include/linux/errno.h | 4 + include/linux/ext2_fs.h | 31 - + include/linux/ext2_xattr.h | 157 +++++ + include/linux/ext3_fs.h | 31 - + include/linux/ext3_jbd.h | 8 + include/linux/ext3_xattr.h | 157 +++++ + include/linux/fs.h | 2 + include/linux/mbcache.h | 69 ++ + kernel/ksyms.c | 4 + mm/vmscan.c | 35 + + fs/ext3/ext3-exports.c | 14 + + 64 files changed, 4355 insertions(+), 195 deletions(-) + +Index: linux-2.4.21-chaos/Documentation/Configure.help +=================================================================== +--- linux-2.4.21-chaos.orig/Documentation/Configure.help 2003-10-04 01:18:57.000000000 +0400 ++++ linux-2.4.21-chaos/Documentation/Configure.help 2003-12-14 15:11:46.000000000 +0300 +@@ -16008,6 +16041,39 @@ + + If unsure, say N. + ++Ext3 extended attributes ++CONFIG_EXT3_FS_XATTR ++ Extended attributes are name:value pairs associated with inodes by ++ the kernel or by users (see the attr(5) manual page, or visit ++ for details). ++ ++ If unsure, say N. ++ ++Ext3 extended attribute block sharing ++CONFIG_EXT3_FS_XATTR_SHARING ++ This options enables code for sharing identical extended attribute ++ blocks among multiple inodes. ++ ++ Usually, say Y. ++ ++Ext3 extended user attributes ++CONFIG_EXT3_FS_XATTR_USER ++ This option enables extended user attributes on ext3. Processes can ++ associate extended user attributes with inodes to store additional ++ information such as the character encoding of files, etc. (see the ++ attr(5) manual page, or visit for details). ++ ++ If unsure, say N. ++ ++Ext3 trusted extended attributes ++CONFIG_EXT3_FS_XATTR_TRUSTED ++ This option enables extended attributes on ext3 that are accessible ++ (and visible) only to users capable of CAP_SYS_ADMIN. Usually this ++ is only the super user. Trusted extended attributes are meant for ++ implementing system/security services. ++ ++ If unsure, say N. ++ + Journal Block Device support (JBD for ext3) (EXPERIMENTAL) + CONFIG_JBD + This is a generic journalling layer for block devices. It is +Index: linux-2.4.21-chaos/fs/ext3/Makefile +=================================================================== +--- linux-2.4.21-chaos.orig/fs/ext3/Makefile 2003-12-14 15:09:30.000000000 +0300 ++++ linux-2.4.21-chaos/fs/ext3/Makefile 2003-12-14 15:11:46.000000000 +0300 +@@ -9,10 +9,10 @@ + + O_TARGET := ext3.o + +-export-objs := super.o inode.o ++export-objs := ext3-exports.o + + obj-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ +- ioctl.o namei.o super.o symlink.o hash.o ++ ioctl.o namei.o super.o symlink.o hash.o ext3-exports.o + obj-m := $(O_TARGET) + + export-objs += xattr.o +Index: linux-2.4.21-chaos/fs/ext3/super.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/ext3/super.c 2003-12-14 15:09:30.000000000 +0300 ++++ linux-2.4.21-chaos/fs/ext3/super.c 2003-12-14 15:11:46.000000000 +0300 +@@ -1944,9 +1944,6 @@ + unregister_filesystem(&ext3_fs_type); + } + +-EXPORT_SYMBOL(ext3_force_commit); +-EXPORT_SYMBOL(ext3_bread); +- + MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); + MODULE_DESCRIPTION("Second Extended Filesystem with journaling extensions"); + MODULE_LICENSE("GPL"); +Index: linux-2.4.21-chaos/fs/ext3/ext3-exports.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/ext3/ext3-exports.c 2003-01-30 13:24:37.000000000 +0300 ++++ linux-2.4.21-chaos/fs/ext3/ext3-exports.c 2003-12-14 15:11:46.000000000 +0300 +@@ -0,0 +1,14 @@ ++#include ++#include ++#include ++#include ++#include ++ ++EXPORT_SYMBOL(ext3_force_commit); ++EXPORT_SYMBOL(ext3_bread); ++EXPORT_SYMBOL(ext3_journal_abort_handle); ++EXPORT_SYMBOL(ext3_xattr_register); ++EXPORT_SYMBOL(ext3_xattr_unregister); ++EXPORT_SYMBOL(ext3_xattr_get); ++EXPORT_SYMBOL(ext3_xattr_list); ++EXPORT_SYMBOL(ext3_xattr_set); +Index: linux-2.4.21-chaos/fs/ext3/xattr_trusted.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/ext3/xattr_trusted.c 2003-07-15 04:41:01.000000000 +0400 ++++ linux-2.4.21-chaos/fs/ext3/xattr_trusted.c 2003-12-14 15:11:46.000000000 +0300 +@@ -50,7 +50,7 @@ + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; +- return ext3_xattr_set(inode, EXT3_XATTR_INDEX_TRUSTED, name, ++ return ext3_xattr_set_trans(inode, EXT3_XATTR_INDEX_TRUSTED, name, + value, size, flags); + } + +Index: linux-2.4.21-chaos/fs/ext3/xattr.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/ext3/xattr.c 2003-07-30 04:11:55.000000000 +0400 ++++ linux-2.4.21-chaos/fs/ext3/xattr.c 2003-12-14 15:11:46.000000000 +0300 +@@ -868,7 +868,7 @@ + } + + /* +- * ext3_xattr_set() ++ * ext3_xattr_set_trans() + * + * Like ext3_xattr_set_handle, but start from an inode. This extended + * attribute modification is a filesystem transaction by itself. +@@ -876,7 +876,7 @@ + * Returns 0, or a negative error number on failure. + */ + int +-ext3_xattr_set(struct inode *inode, int name_index, const char *name, ++ext3_xattr_set_trans(struct inode *inode, int name_index, const char *name, + const void *value, size_t value_len, int flags) + { + handle_t *handle; +@@ -895,6 +895,20 @@ + return error ? error : error2; + } + ++int ++ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index, ++ const char *name, const void *value, size_t value_len, ++ int flags) ++{ ++ int error; ++ ++ lock_kernel(); ++ error = ext3_xattr_set_handle(handle, inode, name_index, name, ++ value, value_len, flags); ++ unlock_kernel(); ++ return error; ++} ++ + /* + * ext3_xattr_delete_inode() + * +Index: linux-2.4.21-chaos/fs/ext3/xattr_user.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/ext3/xattr_user.c 2003-07-30 04:11:55.000000000 +0400 ++++ linux-2.4.21-chaos/fs/ext3/xattr_user.c 2003-12-14 15:26:58.000000000 +0300 +@@ -70,7 +70,7 @@ + if (error) + return error; + +- return ext3_xattr_set(inode, EXT3_XATTR_INDEX_USER, name, ++ return ext3_xattr_set_trans(inode, EXT3_XATTR_INDEX_USER, name, + value, size, flags); + } + +Index: linux-2.4.21-chaos/include/linux/errno.h +=================================================================== +--- linux-2.4.21-chaos.orig/include/linux/errno.h 2003-07-15 04:41:12.000000000 +0400 ++++ linux-2.4.21-chaos/include/linux/errno.h 2003-12-14 15:11:46.000000000 +0300 +@@ -26,4 +26,8 @@ + + #endif + ++/* Defined for extended attributes */ ++#define ENOATTR ENODATA /* No such attribute */ ++#define ENOTSUP EOPNOTSUPP /* Operation not supported */ ++ + #endif +Index: linux-2.4.21-chaos/include/linux/ext3_xattr.h +=================================================================== +--- linux-2.4.21-chaos.orig/include/linux/ext3_xattr.h 2003-12-05 16:54:33.000000000 +0300 ++++ linux-2.4.21-chaos/include/linux/ext3_xattr.h 2003-12-14 15:21:13.000000000 +0300 +@@ -82,8 +82,10 @@ + extern int ext3_xattr_list(struct inode *, char *, size_t); + extern int ext3_xattr_set_handle(handle_t *handle, struct inode *, int, + const char *, const void *, size_t, int); +-extern int ext3_xattr_set(struct inode *, int, const char *, const void *, ++extern int ext3_xattr_set_trans(struct inode *, int, const char *, const void *, + size_t, int); ++extern int ext3_xattr_set(handle_t *, struct inode *, int, const char *, ++ const void *, size_t, int); + + extern void ext3_xattr_delete_inode(handle_t *, struct inode *); + extern void ext3_xattr_put_super(struct super_block *); diff --git a/lustre/kernel_patches/patches/nfs_export_kernel-2.4.21-suse2.patch b/lustre/kernel_patches/patches/nfs_export_kernel-2.4.21-suse2.patch new file mode 100644 index 0000000..c1ed0f3 --- /dev/null +++ b/lustre/kernel_patches/patches/nfs_export_kernel-2.4.21-suse2.patch @@ -0,0 +1,746 @@ + fs/Makefile | 3 + fs/file_table.c | 11 ++ + fs/inode.c | 23 ++++- + fs/namei.c | 12 ++ + fs/nfsd/export.c | 5 + + fs/nfsd/nfsfh.c | 65 +++++++++++++- + fs/nfsd/vfs.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++++----- + include/linux/fs.h | 11 ++ + kernel/ksyms.c | 2 + 9 files changed, 333 insertions(+), 34 deletions(-) + +Index: linux-2.4.21-chaos/fs/file_table.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/file_table.c 2003-07-15 04:41:00.000000000 +0400 ++++ linux-2.4.21-chaos/fs/file_table.c 2003-12-12 16:19:25.000000000 +0300 +@@ -82,7 +82,8 @@ + * and call the open function (if any). The caller must verify that + * inode->i_fop is not NULL. + */ +-int init_private_file(struct file *filp, struct dentry *dentry, int mode) ++int init_private_file_it(struct file *filp, struct dentry *dentry, int mode, ++ struct lookup_intent *it) + { + memset(filp, 0, sizeof(*filp)); + filp->f_mode = mode; +@@ -90,12 +91,20 @@ + filp->f_dentry = dentry; + filp->f_uid = current->fsuid; + filp->f_gid = current->fsgid; ++ if (it) ++ filp->f_it = it; + filp->f_op = dentry->d_inode->i_fop; + if (filp->f_op->open) + return filp->f_op->open(dentry->d_inode, filp); + else + return 0; + } ++EXPORT_SYMBOL(init_private_file_it); ++ ++int init_private_file(struct file *filp, struct dentry *dentry, int mode) ++{ ++ return init_private_file_it(filp, dentry, mode, NULL); ++} + + void fput(struct file * file) + { +Index: linux-2.4.21-chaos/fs/inode.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/inode.c 2003-12-12 16:18:15.000000000 +0300 ++++ linux-2.4.21-chaos/fs/inode.c 2003-12-12 16:19:25.000000000 +0300 +@@ -1054,9 +1054,10 @@ + return inode; + } + +-struct inode *iget4_locked(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque) ++struct inode *ifind(struct super_block *sb, unsigned long ino, ++ struct list_head *head, ++ find_inode_t find_actor, void *opaque) + { +- struct list_head * head = inode_hashtable + hash(sb,ino); + struct inode * inode; + + spin_lock(&inode_lock); +@@ -1069,6 +1070,24 @@ + } + spin_unlock(&inode_lock); + ++ return NULL; ++} ++ ++struct inode *ilookup4(struct super_block *sb, unsigned long ino, ++ find_inode_t find_actor, void *opaque) ++{ ++ struct list_head * head = inode_hashtable + hash(sb,ino); ++ return ifind(sb, ino, head, find_actor, opaque); ++} ++ ++struct inode *iget4_locked(struct super_block *sb, unsigned long ino, ++ find_inode_t find_actor, void *opaque) ++{ ++ struct list_head * head = inode_hashtable + hash(sb,ino); ++ struct inode *inode = ifind(sb, ino, head, find_actor, opaque); ++ if (inode) ++ return inode; ++ + /* + * get_new_inode() will do the right thing, re-trying the search + * in case it had to block at any point. +Index: linux-2.4.21-chaos/fs/Makefile +=================================================================== +--- linux-2.4.21-chaos.orig/fs/Makefile 2003-12-12 16:18:36.000000000 +0300 ++++ linux-2.4.21-chaos/fs/Makefile 2003-12-12 16:19:25.000000000 +0300 +@@ -9,7 +9,8 @@ + + O_TARGET := fs.o + +-export-objs := filesystems.o open.o dcache.o buffer.o dquot.o inode.o ++export-objs := filesystems.o open.o dcache.o buffer.o dquot.o inode.o \ ++ namei.o file_table.o + mod-subdirs := nls xfs + + obj-y := open.o read_write.o devices.o file_table.o buffer.o \ +Index: linux-2.4.21-chaos/fs/namei.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/namei.c 2003-12-12 16:18:06.000000000 +0300 ++++ linux-2.4.21-chaos/fs/namei.c 2003-12-12 16:19:25.000000000 +0300 +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -100,6 +101,7 @@ + it->it_op_release(it); + + } ++EXPORT_SYMBOL(intent_release); + + /* In order to reduce some races, while at the same time doing additional + * checking and hopefully speeding things up, we copy filenames to the +@@ -910,7 +912,8 @@ + + + /* SMP-safe */ +-struct dentry * lookup_one_len(const char * name, struct dentry * base, int len) ++struct dentry * lookup_one_len_it(const char * name, struct dentry * base, ++ int len, struct lookup_intent *it) + { + unsigned long hash; + struct qstr this; +@@ -930,11 +933,16 @@ + } + this.hash = end_name_hash(hash); + +- return lookup_hash_it(&this, base, NULL); ++ return lookup_hash_it(&this, base, it); + access: + return ERR_PTR(-EACCES); + } + ++struct dentry * lookup_one_len(const char * name, struct dentry * base, int len) ++{ ++ return lookup_one_len_it(name, base, len, NULL); ++} ++ + /* + * namei() + * +Index: linux-2.4.21-chaos/fs/nfsd/export.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/nfsd/export.c 2003-09-19 03:49:54.000000000 +0400 ++++ linux-2.4.21-chaos/fs/nfsd/export.c 2003-12-12 16:19:25.000000000 +0300 +@@ -223,6 +223,11 @@ + inode = nd.dentry->d_inode; + dev = inode->i_dev; + ino = inode->i_ino; ++ if ((inode->i_sb->s_type->fs_flags & FS_NFSEXP_FSID) && ++ !(nxp->ex_flags & NFSEXP_FSID)) { ++ nxp->ex_dev = inode->i_sb->s_dev; ++ nxp->ex_flags |= NFSEXP_FSID; ++ } + err = -EINVAL; + + exp = exp_get(clp, dev, ino); +Index: linux-2.4.21-chaos/fs/nfsd/nfsfh.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/nfsd/nfsfh.c 2003-09-19 03:49:54.000000000 +0400 ++++ linux-2.4.21-chaos/fs/nfsd/nfsfh.c 2003-12-12 16:19:25.000000000 +0300 +@@ -36,6 +36,15 @@ + int sequence; /* sequence counter */ + }; + ++static struct dentry *lookup_it(struct inode *inode, struct dentry * dentry) ++{ ++ if (inode->i_op->lookup_it) ++ return inode->i_op->lookup_it(inode, dentry, NULL, 0); ++ else ++ return inode->i_op->lookup(inode, dentry); ++ ++} ++ + /* + * A rather strange filldir function to capture + * the name matching the specified inode number. +@@ -75,6 +84,8 @@ + int error; + struct file file; + struct nfsd_getdents_callback buffer; ++ struct lookup_intent it; ++ struct file *filp = NULL; + + error = -ENOTDIR; + if (!dir || !S_ISDIR(dir->i_mode)) +@@ -85,9 +96,37 @@ + /* + * Open the directory ... + */ +- error = init_private_file(&file, dentry, FMODE_READ); +- if (error) ++ if (dentry->d_op && dentry->d_op->d_revalidate_it) { ++ if ((dentry->d_flags & DCACHE_NFSD_DISCONNECTED) && ++ (dentry->d_parent == dentry) ) { ++ it.it_op_release = NULL; ++ /* ++ * XXX Temporary Hack: Simulating init_private_file without ++ * f_op->open for disconnected dentry Since we don't have actual ++ * dentry->d_name to revalidate in revalidate_it() ++ */ ++ filp = &file; ++ memset(filp, 0, sizeof(*filp)); ++ filp->f_mode = FMODE_READ; ++ atomic_set(&filp->f_count, 1); ++ filp->f_dentry = dentry; ++ filp->f_uid = current->fsuid; ++ filp->f_gid = current->fsgid; ++ filp->f_op = dentry->d_inode->i_fop; ++ error = 0; ++ } else { ++ intent_init(&it, IT_OPEN, 0); ++ error = revalidate_it(dentry, &it); ++ if (error) ++ goto out; ++ error = init_private_file_it(&file, dentry, FMODE_READ, &it); ++ } ++ } else { ++ error = init_private_file_it(&file, dentry, FMODE_READ, NULL); ++ } ++ if (error) + goto out; ++ + error = -EINVAL; + if (!file.f_op->readdir) + goto out_close; +@@ -113,9 +152,13 @@ + } + + out_close: +- if (file.f_op->release) ++ if (file.f_op->release && !filp) + file.f_op->release(dir, &file); + out: ++ if (dentry->d_op && ++ dentry->d_op->d_revalidate_it && ++ it.it_op_release && !filp) ++ intent_release(&it); + return error; + } + +@@ -274,7 +317,7 @@ + * it is well connected. But nobody returns different dentrys do they? + */ + down(&child->d_inode->i_sem); +- pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry); ++ pdentry = lookup_it(child->d_inode, tdentry); + up(&child->d_inode->i_sem); + d_drop(tdentry); /* we never want ".." hashed */ + if (!pdentry && tdentry->d_inode == NULL) { +@@ -307,6 +350,8 @@ + pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED; + pdentry->d_op = child->d_op; + } ++ if (child->d_op && child->d_op->d_revalidate_it) ++ pdentry->d_op = child->d_op; + } + if (pdentry == NULL) + pdentry = ERR_PTR(-ENOMEM); +@@ -464,6 +509,8 @@ + struct dentry *pdentry; + struct inode *parent; + ++ if (result->d_op && result->d_op->d_revalidate_it) ++ dentry->d_op = result->d_op; + pdentry = nfsd_findparent(dentry); + err = PTR_ERR(pdentry); + if (IS_ERR(pdentry)) +@@ -672,6 +719,11 @@ + + inode = dentry->d_inode; + ++ /* cache coherency for non-device filesystems */ ++ if (inode->i_op && inode->i_op->revalidate_it) { ++ inode->i_op->revalidate_it(dentry, NULL); ++ } ++ + /* Type check. The correct error return for type mismatches + * does not seem to be generally agreed upon. SunOS seems to + * use EISDIR if file isn't S_IFREG; a comment in the NFSv3 +@@ -905,8 +957,9 @@ + dentry->d_parent->d_name.name, dentry->d_name.name); + goto out; + out_uptodate: +- printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n", +- dentry->d_parent->d_name.name, dentry->d_name.name); ++ if(!dentry->d_parent->d_inode->i_op->mkdir_raw) ++ printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n", ++ dentry->d_parent->d_name.name, dentry->d_name.name); + goto out; + } + +Index: linux-2.4.21-chaos/fs/nfsd/vfs.c +=================================================================== +--- linux-2.4.21-chaos.orig/fs/nfsd/vfs.c 2003-09-19 03:49:54.000000000 +0400 ++++ linux-2.4.21-chaos/fs/nfsd/vfs.c 2003-12-12 16:19:25.000000000 +0300 +@@ -78,6 +78,128 @@ + static struct raparms * raparml; + static struct raparms * raparm_cache; + ++static int link_raw(struct dentry *dold, struct dentry *ddir, ++ struct dentry *dnew) ++{ ++ int err; ++ ++ struct nameidata old_nd = { .dentry = dold }; ++ struct nameidata nd = { .dentry = ddir, .last = dnew->d_name }; ++ struct inode_operations *op = nd.dentry->d_inode->i_op; ++ err = op->link_raw(&old_nd, &nd); ++ d_instantiate(dnew, dold->d_inode); ++ if(dold->d_inode->i_op && dold->d_inode->i_op->revalidate_it) ++ dold->d_inode->i_op->revalidate_it(dnew, NULL); ++ ++ return err; ++} ++ ++static int unlink_raw(struct dentry *dentry, char *fname, int flen, ++ struct dentry *rdentry) ++{ ++ int err; ++ struct qstr last = { .name = fname, .len = flen }; ++ struct nameidata nd = { .dentry = dentry, .last = last }; ++ struct inode_operations *op = nd.dentry->d_inode->i_op; ++ err = op->unlink_raw(&nd); ++ if (!err) ++ d_delete(rdentry); ++ ++ return err; ++} ++ ++static int rmdir_raw(struct dentry *dentry, char *fname, int flen, ++ struct dentry *rdentry) ++{ ++ int err; ++ struct qstr last = { .name = fname, .len = flen }; ++ struct nameidata nd = { .dentry = dentry, .last = last }; ++ struct inode_operations *op = nd.dentry->d_inode->i_op; ++ err = op->rmdir_raw(&nd); ++ if(!err) { ++ rdentry->d_inode->i_flags |= S_DEAD; ++ d_delete(rdentry); ++ } ++ ++ return err; ++} ++ ++static int symlink_raw(struct dentry *dentry, char *fname, int flen, ++ char *path) ++{ ++ int err; ++ struct qstr last = { .name = fname, .len = flen }; ++ struct nameidata nd = { .dentry = dentry, .last = last }; ++ struct inode_operations *op = nd.dentry->d_inode->i_op; ++ err = op->symlink_raw(&nd, path); ++ ++ return err; ++} ++ ++static int mkdir_raw(struct dentry *dentry, char *fname, int flen, int mode) ++{ ++ int err; ++ struct qstr last = { .name = fname, .len = flen }; ++ struct nameidata nd = { .dentry = dentry, .last = last }; ++ struct inode_operations *op = nd.dentry->d_inode->i_op; ++ err = op->mkdir_raw(&nd, mode); ++ ++ return err; ++} ++ ++static int mknod_raw(struct dentry *dentry, char *fname, int flen, int mode, ++ dev_t dev) ++{ ++ int err; ++ struct qstr last = { .name = fname, .len = flen }; ++ struct nameidata nd = { .dentry = dentry, .last = last }; ++ struct inode_operations *op = nd.dentry->d_inode->i_op; ++ err = op->mknod_raw(&nd, mode, dev); ++ ++ return err; ++} ++ ++static int rename_raw(struct dentry *fdentry, struct dentry *tdentry, ++ struct dentry *odentry, struct dentry *ndentry) ++{ ++ int err; ++ ++ struct nameidata old_nd = { .dentry = fdentry, .last = odentry->d_name}; ++ struct nameidata new_nd = { .dentry = tdentry, .last = ndentry->d_name}; ++ struct inode_operations *op = old_nd.dentry->d_inode->i_op; ++ err = op->rename_raw(&old_nd, &new_nd); ++ d_move(odentry, ndentry); ++ ++ return err; ++} ++ ++static int setattr_raw(struct inode *inode, struct iattr *iap) ++{ ++ int err; ++ ++ iap->ia_valid |= ATTR_RAW; ++ err = inode->i_op->setattr_raw(inode, iap); ++ ++ return err; ++} ++ ++int revalidate_it(struct dentry *dentry, struct lookup_intent *it) ++{ ++ int err = 0; ++ ++ if (dentry && dentry->d_op && dentry->d_op->d_revalidate_it) { ++ if (!dentry->d_op->d_revalidate_it(dentry, 0, it) && ++ !d_invalidate(dentry)) { ++ dput(dentry); ++ err = -EINVAL; ++ dentry = NULL; ++ return err; ++ } ++ } ++ ++ return err; ++} ++ + /* + * Look up one component of a pathname. + * N.B. After this call _both_ fhp and resfh need an fh_put +@@ -303,7 +425,10 @@ + } + err = nfserr_notsync; + if (!check_guard || guardtime == inode->i_ctime) { +- err = notify_change(dentry, iap); ++ if ( dentry->d_inode->i_op && dentry->d_inode->i_op->setattr_raw) ++ err = setattr_raw(dentry->d_inode, iap); ++ else ++ err = notify_change(dentry, iap); + err = nfserrno(err); + } + if (size_change) { +@@ -430,6 +555,7 @@ + { + struct dentry *dentry; + struct inode *inode; ++ struct lookup_intent it; + int err; + + /* If we get here, then the client has already done an "open", and (hopefully) +@@ -476,6 +602,14 @@ + filp->f_mode = FMODE_READ; + } + ++ intent_init(&it, IT_OPEN, (filp->f_flags & ~O_ACCMODE) | filp->f_mode); ++ ++ err = revalidate_it(dentry, &it); ++ if (err) ++ goto out_nfserr; ++ ++ filp->f_it = ⁢ ++ + err = 0; + if (filp->f_op && filp->f_op->open) { + err = filp->f_op->open(inode, filp); +@@ -490,7 +624,11 @@ + atomic_dec(&filp->f_count); + } + } ++ + out_nfserr: ++ if (it.it_op_release) ++ intent_release(&it); ++ + if (err) + err = nfserrno(err); + out: +@@ -821,7 +959,7 @@ + { + struct dentry *dentry, *dchild; + struct inode *dirp; +- int err; ++ int err, error = -EOPNOTSUPP; + + err = nfserr_perm; + if (!flen) +@@ -837,20 +975,44 @@ + dentry = fhp->fh_dentry; + dirp = dentry->d_inode; + ++ switch (type) { ++ case S_IFDIR: ++ if (dirp->i_op->mkdir_raw) ++ error = mkdir_raw(dentry, fname, flen, iap->ia_mode); ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ case S_IFIFO: ++ case S_IFSOCK: ++ case S_IFREG: ++ if (dirp->i_op->mknod_raw) { ++ if (type == S_IFREG) ++ rdev = 0; ++ error = mknod_raw(dentry, fname, flen, iap->ia_mode, rdev); ++ } ++ break; ++ default: ++ printk("nfsd: bad file type %o in nfsd_create\n", type); ++ } ++ + err = nfserr_notdir; +- if(!dirp->i_op || !dirp->i_op->lookup) ++ if(!dirp->i_op || !(dirp->i_op->lookup || dirp->i_op->lookup_it)) + goto out; + /* + * Check whether the response file handle has been verified yet. + * If it has, the parent directory should already be locked. + */ +- if (!resfhp->fh_dentry) { +- /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */ +- fh_lock(fhp); ++ if (!resfhp->fh_dentry || dirp->i_op->lookup_it) { ++ /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create ++ and nfsd_proc_create in case of lustre ++ */ ++ if (!resfhp->fh_dentry) ++ fh_lock(fhp); + dchild = lookup_one_len(fname, dentry, flen); + err = PTR_ERR(dchild); + if (IS_ERR(dchild)) + goto out_nfserr; ++ resfhp->fh_dentry = NULL; + err = fh_compose(resfhp, fhp->fh_export, dchild, fhp); + if (err) + goto out; +@@ -871,10 +1033,12 @@ + * Make sure the child dentry is still negative ... + */ + err = nfserr_exist; +- if (dchild->d_inode) { +- dprintk("nfsd_create: dentry %s/%s not negative!\n", +- dentry->d_name.name, dchild->d_name.name); +- goto out; ++ if ( error == -EOPNOTSUPP) { ++ if (dchild->d_inode) { ++ dprintk("nfsd_create: dentry %s/%s not negative!\n", ++ dentry->d_name.name, dchild->d_name.name); ++ goto out; ++ } + } + + if (!(iap->ia_valid & ATTR_MODE)) +@@ -887,16 +1051,19 @@ + err = nfserr_perm; + switch (type) { + case S_IFREG: +- err = vfs_create(dirp, dchild, iap->ia_mode); ++ if (error == -EOPNOTSUPP) ++ err = vfs_create(dirp, dchild, iap->ia_mode); + break; + case S_IFDIR: +- err = vfs_mkdir(dirp, dchild, iap->ia_mode); ++ if (error == -EOPNOTSUPP) ++ err = vfs_mkdir(dirp, dchild, iap->ia_mode); + break; + case S_IFCHR: + case S_IFBLK: + case S_IFIFO: + case S_IFSOCK: +- err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); ++ if (error == -EOPNOTSUPP) ++ err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); + break; + default: + printk("nfsd: bad file type %o in nfsd_create\n", type); +@@ -965,7 +1132,13 @@ + /* Get all the sanity checks out of the way before + * we lock the parent. */ + err = nfserr_notdir; +- if(!dirp->i_op || !dirp->i_op->lookup) ++ if (dirp->i_op->mknod_raw) { ++ err = mknod_raw(dentry, fname, flen, iap->ia_mode, 0); ++ if (err && err != -EOPNOTSUPP) ++ goto out; ++ } ++ ++ if(!dirp->i_op || !(dirp->i_op->lookup || dirp->i_op->lookup_it)) + goto out; + fh_lock(fhp); + +@@ -1016,6 +1189,8 @@ + case NFS3_CREATE_GUARDED: + err = nfserr_exist; + } ++ if(dirp->i_op->mknod_raw) ++ err = 0; + goto out; + } + +@@ -1122,7 +1297,7 @@ + struct iattr *iap) + { + struct dentry *dentry, *dnew; +- int err, cerr; ++ int err, cerr, error = -EOPNOTSUPP; + + err = nfserr_noent; + if (!flen || !plen) +@@ -1136,12 +1311,18 @@ + goto out; + fh_lock(fhp); + dentry = fhp->fh_dentry; ++ ++ if (dentry->d_inode->i_op->symlink_raw) ++ error = symlink_raw(dentry, fname, flen, path); ++ + dnew = lookup_one_len(fname, dentry, flen); + err = PTR_ERR(dnew); + if (IS_ERR(dnew)) + goto out_nfserr; + +- err = vfs_symlink(dentry->d_inode, dnew, path); ++ err = error; ++ if (err == -EOPNOTSUPP || !dentry->d_inode->i_op->symlink_raw) ++ err = vfs_symlink(dentry->d_inode, dnew, path); + if (!err) { + if (EX_ISSYNC(fhp->fh_export)) + nfsd_sync_dir(dentry); +@@ -1211,7 +1392,10 @@ + dold = tfhp->fh_dentry; + dest = dold->d_inode; + +- err = vfs_link(dold, dirp, dnew); ++ if (dirp->i_op->link_raw) ++ err = link_raw(dold, ddir, dnew); ++ else ++ err = vfs_link(dold, dirp, dnew); + if (!err) { + if (EX_ISSYNC(ffhp->fh_export)) { + nfsd_sync_dir(ddir); +@@ -1296,7 +1480,10 @@ + err = nfserr_perm; + } else + #endif +- err = vfs_rename(fdir, odentry, tdir, ndentry); ++ if(fdir->i_op->rename_raw) ++ err = rename_raw(fdentry, tdentry, odentry, ndentry); ++ else ++ err = vfs_rename(fdir, odentry, tdir, ndentry); + if (!err && EX_ISSYNC(tfhp->fh_export)) { + nfsd_sync_dir(tdentry); + nfsd_sync_dir(fdentry); +@@ -1317,7 +1504,7 @@ + fill_post_wcc(tfhp); + double_up(&tdir->i_sem, &fdir->i_sem); + ffhp->fh_locked = tfhp->fh_locked = 0; +- ++ + out: + return err; + } +@@ -1363,9 +1550,15 @@ + err = nfserr_perm; + } else + #endif +- err = vfs_unlink(dirp, rdentry); ++ if (dirp->i_op->unlink_raw) ++ err = unlink_raw(dentry, fname, flen, rdentry); ++ else ++ err = vfs_unlink(dirp, rdentry); + } else { /* It's RMDIR */ +- err = vfs_rmdir(dirp, rdentry); ++ if (dirp->i_op->rmdir_raw) ++ err = rmdir_raw(dentry, fname, flen, rdentry); ++ else ++ err = vfs_rmdir(dirp, rdentry); + } + + dput(rdentry); +Index: linux-2.4.21-chaos/include/linux/fs.h +=================================================================== +--- linux-2.4.21-chaos.orig/include/linux/fs.h 2003-12-12 16:19:23.000000000 +0300 ++++ linux-2.4.21-chaos/include/linux/fs.h 2003-12-12 16:19:25.000000000 +0300 +@@ -93,6 +93,9 @@ + #define FS_SINGLE 8 /* Filesystem that can have only one superblock */ + #define FS_NOMOUNT 16 /* Never mount from userland */ + #define FS_LITTER 32 /* Keeps the tree in dcache */ ++#define FS_NFSEXP_FSID 64 /* Use file system specific fsid for ++ * exporting non device filesystems. ++ */ + #define FS_ODD_RENAME 32768 /* Temporary stuff; will go away as soon + * as nfs_rename() will be cleaned up + */ +@@ -1159,6 +1162,9 @@ + struct nameidata *nd, struct lookup_intent *it); + extern struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt, + int flags, struct lookup_intent *it); ++extern int revalidate_it(struct dentry *dentry, struct lookup_intent *it); ++extern int init_private_file_it(struct file *, struct dentry *dentry, int mode, ++ struct lookup_intent *it); + extern int filp_close(struct file *, fl_owner_t id); + extern char * getname(const char *); + +@@ -1458,6 +1464,8 @@ + extern int follow_down(struct vfsmount **, struct dentry **); + extern int follow_up(struct vfsmount **, struct dentry **); + extern struct dentry * lookup_one_len(const char *, struct dentry *, int); ++extern struct dentry * lookup_one_len_it(const char *, struct dentry *, int, ++ struct lookup_intent *); + extern struct dentry * __lookup_hash(struct qstr *, struct dentry *); + extern struct dentry * lookup_hash(struct qstr *, struct dentry *); + #define user_path_walk(name,nd) __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd) +@@ -1477,7 +1485,8 @@ + + extern struct inode * iget4_locked(struct super_block *, unsigned long, + find_inode_t, void *); +- ++extern struct inode * ilookup4(struct super_block *, unsigned long, ++ find_inode_t, void *); + static inline struct inode *iget4(struct super_block *sb, unsigned long ino, + find_inode_t find_actor, void *opaque) + { +Index: linux-2.4.21-chaos/kernel/ksyms.c +=================================================================== +--- linux-2.4.21-chaos.orig/kernel/ksyms.c 2003-12-12 16:18:36.000000000 +0300 ++++ linux-2.4.21-chaos/kernel/ksyms.c 2003-12-12 16:19:25.000000000 +0300 +@@ -178,6 +178,7 @@ + EXPORT_SYMBOL(igrab); + EXPORT_SYMBOL(iunique); + EXPORT_SYMBOL(iget4_locked); ++EXPORT_SYMBOL(ilookup4); + EXPORT_SYMBOL(unlock_new_inode); + EXPORT_SYMBOL(iput); + EXPORT_SYMBOL(inode_init_once); +@@ -191,6 +192,7 @@ + EXPORT_SYMBOL(path_release); + EXPORT_SYMBOL(__user_walk); + EXPORT_SYMBOL(lookup_one_len); ++EXPORT_SYMBOL(lookup_one_len_it); + EXPORT_SYMBOL(lookup_hash); + + EXPORT_SYMBOL(sys_close); diff --git a/lustre/kernel_patches/patches/tcp-zero-copy-2.4.21-suse2.patch b/lustre/kernel_patches/patches/tcp-zero-copy-2.4.21-suse2.patch new file mode 100644 index 0000000..f61bc07 --- /dev/null +++ b/lustre/kernel_patches/patches/tcp-zero-copy-2.4.21-suse2.patch @@ -0,0 +1,468 @@ +Index: linux-2.4.21-suse2/include/linux/skbuff.h +=================================================================== +--- linux-2.4.21-suse2.orig/include/linux/skbuff.h 2004-01-10 12:48:50.000000000 +0300 ++++ linux-2.4.21-suse2/include/linux/skbuff.h 2004-01-10 16:31:03.000000000 +0300 +@@ -116,6 +116,30 @@ + __u16 size; + }; + ++/* Support for callback when skb data has been released */ ++typedef struct zccd /* Zero Copy Callback Descriptor */ ++{ /* (embed as first member of custom struct) */ ++ atomic_t zccd_count; /* reference count */ ++ void (*zccd_destructor)(struct zccd *); /* callback when refcount reaches zero */ ++} zccd_t; ++ ++static inline void zccd_init (zccd_t *d, void (*callback)(zccd_t *)) ++{ ++ atomic_set (&d->zccd_count, 1); ++ d->zccd_destructor = callback; ++} ++ ++static inline void zccd_get (zccd_t *d) /* take a reference */ ++{ ++ atomic_inc (&d->zccd_count); ++} ++ ++static inline void zccd_put (zccd_t *d) /* release a reference */ ++{ ++ if (atomic_dec_and_test (&d->zccd_count)) ++ (d->zccd_destructor)(d); ++} ++ + /* This data is invariant across clones and lives at + * the end of the header data, ie. at skb->end. + */ +@@ -123,6 +147,12 @@ + atomic_t dataref; + unsigned int nr_frags; + struct sk_buff *frag_list; ++ zccd_t *zccd; /* zero copy descriptor */ ++ zccd_t *zccd2; /* 2nd zero copy descriptor */ ++ /* NB we expect zero-copy data to be at least 1 packet, so ++ * having 2 zccds means we don't unneccessarily split the packet ++ * where consecutive zero-copy sends abutt. ++ */ + skb_frag_t frags[MAX_SKB_FRAGS]; + }; + +Index: linux-2.4.21-suse2/include/net/tcp.h +=================================================================== +--- linux-2.4.21-suse2.orig/include/net/tcp.h 2003-11-11 03:47:27.000000000 +0300 ++++ linux-2.4.21-suse2/include/net/tcp.h 2004-01-10 16:33:16.000000000 +0300 +@@ -644,6 +644,8 @@ + + extern int tcp_sendmsg(struct sock *sk, struct msghdr *msg, int size); + extern ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags); ++extern ssize_t tcp_sendpage_zccd(struct socket *sock, struct page *page, int offset, size_t size, ++ int flags, zccd_t *zccd); + + extern int tcp_ioctl(struct sock *sk, + int cmd, +@@ -740,6 +742,9 @@ + struct msghdr *msg, + int len, int nonblock, + int flags, int *addr_len); ++extern int tcp_recvpackets(struct sock *sk, ++ struct sk_buff_head *packets, ++ int len, int nonblock); + extern int tcp_kvec_read(struct sock *sk, kvec_cb_t cb, int len); + extern int tcp_kvec_write(struct sock *sk, kvec_cb_t cb, int len); + +Index: linux-2.4.21-suse2/net/netsyms.c +=================================================================== +--- linux-2.4.21-suse2.orig/net/netsyms.c 2003-10-28 21:34:24.000000000 +0300 ++++ linux-2.4.21-suse2/net/netsyms.c 2004-01-10 16:30:46.000000000 +0300 +@@ -403,6 +403,8 @@ + + #endif + ++EXPORT_SYMBOL(tcp_sendpage_zccd); ++EXPORT_SYMBOL(tcp_recvpackets); + EXPORT_SYMBOL(tcp_read_sock); + + EXPORT_SYMBOL(netlink_set_err); +Index: linux-2.4.21-suse2/net/core/skbuff.c +=================================================================== +--- linux-2.4.21-suse2.orig/net/core/skbuff.c 2003-11-07 02:54:26.000000000 +0300 ++++ linux-2.4.21-suse2/net/core/skbuff.c 2004-01-10 16:30:46.000000000 +0300 +@@ -208,6 +208,8 @@ + atomic_set(&(skb_shinfo(skb)->dataref), 1); + skb_shinfo(skb)->nr_frags = 0; + skb_shinfo(skb)->frag_list = NULL; ++ skb_shinfo(skb)->zccd = NULL; /* skbuffs kick off with NO user zero copy descriptors */ ++ skb_shinfo(skb)->zccd2 = NULL; + return skb; + + nodata: +@@ -277,6 +279,10 @@ + { + if (!skb->cloned || + atomic_dec_and_test(&(skb_shinfo(skb)->dataref))) { ++ if (skb_shinfo(skb)->zccd != NULL) /* zero copy callback descriptor? */ ++ zccd_put (skb_shinfo(skb)->zccd); /* release hold */ ++ if (skb_shinfo(skb)->zccd2 != NULL) /* 2nd zero copy callback descriptor? */ ++ zccd_put (skb_shinfo(skb)->zccd2); /* release hold */ + if (skb_shinfo(skb)->nr_frags) { + int i; + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) +@@ -535,6 +541,8 @@ + atomic_set(&(skb_shinfo(skb)->dataref), 1); + skb_shinfo(skb)->nr_frags = 0; + skb_shinfo(skb)->frag_list = NULL; ++ skb_shinfo(skb)->zccd = NULL; /* copied data => no user zero copy descriptor */ ++ skb_shinfo(skb)->zccd2 = NULL; + + /* We are no longer a clone, even if we were. */ + skb->cloned = 0; +@@ -581,6 +589,14 @@ + n->data_len = skb->data_len; + n->len = skb->len; + ++ if (skb_shinfo(skb)->zccd != NULL) /* user zero copy descriptor? */ ++ zccd_get (skb_shinfo(skb)->zccd); /* 1 more ref (pages are shared) */ ++ skb_shinfo(n)->zccd = skb_shinfo(skb)->zccd; ++ ++ if (skb_shinfo(skb)->zccd2 != NULL) /* 2nd user zero copy descriptor? */ ++ zccd_get (skb_shinfo(skb)->zccd2); /* 1 more ref (pages are shared) */ ++ skb_shinfo(n)->zccd2 = skb_shinfo(skb)->zccd2; ++ + if (skb_shinfo(skb)->nr_frags) { + int i; + +@@ -623,6 +639,8 @@ + u8 *data; + int size = nhead + (skb->end - skb->head) + ntail; + long off; ++ zccd_t *zccd = skb_shinfo(skb)->zccd; /* stash user zero copy descriptor */ ++ zccd_t *zccd2 = skb_shinfo(skb)->zccd2; /* stash 2nd user zero copy descriptor */ + + if (skb_shared(skb)) + BUG(); +@@ -644,6 +662,11 @@ + if (skb_shinfo(skb)->frag_list) + skb_clone_fraglist(skb); + ++ if (zccd != NULL) /* user zero copy descriptor? */ ++ zccd_get (zccd); /* extra ref (pages are shared) */ ++ if (zccd2 != NULL) /* 2nd user zero copy descriptor? */ ++ zccd_get (zccd2); /* extra ref (pages are shared) */ ++ + skb_release_data(skb); + + off = (data+nhead) - skb->head; +@@ -658,6 +681,8 @@ + skb->nh.raw += off; + skb->cloned = 0; + atomic_set(&skb_shinfo(skb)->dataref, 1); ++ skb_shinfo(skb)->zccd = zccd; ++ skb_shinfo(skb)->zccd2 = zccd2; + return 0; + + nodata: +Index: linux-2.4.21-suse2/net/ipv4/tcp.c +=================================================================== +--- linux-2.4.21-suse2.orig/net/ipv4/tcp.c 2003-10-28 21:34:09.000000000 +0300 ++++ linux-2.4.21-suse2/net/ipv4/tcp.c 2004-01-10 16:35:26.000000000 +0300 +@@ -1013,7 +1013,7 @@ + goto out; + } + +-ssize_t do_tcp_sendpages(struct sock *sk, struct kveclet *let, int poffset, size_t psize, int flags); ++ssize_t do_tcp_sendpages(struct sock *sk, struct kveclet *let, int poffset, size_t psize, int flags, zccd_t *zccd); + + static inline int + can_coalesce(struct sk_buff *skb, int i, struct page *page, int off) +@@ -1092,7 +1092,8 @@ + return err; + } + +-ssize_t do_tcp_sendpages(struct sock *sk, struct kveclet *let, int poffset, size_t psize, int flags) ++/* Extra parameter: user zero copy descriptor (or NULL if not doing that) */ ++ssize_t do_tcp_sendpages(struct sock *sk, struct kveclet *let, int poffset, size_t psize, int flags, zccd_t *zccd) + { + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + int mss_now; +@@ -1145,6 +1146,17 @@ + copy = size; + + i = skb_shinfo(skb)->nr_frags; ++ ++ if (zccd != NULL && /* this is a zcc I/O */ ++ skb_shinfo(skb)->zccd != NULL && /* skb is part of a zcc I/O */ ++ skb_shinfo(skb)->zccd2 != NULL && ++ skb_shinfo(skb)->zccd != zccd && /* not the same one */ ++ skb_shinfo(skb)->zccd2 != zccd) ++ { ++ tcp_mark_push (tp, skb); ++ goto new_segment; ++ } ++ + if (can_coalesce(skb, i, page, offset)) { + skb_shinfo(skb)->frags[i-1].size += copy; + } else if (i < MAX_SKB_FRAGS) { +@@ -1155,6 +1167,20 @@ + goto new_segment; + } + ++ if (zccd != NULL && /* this is a zcc I/O */ ++ skb_shinfo(skb)->zccd != zccd && /* not already referencing this zccd */ ++ skb_shinfo(skb)->zccd2 != zccd) ++ { ++ zccd_get (zccd); /* bump ref count */ ++ ++ BUG_TRAP (skb_shinfo(skb)->zccd2 == NULL); ++ ++ if (skb_shinfo(skb)->zccd == NULL) /* reference this zccd */ ++ skb_shinfo(skb)->zccd = zccd; ++ else ++ skb_shinfo(skb)->zccd2 = zccd; ++ } ++ + skb->len += copy; + skb->data_len += copy; + skb->ip_summed = CHECKSUM_HW; +@@ -1221,7 +1247,30 @@ + + lock_sock(sk); + TCP_CHECK_TIMER(sk); +- res = do_tcp_sendpages(sk, &let, 0, size, flags); ++ res = do_tcp_sendpages(sk, &let, 0, size, flags, NULL); ++ TCP_CHECK_TIMER(sk); ++ release_sock(sk); ++ return res; ++} ++ ++ssize_t tcp_sendpage_zccd(struct socket *sock, struct page *page, int offset, size_t size, ++ int flags, zccd_t *zccd) ++{ ++ struct kveclet let = { page, offset, size }; ++ ssize_t res; ++ struct sock *sk = sock->sk; ++ ++#define TCP_ZC_CSUM_FLAGS (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM) ++ ++ if (!(sk->route_caps & NETIF_F_SG) || /* caller shouldn't waste her time */ ++ !(sk->route_caps & TCP_ZC_CSUM_FLAGS)) /* on double mapping */ ++ BUG (); ++ ++ lock_sock(sk); ++ TCP_CHECK_TIMER(sk); ++ ++ res = do_tcp_sendpages(sk, &let, 0, size, flags, zccd); ++ + TCP_CHECK_TIMER(sk); + release_sock(sk); + return res; +@@ -1235,7 +1284,7 @@ + !(sk->route_caps & TCP_ZC_CSUM_FLAGS)) + BUG(); + +- res = do_tcp_sendpages(sk, info->cur_let, info->offset, info->len - info->done, MSG_DONTWAIT); ++ res = do_tcp_sendpages(sk, info->cur_let, info->offset, info->len - info->done, MSG_DONTWAIT, NULL); + if (res > 0) + info->done += res; + +@@ -2084,6 +2133,202 @@ + goto out; + } + ++int tcp_recvpackets (struct sock *sk, struct sk_buff_head *packets, ++ int len, int nonblock) ++{ ++ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); ++ int copied; ++ long timeo; ++ ++ BUG_TRAP (len > 0); ++ /*BUG_TRAP ((flags & (MSG_OOB | MSG_PEEK | MSG_TRUNC)) == 0);*/ ++ ++ lock_sock(sk); ++ ++ TCP_CHECK_TIMER(sk); ++ ++ copied = -ENOTCONN; ++ if (sk->state == TCP_LISTEN) ++ goto out; ++ ++ copied = 0; ++ timeo = sock_rcvtimeo(sk, nonblock); ++ ++ do { ++ struct sk_buff * skb; ++ u32 offset; ++ unsigned long used; ++ int exhausted; ++ int eaten; ++ ++ /* Are we at urgent data? Stop if we have read anything. */ ++ if (copied && tp->urg_data && tp->urg_seq == tp->copied_seq) ++ break; ++ ++ /* We need to check signals first, to get correct SIGURG ++ * handling. FIXME: Need to check this doesnt impact 1003.1g ++ * and move it down to the bottom of the loop ++ */ ++ if (signal_pending(current)) { ++ if (copied) ++ break; ++ copied = timeo ? sock_intr_errno(timeo) : -EAGAIN; ++ break; ++ } ++ ++ /* Next get a buffer. */ ++ ++ skb = skb_peek(&sk->receive_queue); ++ ++ if (skb == NULL) /* nothing ready */ ++ { ++ if (copied) { ++ if (sk->err || ++ sk->state == TCP_CLOSE || ++ (sk->shutdown & RCV_SHUTDOWN) || ++ !timeo || ++ (0)) ++ break; ++ } else { ++ if (sk->done) ++ break; ++ ++ if (sk->err) { ++ copied = sock_error(sk); ++ break; ++ } ++ ++ if (sk->shutdown & RCV_SHUTDOWN) ++ break; ++ ++ if (sk->state == TCP_CLOSE) { ++ if (!sk->done) { ++ /* This occurs when user tries to read ++ * from never connected socket. ++ */ ++ copied = -ENOTCONN; ++ break; ++ } ++ break; ++ } ++ ++ if (!timeo) { ++ copied = -EAGAIN; ++ break; ++ } ++ } ++ ++ cleanup_rbuf(sk, copied); ++ timeo = tcp_data_wait(sk, timeo); ++ continue; ++ } ++ ++ BUG_TRAP (atomic_read (&skb->users) == 1); ++ ++ exhausted = eaten = 0; ++ ++ offset = tp->copied_seq - TCP_SKB_CB(skb)->seq; ++ if (skb->h.th->syn) ++ offset--; ++ ++ used = skb->len - offset; ++ ++ if (tp->urg_data) { ++ u32 urg_offset = tp->urg_seq - tp->copied_seq; ++ if (urg_offset < used) { ++ if (!urg_offset) { /* at urgent date */ ++ if (!sk->urginline) { ++ tp->copied_seq++; /* discard the single byte of urgent data */ ++ offset++; ++ used--; ++ } ++ } else /* truncate read */ ++ used = urg_offset; ++ } ++ } ++ ++ BUG_TRAP (used >= 0); ++ if (len < used) ++ used = len; ++ ++ if (used == 0) ++ exhausted = 1; ++ else ++ { ++ if (skb_is_nonlinear (skb)) ++ { ++ int rc = skb_linearize (skb, GFP_KERNEL); ++ ++ printk ("tcp_recvpackets(): linearising: %d\n", rc); ++ ++ if (rc) ++ { ++ if (!copied) ++ copied = rc; ++ break; ++ } ++ } ++ ++ if ((offset + used) == skb->len) /* consuming the whole packet */ ++ { ++ __skb_unlink (skb, &sk->receive_queue); ++ dst_release (skb->dst); ++ skb_orphan (skb); ++ __skb_pull (skb, offset); ++ __skb_queue_tail (packets, skb); ++ exhausted = eaten = 1; ++ } ++ else /* consuming only part of the packet */ ++ { ++ struct sk_buff *skb2 = skb_clone (skb, GFP_KERNEL); ++ ++ if (skb2 == NULL) ++ { ++ if (!copied) ++ copied = -ENOMEM; ++ break; ++ } ++ ++ dst_release (skb2->dst); ++ __skb_pull (skb2, offset); ++ __skb_trim (skb2, used); ++ __skb_queue_tail (packets, skb2); ++ } ++ ++ tp->copied_seq += used; ++ copied += used; ++ len -= used; ++ } ++ ++ if (tp->urg_data && after(tp->copied_seq,tp->urg_seq)) { ++ tp->urg_data = 0; ++ tcp_fast_path_check(sk, tp); ++ } ++ ++ if (!exhausted) ++ continue; ++ ++ if (skb->h.th->fin) ++ { ++ tp->copied_seq++; ++ if (!eaten) ++ tcp_eat_skb (sk, skb); ++ break; ++ } ++ ++ if (!eaten) ++ tcp_eat_skb (sk, skb); ++ ++ } while (len > 0); ++ ++ out: ++ /* Clean up data we have read: This will do ACK frames. */ ++ cleanup_rbuf(sk, copied); ++ TCP_CHECK_TIMER(sk); ++ release_sock(sk); ++ return copied; ++} ++ + /* + * State processing on a close. This implements the state shift for + * sending our FIN frame. Note that we only send a FIN for some diff --git a/lustre/kernel_patches/patches/vfs_intent-2.4.21-suse2.patch b/lustre/kernel_patches/patches/vfs_intent-2.4.21-suse2.patch new file mode 100644 index 0000000..cfe87c5 --- /dev/null +++ b/lustre/kernel_patches/patches/vfs_intent-2.4.21-suse2.patch @@ -0,0 +1,1839 @@ + fs/dcache.c | 19 ++ + fs/exec.c | 17 +- + fs/namei.c | 295 +++++++++++++++++++++++++++++++++++++++------- + fs/namespace.c | 28 +++- + fs/open.c | 172 +++++++++++++++++++------- + fs/stat.c | 52 +++++--- + include/linux/dcache.h | 60 +++++++++ + include/linux/fs.h | 32 ++++ + include/linux/fs_struct.h | 4 + kernel/exit.c | 3 + kernel/fork.c | 3 + kernel/ksyms.c | 1 + 12 files changed, 558 insertions(+), 128 deletions(-) + +Index: linux-2.4.21-suse2/fs/dcache.c +=================================================================== +--- linux-2.4.21-suse2.orig/fs/dcache.c 2003-10-28 21:33:59.000000000 +0300 ++++ linux-2.4.21-suse2/fs/dcache.c 2004-01-10 12:15:41.000000000 +0300 +@@ -186,6 +186,13 @@ + spin_unlock(&dcache_lock); + return 0; + } ++ ++ /* network invalidation by Lustre */ ++ if (dentry->d_flags & DCACHE_LUSTRE_INVALID) { ++ spin_unlock(&dcache_lock); ++ return 0; ++ } ++ + /* + * Check whether to do a partial shrink_dcache + * to get rid of unused child entries. +@@ -838,13 +845,19 @@ + * Adds a dentry to the hash according to its name. + */ + +-void d_rehash(struct dentry * entry) ++void __d_rehash(struct dentry * entry, int lock) + { + struct list_head *list = d_hash(entry->d_parent, entry->d_name.hash); + if (!list_empty(&entry->d_hash)) BUG(); +- spin_lock(&dcache_lock); ++ if (lock) spin_lock(&dcache_lock); + list_add(&entry->d_hash, list); +- spin_unlock(&dcache_lock); ++ if (lock) spin_unlock(&dcache_lock); ++} ++EXPORT_SYMBOL(__d_rehash); ++ ++void d_rehash(struct dentry * entry) ++{ ++ __d_rehash(entry, 1); + } + + #define do_switch(x,y) do { \ +Index: linux-2.4.21-suse2/fs/exec.c +=================================================================== +--- linux-2.4.21-suse2.orig/fs/exec.c 2003-10-28 21:34:17.000000000 +0300 ++++ linux-2.4.21-suse2/fs/exec.c 2004-01-10 12:15:41.000000000 +0300 +@@ -112,8 +112,10 @@ + struct file * file; + struct nameidata nd; + int error; ++ struct lookup_intent it = { .it_op = IT_OPEN, ++ .it_flags = FMODE_READ|FMODE_EXEC }; + +- error = user_path_walk(library, &nd); ++ error = user_path_walk_it(library, &nd, &it); + if (error) + goto out; + +@@ -125,7 +127,8 @@ + if (error) + goto exit; + +- file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); ++ file = dentry_open_it(nd.dentry, nd.mnt, O_RDONLY, &it); ++ intent_release(&it); + error = PTR_ERR(file); + if (IS_ERR(file)) + goto out; +@@ -382,8 +385,10 @@ + struct inode *inode; + struct file *file; + int err = 0; ++ struct lookup_intent it = { .it_op = IT_OPEN, ++ .it_flags = FMODE_READ|FMODE_EXEC }; + +- err = path_lookup(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd); ++ err = path_lookup_it(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd, &it); + file = ERR_PTR(err); + if (!err) { + inode = nd.dentry->d_inode; +@@ -395,7 +400,8 @@ + err = -EACCES; + file = ERR_PTR(err); + if (!err) { +- file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); ++ file = dentry_open_it(nd.dentry, nd.mnt, O_RDONLY, &it); ++ intent_release(&it); + if (!IS_ERR(file)) { + err = deny_write_access(file); + if (err) { +@@ -407,6 +413,7 @@ + return file; + } + } ++ intent_release(&it); + path_release(&nd); + } + goto out; +@@ -1150,7 +1157,7 @@ + goto close_fail; + if (!file->f_op->write) + goto close_fail; +- if (do_truncate(file->f_dentry, 0) != 0) ++ if (do_truncate(file->f_dentry, 0, 0) != 0) + goto close_fail; + + retval = binfmt->core_dump(signr, regs, file); +Index: linux-2.4.21-suse2/fs/namei.c +=================================================================== +--- linux-2.4.21-suse2.orig/fs/namei.c 2004-01-10 12:06:40.000000000 +0300 ++++ linux-2.4.21-suse2/fs/namei.c 2004-01-10 12:44:04.000000000 +0300 +@@ -94,6 +94,13 @@ + * XEmacs seems to be relying on it... + */ + ++void intent_release(struct lookup_intent *it) ++{ ++ if (it && it->it_op_release) ++ it->it_op_release(it); ++ ++} ++ + /* In order to reduce some races, while at the same time doing additional + * checking and hopefully speeding things up, we copy filenames to the + * kernel data space before using them.. +@@ -260,10 +267,19 @@ + * Internal lookup() using the new generic dcache. + * SMP-safe + */ +-static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, int flags) ++static struct dentry *cached_lookup(struct dentry *parent, struct qstr *name, ++ int flags, struct lookup_intent *it) + { + struct dentry * dentry = d_lookup(parent, name); + ++ if (dentry && dentry->d_op && dentry->d_op->d_revalidate_it) { ++ if (!dentry->d_op->d_revalidate_it(dentry, flags, it) && ++ !d_invalidate(dentry)) { ++ dput(dentry); ++ dentry = NULL; ++ } ++ return dentry; ++ } else + if (dentry && dentry->d_op && dentry->d_op->d_revalidate) { + if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) { + dput(dentry); +@@ -281,11 +297,15 @@ + * make sure that nobody added the entry to the dcache in the meantime.. + * SMP-safe + */ +-static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, int flags) ++static struct dentry *real_lookup(struct dentry *parent, struct qstr *name, ++ int flags, struct lookup_intent *it) + { + struct dentry * result; + struct inode *dir = parent->d_inode; ++ int counter = 0; + ++again: ++ counter++; + down(&dir->i_sem); + /* + * First re-do the cached lookup just in case it was created +@@ -300,6 +320,9 @@ + result = ERR_PTR(-ENOMEM); + if (dentry) { + lock_kernel(); ++ if (dir->i_op->lookup_it) ++ result = dir->i_op->lookup_it(dir, dentry, it, flags); ++ else + result = dir->i_op->lookup(dir, dentry); + unlock_kernel(); + if (result) +@@ -321,6 +344,15 @@ + dput(result); + result = ERR_PTR(-ENOENT); + } ++ } else if (result->d_op && result->d_op->d_revalidate_it) { ++ if (!result->d_op->d_revalidate_it(result, flags, it) && ++ !d_invalidate(result)) { ++ dput(result); ++ if (counter > 10) ++ result = ERR_PTR(-ESTALE); ++ if (!IS_ERR(result)) ++ goto again; ++ } + } + return result; + } +@@ -332,7 +364,8 @@ + * Without that kind of total limit, nasty chains of consecutive + * symlinks can cause almost arbitrarily long lookups. + */ +-static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd) ++static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd, ++ struct lookup_intent *it) + { + int err; + if (current->link_count >= 8) +@@ -346,10 +379,12 @@ + current->link_count++; + current->total_link_count++; + UPDATE_ATIME(dentry->d_inode); ++ nd->intent = it; + err = dentry->d_inode->i_op->follow_link(dentry, nd); + current->link_count--; + return err; + loop: ++ intent_release(it); + path_release(nd); + return -ELOOP; + } +@@ -447,7 +482,8 @@ + * + * We expect 'base' to be positive and a directory. + */ +-static inline int __link_path_walk(const char * name, struct nameidata *nd) ++static inline int __link_path_walk_it(const char * name, struct nameidata *nd, ++ struct lookup_intent *it) + { + struct dentry *dentry; + struct inode *inode; +@@ -524,12 +560,12 @@ + break; + } + /* This does the actual lookups.. */ +- dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE); ++ dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE, NULL); + if (!dentry) { + err = -EWOULDBLOCKIO; + if (atomic) + break; +- dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE); ++ dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE, NULL); + err = PTR_ERR(dentry); + if (IS_ERR(dentry)) + break; +@@ -547,7 +583,7 @@ + goto out_dput; + + if (inode->i_op->follow_link) { +- err = do_follow_link(dentry, nd); ++ err = do_follow_link(dentry, nd, NULL); + dput(dentry); + if (err) + goto return_err; +@@ -563,7 +599,7 @@ + nd->dentry = dentry; + } + err = -ENOTDIR; +- if (!inode->i_op->lookup) ++ if (!inode->i_op->lookup && !inode->i_op->lookup_it) + break; + continue; + /* here ends the main loop */ +@@ -590,12 +626,12 @@ + if (err < 0) + break; + } +- dentry = cached_lookup(nd->dentry, &this, 0); ++ dentry = cached_lookup(nd->dentry, &this, 0, it); + if (!dentry) { + err = -EWOULDBLOCKIO; + if (atomic) + break; +- dentry = real_lookup(nd->dentry, &this, 0); ++ dentry = real_lookup(nd->dentry, &this, 0, it); + err = PTR_ERR(dentry); + if (IS_ERR(dentry)) + break; +@@ -605,7 +641,7 @@ + inode = dentry->d_inode; + if ((lookup_flags & LOOKUP_FOLLOW) + && inode && inode->i_op && inode->i_op->follow_link) { +- err = do_follow_link(dentry, nd); ++ err = do_follow_link(dentry, nd, it); + dput(dentry); + if (err) + goto return_err; +@@ -619,7 +655,8 @@ + goto no_inode; + if (lookup_flags & LOOKUP_DIRECTORY) { + err = -ENOTDIR; +- if (!inode->i_op || !inode->i_op->lookup) ++ if (!inode->i_op || ++ (!inode->i_op->lookup && !inode->i_op->lookup_it)) + break; + } + goto return_base; +@@ -643,6 +680,25 @@ + * Check the cached dentry for staleness. + */ + dentry = nd->dentry; ++ if (dentry && dentry->d_op && dentry->d_op->d_revalidate_it) { ++ err = -ESTALE; ++ if (!dentry->d_op->d_revalidate_it(dentry, 0, it)) { ++ struct dentry *new; ++ err = permission(dentry->d_parent->d_inode, ++ MAY_EXEC); ++ if (err) ++ break; ++ new = real_lookup(dentry->d_parent, ++ &dentry->d_name, 0, NULL); ++ d_invalidate(dentry); ++ dput(dentry); ++ if (IS_ERR(new)) { ++ err = PTR_ERR(new); ++ break; ++ } ++ nd->dentry = new; ++ } ++ } else + if (dentry && dentry->d_op && dentry->d_op->d_revalidate) { + err = -ESTALE; + if (!dentry->d_op->d_revalidate(dentry, lookup_flags & LOOKUP_PARENT)) { +@@ -656,6 +712,8 @@ + dput(dentry); + break; + } ++ if (err) ++ intent_release(it); + path_release(nd); + return_err: + return err; +@@ -663,7 +721,7 @@ + + int link_path_walk(const char * name, struct nameidata *nd) + { +- return __link_path_walk(name,nd); ++ return __link_path_walk_it(name, nd, NULL); + } + + static inline int __path_walk(const char * name, struct nameidata *nd) +@@ -677,6 +735,11 @@ + return __path_walk(name, nd); + } + ++int path_walk_it(const char * name, struct nameidata *nd, struct lookup_intent *it) ++{ ++ return __path_walk(name, nd, it); ++} ++ + /* SMP-safe */ + /* returns 1 if everything is done */ + static int __emul_lookup_dentry(const char *name, struct nameidata *nd) +@@ -759,6 +822,17 @@ + } + + /* SMP-safe */ ++int path_lookup_it(const char *path, unsigned flags, struct nameidata *nd, ++ struct lookup_intent *it) ++{ ++ int error = 0; ++ if (path_init(path, flags, nd)) ++ error = path_walk_it(path, nd, it); ++ return error; ++} ++ ++ ++/* SMP-safe */ + int path_lookup(const char *path, unsigned flags, struct nameidata *nd) + { + int error = 0; +@@ -773,6 +847,7 @@ + { + nd->last_type = LAST_ROOT; /* if there are only slashes... */ + nd->flags = flags; ++ nd->intent = NULL; + if (*name=='/') + return walk_init_root(name,nd); + read_lock(¤t->fs->lock); +@@ -787,7 +862,8 @@ + * needs parent already locked. Doesn't follow mounts. + * SMP-safe. + */ +-struct dentry * lookup_hash(struct qstr *name, struct dentry * base) ++struct dentry * lookup_hash_it(struct qstr *name, struct dentry * base, ++ struct lookup_intent *it) + { + struct dentry * dentry; + struct inode *inode; +@@ -810,13 +886,16 @@ + goto out; + } + +- dentry = cached_lookup(base, name, 0); ++ dentry = cached_lookup(base, name, 0, it); + if (!dentry) { + struct dentry *new = d_alloc(base, name); + dentry = ERR_PTR(-ENOMEM); + if (!new) + goto out; + lock_kernel(); ++ if (inode->i_op->lookup_it) ++ dentry = inode->i_op->lookup_it(inode, new, it, 0); ++ else + dentry = inode->i_op->lookup(inode, new); + unlock_kernel(); + if (!dentry) +@@ -828,6 +907,12 @@ + return dentry; + } + ++struct dentry * lookup_hash(struct qstr *name, struct dentry * base) ++{ ++ return lookup_hash_it(name, base, NULL); ++} ++ ++ + /* SMP-safe */ + struct dentry * lookup_one_len(const char * name, struct dentry * base, int len) + { +@@ -849,7 +934,7 @@ + } + this.hash = end_name_hash(hash); + +- return lookup_hash(&this, base); ++ return lookup_hash_it(&this, base, NULL); + access: + return ERR_PTR(-EACCES); + } +@@ -880,6 +965,23 @@ + return err; + } + ++int __user_walk_it(const char *name, unsigned flags, struct nameidata *nd, ++ struct lookup_intent *it) ++{ ++ char *tmp; ++ int err; ++ ++ tmp = getname(name); ++ err = PTR_ERR(tmp); ++ if (!IS_ERR(tmp)) { ++ err = 0; ++ if (path_init(tmp, flags, nd)) ++ err = path_walk_it(tmp, nd, it); ++ putname(tmp); ++ } ++ return err; ++} ++ + /* + * It's inline, so penalty for filesystems that don't use sticky bit is + * minimal. +@@ -977,7 +1079,8 @@ + return retval; + } + +-int vfs_create(struct inode *dir, struct dentry *dentry, int mode) ++static int vfs_create_it(struct inode *dir, struct dentry *dentry, int mode, ++ struct lookup_intent *it) + { + int error; + +@@ -990,12 +1093,15 @@ + goto exit_lock; + + error = -EACCES; /* shouldn't it be ENOSYS? */ +- if (!dir->i_op || !dir->i_op->create) ++ if (!dir->i_op || (!dir->i_op->create && !dir->i_op->create_it)) + goto exit_lock; + + DQUOT_INIT(dir); + lock_kernel(); +- error = dir->i_op->create(dir, dentry, mode); ++ if (dir->i_op->create_it) ++ error = dir->i_op->create_it(dir, dentry, mode, it); ++ else ++ error = dir->i_op->create(dir, dentry, mode); + unlock_kernel(); + exit_lock: + up(&dir->i_zombie); +@@ -1004,6 +1110,11 @@ + return error; + } + ++int vfs_create(struct inode *dir, struct dentry *dentry, int mode) ++{ ++ return vfs_create_it(dir, dentry, mode, NULL); ++} ++ + /* + * open_namei() + * +@@ -1018,7 +1129,8 @@ + * for symlinks (where the permissions are checked later). + * SMP-safe + */ +-int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) ++int open_namei_it(const char *pathname, int flag, int mode, ++ struct nameidata *nd, struct lookup_intent *it) + { + int acc_mode, error = 0; + struct inode *inode; +@@ -1028,11 +1140,14 @@ + + acc_mode = ACC_MODE(flag); + ++ if (it) ++ it->it_flags = flag; ++ + /* + * The simplest case - just a plain lookup. + */ + if (!(flag & O_CREAT)) { +- error = path_lookup(pathname, lookup_flags(flag), nd); ++ error = path_lookup_it(pathname, lookup_flags(flag), nd, it); + if (error) + return error; + dentry = nd->dentry; +@@ -1042,6 +1157,10 @@ + /* + * Create - we need to know the parent. + */ ++ if (it) { ++ it->it_create_mode = mode; ++ it->it_op |= IT_CREAT; ++ } + error = path_lookup(pathname, LOOKUP_PARENT, nd); + if (error) + return error; +@@ -1057,7 +1176,7 @@ + + dir = nd->dentry; + down(&dir->d_inode->i_sem); +- dentry = lookup_hash(&nd->last, nd->dentry); ++ dentry = lookup_hash_it(&nd->last, nd->dentry, it); + + do_last: + error = PTR_ERR(dentry); +@@ -1066,11 +1185,12 @@ + goto exit; + } + ++ it->it_create_mode = mode; + /* Negative dentry, just create the file */ + if (!dentry->d_inode) { + if (!IS_POSIXACL(dir->d_inode)) + mode &= ~current->fs->umask; +- error = vfs_create(dir->d_inode, dentry, mode); ++ error = vfs_create_it(dir->d_inode, dentry, mode, it); + up(&dir->d_inode->i_sem); + #ifndef DENTRY_WASTE_RAM + if (error) +@@ -1178,7 +1298,7 @@ + if (!error) { + DQUOT_INIT(inode); + +- error = do_truncate(dentry, 0); ++ error = do_truncate(dentry, 0, 1); + } + put_write_access(inode); + if (error) +@@ -1190,8 +1310,10 @@ + return 0; + + exit_dput: ++ intent_release(it); + dput(dentry); + exit: ++ intent_release(it); + path_release(nd); + return error; + +@@ -1210,7 +1332,10 @@ + * are done. Procfs-like symlinks just set LAST_BIND. + */ + UPDATE_ATIME(dentry->d_inode); ++ nd->intent = it; + error = dentry->d_inode->i_op->follow_link(dentry, nd); ++ if (error) ++ intent_release(it); + dput(dentry); + if (error) + return error; +@@ -1232,13 +1357,20 @@ + } + dir = nd->dentry; + down(&dir->d_inode->i_sem); +- dentry = lookup_hash(&nd->last, nd->dentry); ++ dentry = lookup_hash_it(&nd->last, nd->dentry, it); + putname(nd->last.name); + goto do_last; + } + ++int open_namei(const char *pathname, int flag, int mode, struct nameidata *nd) ++{ ++ return open_namei_it(pathname, flag, mode, nd, NULL); ++} ++ ++ + /* SMP-safe */ +-struct dentry *lookup_create(struct nameidata *nd, int is_dir) ++struct dentry *lookup_create(struct nameidata *nd, int is_dir, ++ struct lookup_intent *it) + { + struct dentry *dentry; + +@@ -1246,7 +1378,7 @@ + dentry = ERR_PTR(-EEXIST); + if (nd->last_type != LAST_NORM) + goto fail; +- dentry = lookup_hash(&nd->last, nd->dentry); ++ dentry = lookup_hash_it(&nd->last, nd->dentry, it); + if (IS_ERR(dentry)) + goto fail; + if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode) +@@ -1302,7 +1434,16 @@ + error = path_lookup(tmp, LOOKUP_PARENT, &nd); + if (error) + goto out; +- dentry = lookup_create(&nd, 0); ++ ++ if (nd.dentry->d_inode->i_op->mknod_raw) { ++ struct inode_operations *op = nd.dentry->d_inode->i_op; ++ error = op->mknod_raw(&nd, mode, dev); ++ /* the file system wants to use normal vfs path now */ ++ if (error != -EOPNOTSUPP) ++ goto out2; ++ } ++ ++ dentry = lookup_create(&nd, 0, NULL); + error = PTR_ERR(dentry); + + if (!IS_POSIXACL(nd.dentry->d_inode)) +@@ -1324,6 +1465,7 @@ + dput(dentry); + } + up(&nd.dentry->d_inode->i_sem); ++out2: + path_release(&nd); + out: + putname(tmp); +@@ -1371,7 +1513,14 @@ + error = path_lookup(tmp, LOOKUP_PARENT, &nd); + if (error) + goto out; +- dentry = lookup_create(&nd, 1); ++ if (nd.dentry->d_inode->i_op->mkdir_raw) { ++ struct inode_operations *op = nd.dentry->d_inode->i_op; ++ error = op->mkdir_raw(&nd, mode); ++ /* the file system wants to use normal vfs path now */ ++ if (error != -EOPNOTSUPP) ++ goto out2; ++ } ++ dentry = lookup_create(&nd, 1, NULL); + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + if (!IS_POSIXACL(nd.dentry->d_inode)) +@@ -1380,6 +1529,7 @@ + dput(dentry); + } + up(&nd.dentry->d_inode->i_sem); ++out2: + path_release(&nd); + out: + putname(tmp); +@@ -1480,8 +1630,16 @@ + error = -EBUSY; + goto exit1; + } ++ if (nd.dentry->d_inode->i_op->rmdir_raw) { ++ struct inode_operations *op = nd.dentry->d_inode->i_op; ++ ++ error = op->rmdir_raw(&nd); ++ /* the file system wants to use normal vfs path now */ ++ if (error != -EOPNOTSUPP) ++ goto exit1; ++ } + down(&nd.dentry->d_inode->i_sem); +- dentry = lookup_hash(&nd.last, nd.dentry); ++ dentry = lookup_hash_it(&nd.last, nd.dentry, NULL); + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + error = vfs_rmdir(nd.dentry->d_inode, dentry); +@@ -1539,8 +1697,15 @@ + error = -EISDIR; + if (nd.last_type != LAST_NORM) + goto exit1; ++ if (nd.dentry->d_inode->i_op->unlink_raw) { ++ struct inode_operations *op = nd.dentry->d_inode->i_op; ++ error = op->unlink_raw(&nd); ++ /* the file system wants to use normal vfs path now */ ++ if (error != -EOPNOTSUPP) ++ goto exit1; ++ } + down(&nd.dentry->d_inode->i_sem); +- dentry = lookup_hash(&nd.last, nd.dentry); ++ dentry = lookup_hash_it(&nd.last, nd.dentry, NULL); + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + /* Why not before? Because we want correct error value */ +@@ -1607,15 +1772,23 @@ + error = path_lookup(to, LOOKUP_PARENT, &nd); + if (error) + goto out; +- dentry = lookup_create(&nd, 0); ++ if (nd.dentry->d_inode->i_op->symlink_raw) { ++ struct inode_operations *op = nd.dentry->d_inode->i_op; ++ error = op->symlink_raw(&nd, from); ++ /* the file system wants to use normal vfs path now */ ++ if (error != -EOPNOTSUPP) ++ goto out2; ++ } ++ dentry = lookup_create(&nd, 0, NULL); + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + error = vfs_symlink(nd.dentry->d_inode, dentry, from); + dput(dentry); + } + up(&nd.dentry->d_inode->i_sem); ++ out2: + path_release(&nd); +-out: ++ out: + putname(to); + } + putname(from); +@@ -1691,7 +1864,14 @@ + error = -EXDEV; + if (old_nd.mnt != nd.mnt) + goto out_release; +- new_dentry = lookup_create(&nd, 0); ++ if (nd.dentry->d_inode->i_op->link_raw) { ++ struct inode_operations *op = nd.dentry->d_inode->i_op; ++ error = op->link_raw(&old_nd, &nd); ++ /* the file system wants to use normal vfs path now */ ++ if (error != -EOPNOTSUPP) ++ goto out_release; ++ } ++ new_dentry = lookup_create(&nd, 0, NULL); + error = PTR_ERR(new_dentry); + if (!IS_ERR(new_dentry)) { + error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry); +@@ -1735,7 +1915,7 @@ + * locking]. + */ + int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, +- struct inode *new_dir, struct dentry *new_dentry) ++ struct inode *new_dir, struct dentry *new_dentry) + { + int error; + struct inode *target; +@@ -1814,7 +1994,7 @@ + } + + int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, +- struct inode *new_dir, struct dentry *new_dentry) ++ struct inode *new_dir, struct dentry *new_dentry) + { + int error; + +@@ -1902,9 +2082,18 @@ + if (newnd.last_type != LAST_NORM) + goto exit2; + ++ if (old_dir->d_inode->i_op->rename_raw) { ++ lock_kernel(); ++ error = old_dir->d_inode->i_op->rename_raw(&oldnd, &newnd); ++ unlock_kernel(); ++ /* the file system wants to use normal vfs path now */ ++ if (error != -EOPNOTSUPP) ++ goto exit2; ++ } ++ + double_lock(new_dir, old_dir); + +- old_dentry = lookup_hash(&oldnd.last, old_dir); ++ old_dentry = lookup_hash_it(&oldnd.last, old_dir, NULL); + error = PTR_ERR(old_dentry); + if (IS_ERR(old_dentry)) + goto exit3; +@@ -1920,16 +2109,16 @@ + if (newnd.last.name[newnd.last.len]) + goto exit4; + } +- new_dentry = lookup_hash(&newnd.last, new_dir); ++ new_dentry = lookup_hash_it(&newnd.last, new_dir, NULL); + error = PTR_ERR(new_dentry); + if (IS_ERR(new_dentry)) + goto exit4; + ++ + lock_kernel(); + error = vfs_rename(old_dir->d_inode, old_dentry, + new_dir->d_inode, new_dentry); + unlock_kernel(); +- + dput(new_dentry); + exit4: + dput(old_dentry); +@@ -1980,20 +2169,26 @@ + } + + static inline int +-__vfs_follow_link(struct nameidata *nd, const char *link) ++__vfs_follow_link(struct nameidata *nd, const char *link, ++ struct lookup_intent *it) + { + int res = 0; + char *name; + if (IS_ERR(link)) + goto fail; + ++ if (it == NULL) ++ it = nd->intent; ++ else if (it != nd->intent) ++ printk("it != nd->intent: tell phil@clusterfs.com\n"); ++ + if (*link == '/') { + path_release(nd); + if (!walk_init_root(link, nd)) + /* weird __emul_prefix() stuff did it */ + goto out; + } +- res = __link_path_walk(link, nd); ++ res = __link_path_walk_it(link, nd, it); + out: + if (current->link_count || res || nd->last_type!=LAST_NORM) + return res; +@@ -2017,7 +2212,13 @@ + + int vfs_follow_link(struct nameidata *nd, const char *link) + { +- return __vfs_follow_link(nd, link); ++ return __vfs_follow_link(nd, link, NULL); ++} ++ ++int vfs_follow_link_it(struct nameidata *nd, const char *link, ++ struct lookup_intent *it) ++{ ++ return __vfs_follow_link(nd, link, it); + } + + /* get the link contents into pagecache */ +@@ -2059,7 +2260,7 @@ + { + struct page *page = NULL; + char *s = page_getlink(dentry, &page); +- int res = __vfs_follow_link(nd, s); ++ int res = __vfs_follow_link(nd, s, NULL); + if (page) { + kunmap(page); + page_cache_release(page); +Index: linux-2.4.21-suse2/fs/namespace.c +=================================================================== +--- linux-2.4.21-suse2.orig/fs/namespace.c 2003-10-28 21:34:12.000000000 +0300 ++++ linux-2.4.21-suse2/fs/namespace.c 2004-01-10 12:15:41.000000000 +0300 +@@ -98,6 +98,7 @@ + { + old_nd->dentry = mnt->mnt_mountpoint; + old_nd->mnt = mnt->mnt_parent; ++ UNPIN(old_nd->dentry, old_nd->mnt, 1); + mnt->mnt_parent = mnt; + mnt->mnt_mountpoint = mnt->mnt_root; + list_del_init(&mnt->mnt_child); +@@ -109,6 +110,7 @@ + { + mnt->mnt_parent = mntget(nd->mnt); + mnt->mnt_mountpoint = dget(nd->dentry); ++ PIN(nd->dentry, nd->mnt, 1); + list_add(&mnt->mnt_hash, mount_hashtable+hash(nd->mnt, nd->dentry)); + list_add(&mnt->mnt_child, &nd->mnt->mnt_mounts); + nd->dentry->d_mounted++; +@@ -488,14 +490,17 @@ + { + struct nameidata old_nd; + struct vfsmount *mnt = NULL; ++ struct lookup_intent it = { .it_op = IT_GETATTR }; + int err = mount_is_safe(nd); + if (err) + return err; + if (!old_name || !*old_name) + return -EINVAL; +- err = path_lookup(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd); +- if (err) ++ err = path_lookup_it(old_name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &old_nd, &it); ++ if (err) { ++ intent_release(&it); + return err; ++ } + + down_write(¤t->namespace->sem); + err = -EINVAL; +@@ -518,6 +523,7 @@ + } + + up_write(¤t->namespace->sem); ++ intent_release(&it); + path_release(&old_nd); + return err; + } +@@ -701,6 +707,7 @@ + unsigned long flags, void *data_page) + { + struct nameidata nd; ++ struct lookup_intent it = { .it_op = IT_GETATTR }; + int retval = 0; + int mnt_flags = 0; + +@@ -725,10 +732,11 @@ + flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV); + + /* ... and get the mountpoint */ +- retval = path_lookup(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd); +- if (retval) ++ retval = path_lookup_it(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd, &it); ++ if (retval) { ++ intent_release(&it); + return retval; +- ++ } + if (flags & MS_REMOUNT) + retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags, + data_page); +@@ -739,6 +747,8 @@ + else + retval = do_add_mount(&nd, type_page, flags, mnt_flags, + dev_name, data_page); ++ ++ intent_release(&it); + path_release(&nd); + return retval; + } +@@ -904,6 +914,8 @@ + { + struct vfsmount *tmp; + struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd; ++ struct lookup_intent new_it = { .it_op = IT_GETATTR }; ++ struct lookup_intent old_it = { .it_op = IT_GETATTR }; + int error; + + if (!capable(CAP_SYS_ADMIN)) +@@ -911,14 +923,14 @@ + + lock_kernel(); + +- error = __user_walk(new_root, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd); ++ error = __user_walk_it(new_root, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd, &new_it); + if (error) + goto out0; + error = -EINVAL; + if (!check_mnt(new_nd.mnt)) + goto out1; + +- error = __user_walk(put_old, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd); ++ error = __user_walk_it(put_old, LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd, &old_it); + if (error) + goto out1; + +@@ -973,8 +985,10 @@ + up(&old_nd.dentry->d_inode->i_zombie); + up_write(¤t->namespace->sem); + path_release(&user_nd); ++ intent_release(&old_it); + path_release(&old_nd); + out1: ++ intent_release(&new_it); + path_release(&new_nd); + out0: + unlock_kernel(); +Index: linux-2.4.21-suse2/fs/open.c +=================================================================== +--- linux-2.4.21-suse2.orig/fs/open.c 2003-10-28 21:33:59.000000000 +0300 ++++ linux-2.4.21-suse2/fs/open.c 2004-01-10 12:15:41.000000000 +0300 +@@ -19,6 +19,8 @@ + #include + + #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) ++extern int path_walk_it(const char *name, struct nameidata *nd, ++ struct lookup_intent *it); + + int vfs_statfs(struct super_block *sb, struct statfs *buf) + { +@@ -95,9 +97,10 @@ + write_unlock(&files->file_lock); + } + +-int do_truncate(struct dentry *dentry, loff_t length) ++int do_truncate(struct dentry *dentry, loff_t length, int called_from_open) + { + struct inode *inode = dentry->d_inode; ++ struct inode_operations *op = dentry->d_inode->i_op; + int error; + struct iattr newattrs; + +@@ -109,7 +112,13 @@ + down(&inode->i_sem); + newattrs.ia_size = length; + newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; +- error = notify_change(dentry, &newattrs); ++ if (called_from_open) ++ newattrs.ia_valid |= ATTR_FROM_OPEN; ++ if (op->setattr_raw) { ++ newattrs.ia_valid |= ATTR_RAW; ++ error = op->setattr_raw(inode, &newattrs); ++ } else ++ error = notify_change(dentry, &newattrs); + up(&inode->i_sem); + up_write(&inode->i_alloc_sem); + return error; +@@ -120,12 +129,13 @@ + struct nameidata nd; + struct inode * inode; + int error; ++ struct lookup_intent it = { .it_op = IT_GETATTR }; + + error = -EINVAL; + if (length < 0) /* sorry, but loff_t says... */ + goto out; + +- error = user_path_walk(path, &nd); ++ error = user_path_walk_it(path, &nd, &it); + if (error) + goto out; + inode = nd.dentry->d_inode; +@@ -165,11 +175,13 @@ + error = locks_verify_truncate(inode, NULL, length); + if (!error) { + DQUOT_INIT(inode); +- error = do_truncate(nd.dentry, length); ++ intent_release(&it); ++ error = do_truncate(nd.dentry, length, 0); + } + put_write_access(inode); + + dput_and_out: ++ intent_release(&it); + path_release(&nd); + out: + return error; +@@ -217,7 +229,7 @@ + + error = locks_verify_truncate(inode, file, length); + if (!error) +- error = do_truncate(dentry, length); ++ error = do_truncate(dentry, length, 0); + out_putf: + fput(file); + out: +@@ -262,11 +274,13 @@ + struct inode * inode; + struct iattr newattrs; + +- error = user_path_walk(filename, &nd); ++ error = user_path_walk_it(filename, &nd, NULL); + if (error) + goto out; + inode = nd.dentry->d_inode; + ++ /* this is safe without a Lustre lock because it only depends ++ on the super block */ + error = -EROFS; + if (IS_RDONLY(inode)) + goto dput_and_out; +@@ -281,11 +295,25 @@ + goto dput_and_out; + + newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; +- } else { ++ } ++ ++ if (inode->i_op->setattr_raw) { ++ struct inode_operations *op = nd.dentry->d_inode->i_op; ++ ++ newattrs.ia_valid |= ATTR_RAW; ++ error = op->setattr_raw(inode, &newattrs); ++ /* the file system wants to use normal vfs path now */ ++ if (error != -EOPNOTSUPP) ++ goto dput_and_out; ++ } ++ ++ error = -EPERM; ++ if (!times) { + if (current->fsuid != inode->i_uid && + (error = permission(inode,MAY_WRITE)) != 0) + goto dput_and_out; + } ++ + error = notify_change(nd.dentry, &newattrs); + dput_and_out: + path_release(&nd); +@@ -306,12 +334,14 @@ + struct inode * inode; + struct iattr newattrs; + +- error = user_path_walk(filename, &nd); ++ error = user_path_walk_it(filename, &nd, NULL); + + if (error) + goto out; + inode = nd.dentry->d_inode; + ++ /* this is safe without a Lustre lock because it only depends ++ on the super block */ + error = -EROFS; + if (IS_RDONLY(inode)) + goto dput_and_out; +@@ -326,7 +356,20 @@ + newattrs.ia_atime = times[0].tv_sec; + newattrs.ia_mtime = times[1].tv_sec; + newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; +- } else { ++ } ++ ++ if (inode->i_op->setattr_raw) { ++ struct inode_operations *op = nd.dentry->d_inode->i_op; ++ ++ newattrs.ia_valid |= ATTR_RAW; ++ error = op->setattr_raw(inode, &newattrs); ++ /* the file system wants to use normal vfs path now */ ++ if (error != -EOPNOTSUPP) ++ goto dput_and_out; ++ } ++ ++ error = -EPERM; ++ if (!utimes) { + if (current->fsuid != inode->i_uid && + (error = permission(inode,MAY_WRITE)) != 0) + goto dput_and_out; +@@ -349,6 +392,7 @@ + int old_fsuid, old_fsgid; + kernel_cap_t old_cap; + int res; ++ struct lookup_intent it = { .it_op = IT_GETATTR }; + + if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ + return -EINVAL; +@@ -366,13 +410,14 @@ + else + current->cap_effective = current->cap_permitted; + +- res = user_path_walk(filename, &nd); ++ res = user_path_walk_it(filename, &nd, &it); + if (!res) { + res = permission(nd.dentry->d_inode, mode); + /* SuS v2 requires we report a read only fs too */ + if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode) + && !special_file(nd.dentry->d_inode->i_mode)) + res = -EROFS; ++ intent_release(&it); + path_release(&nd); + } + +@@ -387,8 +432,9 @@ + { + int error; + struct nameidata nd; ++ struct lookup_intent it = { .it_op = IT_GETATTR }; + +- error = __user_walk(filename,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd); ++ error = __user_walk_it(filename,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd, &it); + if (error) + goto out; + +@@ -399,6 +445,7 @@ + set_fs_pwd(current->fs, nd.mnt, nd.dentry); + + dput_and_out: ++ intent_release(&it); + path_release(&nd); + out: + return error; +@@ -438,9 +485,10 @@ + { + int error; + struct nameidata nd; ++ struct lookup_intent it = { .it_op = IT_GETATTR }; + +- error = __user_walk(filename, LOOKUP_POSITIVE | LOOKUP_FOLLOW | +- LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd); ++ error = __user_walk_it(filename, LOOKUP_POSITIVE | LOOKUP_FOLLOW | ++ LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd, &it); + if (error) + goto out; + +@@ -456,39 +504,56 @@ + set_fs_altroot(); + error = 0; + dput_and_out: ++ intent_release(&it); + path_release(&nd); + out: + return error; + } + +-asmlinkage long sys_fchmod(unsigned int fd, mode_t mode) ++int chmod_common(struct dentry *dentry, mode_t mode) + { +- struct inode * inode; +- struct dentry * dentry; +- struct file * file; +- int err = -EBADF; ++ struct inode *inode = dentry->d_inode; + struct iattr newattrs; ++ int err = -EROFS; + +- file = fget(fd); +- if (!file) ++ if (IS_RDONLY(inode)) + goto out; + +- dentry = file->f_dentry; +- inode = dentry->d_inode; ++ if (inode->i_op->setattr_raw) { ++ newattrs.ia_mode = mode; ++ newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; ++ newattrs.ia_valid |= ATTR_RAW; ++ err = inode->i_op->setattr_raw(inode, &newattrs); ++ /* the file system wants to use normal vfs path now */ ++ if (err != -EOPNOTSUPP) ++ goto out; ++ } + +- err = -EROFS; +- if (IS_RDONLY(inode)) +- goto out_putf; + err = -EPERM; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) +- goto out_putf; ++ goto out; ++ + if (mode == (mode_t) -1) + mode = inode->i_mode; + newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); + newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; + err = notify_change(dentry, &newattrs); + +-out_putf: ++out: ++ return err; ++} ++ ++asmlinkage long sys_fchmod(unsigned int fd, mode_t mode) ++{ ++ struct file * file; ++ int err = -EBADF; ++ ++ file = fget(fd); ++ if (!file) ++ goto out; ++ ++ err = chmod_common(file->f_dentry, mode); ++ + fput(file); + out: + return err; +@@ -497,30 +562,14 @@ + asmlinkage long sys_chmod(const char * filename, mode_t mode) + { + struct nameidata nd; +- struct inode * inode; + int error; +- struct iattr newattrs; + + error = user_path_walk(filename, &nd); + if (error) + goto out; +- inode = nd.dentry->d_inode; +- +- error = -EROFS; +- if (IS_RDONLY(inode)) +- goto dput_and_out; + +- error = -EPERM; +- if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) +- goto dput_and_out; ++ error = chmod_common(nd.dentry, mode); + +- if (mode == (mode_t) -1) +- mode = inode->i_mode; +- newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); +- newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; +- error = notify_change(nd.dentry, &newattrs); +- +-dput_and_out: + path_release(&nd); + out: + return error; +@@ -540,6 +589,20 @@ + error = -EROFS; + if (IS_RDONLY(inode)) + goto out; ++ ++ if (inode->i_op->setattr_raw) { ++ struct inode_operations *op = dentry->d_inode->i_op; ++ ++ newattrs.ia_uid = user; ++ newattrs.ia_gid = group; ++ newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME; ++ newattrs.ia_valid |= ATTR_RAW; ++ error = op->setattr_raw(inode, &newattrs); ++ /* the file system wants to use normal vfs path now */ ++ if (error != -EOPNOTSUPP) ++ return error; ++ } ++ + error = -EPERM; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + goto out; +@@ -644,6 +707,7 @@ + { + int namei_flags, error; + struct nameidata nd; ++ struct lookup_intent it = { .it_op = IT_OPEN }; + + namei_flags = flags; + if ((namei_flags+1) & O_ACCMODE) +@@ -651,14 +715,15 @@ + if (namei_flags & O_TRUNC) + namei_flags |= 2; + +- error = open_namei(filename, namei_flags, mode, &nd); +- if (!error) +- return dentry_open(nd.dentry, nd.mnt, flags); ++ error = open_namei_it(filename, namei_flags, mode, &nd, &it); ++ if (error) ++ return ERR_PTR(error); + +- return ERR_PTR(error); ++ return dentry_open_it(nd.dentry, nd.mnt, flags, &it); + } + +-struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) ++struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt, ++ int flags, struct lookup_intent *it) + { + struct file * f; + struct inode *inode; +@@ -686,7 +751,9 @@ + file_move(f, &inode->i_sb->s_files); + + if (f->f_op && f->f_op->open) { ++ f->f_it = it; + error = f->f_op->open(inode,f); ++ f->f_it = NULL; + if (error) + goto cleanup_all; + } +@@ -698,6 +765,7 @@ + !inode->i_mapping->a_ops->direct_IO)) + goto cleanup_all; + ++ intent_release(it); + return f; + + cleanup_all: +@@ -710,11 +778,17 @@ + cleanup_file: + put_filp(f); + cleanup_dentry: ++ intent_release(it); + dput(dentry); + mntput(mnt); + return ERR_PTR(error); + } + ++struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) ++{ ++ return dentry_open_it(dentry, mnt, flags, NULL); ++} ++ + /* + * Find an empty file descriptor entry, and mark it busy. + */ +Index: linux-2.4.21-suse2/fs/stat.c +=================================================================== +--- linux-2.4.21-suse2.orig/fs/stat.c 2003-10-28 21:33:58.000000000 +0300 ++++ linux-2.4.21-suse2/fs/stat.c 2004-01-10 12:15:41.000000000 +0300 +@@ -17,10 +17,14 @@ + * Revalidate the inode. This is required for proper NFS attribute caching. + */ + static __inline__ int +-do_revalidate(struct dentry *dentry) ++do_revalidate(struct dentry *dentry, struct lookup_intent *it) + { + struct inode * inode = dentry->d_inode; +- if (inode->i_op && inode->i_op->revalidate) ++ if (!inode) ++ return -ENOENT; ++ if (inode->i_op && inode->i_op->revalidate_it) ++ return inode->i_op->revalidate_it(dentry, it); ++ else if (inode->i_op && inode->i_op->revalidate) + return inode->i_op->revalidate(dentry); + return 0; + } +@@ -141,13 +145,15 @@ + asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf) + { + struct nameidata nd; ++ struct lookup_intent it = { .it_op = IT_GETATTR }; + int error; + +- error = user_path_walk(filename, &nd); ++ error = user_path_walk_it(filename, &nd, &it); + if (!error) { +- error = do_revalidate(nd.dentry); ++ error = do_revalidate(nd.dentry, &it); + if (!error) + error = cp_old_stat(nd.dentry->d_inode, statbuf); ++ intent_release(&it); + path_release(&nd); + } + return error; +@@ -157,13 +163,15 @@ + asmlinkage long sys_newstat(char * filename, struct stat * statbuf) + { + struct nameidata nd; ++ struct lookup_intent it = { .it_op = IT_GETATTR }; + int error; + +- error = user_path_walk(filename, &nd); ++ error = user_path_walk_it(filename, &nd, &it); + if (!error) { +- error = do_revalidate(nd.dentry); ++ error = do_revalidate(nd.dentry, &it); + if (!error) + error = cp_new_stat(nd.dentry->d_inode, statbuf); ++ intent_release(&it); + path_release(&nd); + } + return error; +@@ -178,13 +186,15 @@ + asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf) + { + struct nameidata nd; ++ struct lookup_intent it = { .it_op = IT_GETATTR }; + int error; + +- error = user_path_walk_link(filename, &nd); ++ error = user_path_walk_link_it(filename, &nd, &it); + if (!error) { +- error = do_revalidate(nd.dentry); ++ error = do_revalidate(nd.dentry, &it); + if (!error) + error = cp_old_stat(nd.dentry->d_inode, statbuf); ++ intent_release(&it); + path_release(&nd); + } + return error; +@@ -195,13 +205,15 @@ + asmlinkage long sys_newlstat(char * filename, struct stat * statbuf) + { + struct nameidata nd; ++ struct lookup_intent it = { .it_op = IT_GETATTR }; + int error; + +- error = user_path_walk_link(filename, &nd); ++ error = user_path_walk_link_it(filename, &nd, &it); + if (!error) { +- error = do_revalidate(nd.dentry); ++ error = do_revalidate(nd.dentry, &it); + if (!error) + error = cp_new_stat(nd.dentry->d_inode, statbuf); ++ intent_release(&it); + path_release(&nd); + } + return error; +@@ -222,7 +234,7 @@ + if (f) { + struct dentry * dentry = f->f_dentry; + +- err = do_revalidate(dentry); ++ err = do_revalidate(dentry, NULL); + if (!err) + err = cp_old_stat(dentry->d_inode, statbuf); + fput(f); +@@ -241,7 +253,7 @@ + if (f) { + struct dentry * dentry = f->f_dentry; + +- err = do_revalidate(dentry); ++ err = do_revalidate(dentry, NULL); + if (!err) + err = cp_new_stat(dentry->d_inode, statbuf); + fput(f); +@@ -263,7 +275,7 @@ + + error = -EINVAL; + if (inode->i_op && inode->i_op->readlink && +- !(error = do_revalidate(nd.dentry))) { ++ !(error = do_revalidate(nd.dentry, NULL))) { + UPDATE_ATIME(inode); + error = inode->i_op->readlink(nd.dentry, buf, bufsiz); + } +@@ -339,12 +351,14 @@ + { + struct nameidata nd; + int error; ++ struct lookup_intent it = { .it_op = IT_GETATTR }; + +- error = user_path_walk(filename, &nd); ++ error = user_path_walk_it(filename, &nd, &it); + if (!error) { +- error = do_revalidate(nd.dentry); ++ error = do_revalidate(nd.dentry, &it); + if (!error) + error = cp_new_stat64(nd.dentry->d_inode, statbuf); ++ intent_release(&it); + path_release(&nd); + } + return error; +@@ -354,12 +368,14 @@ + { + struct nameidata nd; + int error; ++ struct lookup_intent it = { .it_op = IT_GETATTR }; + +- error = user_path_walk_link(filename, &nd); ++ error = user_path_walk_link_it(filename, &nd, &it); + if (!error) { +- error = do_revalidate(nd.dentry); ++ error = do_revalidate(nd.dentry, &it); + if (!error) + error = cp_new_stat64(nd.dentry->d_inode, statbuf); ++ intent_release(&it); + path_release(&nd); + } + return error; +@@ -374,7 +390,7 @@ + if (f) { + struct dentry * dentry = f->f_dentry; + +- err = do_revalidate(dentry); ++ err = do_revalidate(dentry, NULL); + if (!err) + err = cp_new_stat64(dentry->d_inode, statbuf); + fput(f); +Index: linux-2.4.21-suse2/include/linux/dcache.h +=================================================================== +--- linux-2.4.21-suse2.orig/include/linux/dcache.h 2003-11-11 03:44:28.000000000 +0300 ++++ linux-2.4.21-suse2/include/linux/dcache.h 2004-01-10 12:15:41.000000000 +0300 +@@ -7,6 +7,51 @@ + #include + #include + #include ++#include ++ ++#define IT_OPEN 0x0001 ++#define IT_CREAT 0x0002 ++#define IT_READDIR 0x0004 ++#define IT_GETATTR 0x0008 ++#define IT_LOOKUP 0x0010 ++#define IT_UNLINK 0x0020 ++#define IT_GETXATTR 0x0040 ++#define IT_EXEC 0x0080 ++#define IT_PIN 0x0100 ++ ++#define IT_FL_LOCKED 0x0001 ++#define IT_FL_FOLLOWED 0x0002 /* set by vfs_follow_link */ ++ ++#define INTENT_MAGIC 0x19620323 ++ ++ ++struct lustre_intent_data { ++ int it_disposition; ++ int it_status; ++ __u64 it_lock_handle; ++ void *it_data; ++ int it_lock_mode; ++ int it_int_flags; ++}; ++struct lookup_intent { ++ int it_magic; ++ void (*it_op_release)(struct lookup_intent *); ++ int it_op; ++ int it_flags; ++ int it_create_mode; ++ union { ++ struct lustre_intent_data lustre; ++ } d; ++}; ++ ++static inline void intent_init(struct lookup_intent *it, int op, int flags) ++{ ++ memset(it, 0, sizeof(*it)); ++ it->it_magic = INTENT_MAGIC; ++ it->it_op = op; ++ it->it_flags = flags; ++} ++ + + /* + * linux/include/linux/dcache.h +@@ -94,8 +139,22 @@ + int (*d_delete)(struct dentry *); + void (*d_release)(struct dentry *); + void (*d_iput)(struct dentry *, struct inode *); ++ int (*d_revalidate_it)(struct dentry *, int, struct lookup_intent *); ++ void (*d_pin)(struct dentry *, struct vfsmount * , int); ++ void (*d_unpin)(struct dentry *, struct vfsmount *, int); + }; + ++#define PIN(de,mnt,flag) if (de->d_op && de->d_op->d_pin) \ ++ de->d_op->d_pin(de, mnt, flag); ++#define UNPIN(de,mnt,flag) if (de->d_op && de->d_op->d_unpin) \ ++ de->d_op->d_unpin(de, mnt, flag); ++ ++ ++/* defined in fs/namei.c */ ++extern void intent_release(struct lookup_intent *it); ++/* defined in fs/dcache.c */ ++extern void __d_rehash(struct dentry * entry, int lock); ++ + /* the dentry parameter passed to d_hash and d_compare is the parent + * directory of the entries to be compared. It is used in case these + * functions need any directory specific information for determining +@@ -127,6 +186,7 @@ + * s_nfsd_free_path semaphore will be down + */ + #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ ++#define DCACHE_LUSTRE_INVALID 0x0010 /* Lustre invalidated */ + + extern spinlock_t dcache_lock; + +Index: linux-2.4.21-suse2/include/linux/fs.h +=================================================================== +--- linux-2.4.21-suse2.orig/include/linux/fs.h 2004-01-10 11:28:05.000000000 +0300 ++++ linux-2.4.21-suse2/include/linux/fs.h 2004-01-10 12:15:41.000000000 +0300 +@@ -74,6 +74,7 @@ + + #define FMODE_READ 1 + #define FMODE_WRITE 2 ++#define FMODE_EXEC 4 + + #define READ 0 + #define WRITE 1 +@@ -361,6 +362,9 @@ + #define ATTR_MTIME_SET 256 + #define ATTR_FORCE 512 /* Not a change, but a change it */ + #define ATTR_ATTR_FLAG 1024 ++#define ATTR_RAW 0x0800 /* file system, not vfs will massage attrs */ ++#define ATTR_FROM_OPEN 0x1000 /* called from open path, ie O_TRUNC */ ++#define ATTR_CTIME_SET 0x2000 + + /* + * This is the Inode Attributes structure, used for notify_change(). It +@@ -505,6 +509,7 @@ + struct pipe_inode_info *i_pipe; + struct block_device *i_bdev; + struct char_device *i_cdev; ++ void *i_filterdata; + + unsigned long i_dnotify_mask; /* Directory notify events */ + struct dnotify_struct *i_dnotify; /* for directory notifications */ +@@ -667,6 +672,7 @@ + + /* needed for tty driver, and maybe others */ + void *private_data; ++ struct lookup_intent *f_it; + struct list_head f_ep_links; + spinlock_t f_ep_lock; + }; +@@ -796,6 +802,7 @@ + struct qstr last; + unsigned int flags; + int last_type; ++ struct lookup_intent *intent; + }; + + /* +@@ -917,7 +924,8 @@ + extern int __vfs_rmdir(struct inode *, struct dentry *); + extern int vfs_rmdir(struct inode *, struct dentry *); + extern int vfs_unlink(struct inode *, struct dentry *); +-extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); ++int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, ++ struct inode *new_dir, struct dentry *new_dentry); + + /* + * File types +@@ -992,21 +1000,32 @@ + + struct inode_operations { + int (*create) (struct inode *,struct dentry *,int); ++ int (*create_it) (struct inode *,struct dentry *,int, struct lookup_intent *); + struct dentry * (*lookup) (struct inode *,struct dentry *); ++ struct dentry * (*lookup_it) (struct inode *,struct dentry *, struct lookup_intent *, int flags); + int (*link) (struct dentry *,struct inode *,struct dentry *); ++ int (*link_raw) (struct nameidata *,struct nameidata *); + int (*unlink) (struct inode *,struct dentry *); ++ int (*unlink_raw) (struct nameidata *); + int (*symlink) (struct inode *,struct dentry *,const char *); ++ int (*symlink_raw) (struct nameidata *,const char *); + int (*mkdir) (struct inode *,struct dentry *,int); ++ int (*mkdir_raw) (struct nameidata *,int); + int (*rmdir) (struct inode *,struct dentry *); ++ int (*rmdir_raw) (struct nameidata *); + int (*mknod) (struct inode *,struct dentry *,int,int); ++ int (*mknod_raw) (struct nameidata *,int,dev_t); + int (*rename) (struct inode *, struct dentry *, + struct inode *, struct dentry *); ++ int (*rename_raw) (struct nameidata *, struct nameidata *); + int (*readlink) (struct dentry *, char *,int); + int (*follow_link) (struct dentry *, struct nameidata *); + void (*truncate) (struct inode *); + int (*permission) (struct inode *, int); + int (*revalidate) (struct dentry *); ++ int (*revalidate_it) (struct dentry *, struct lookup_intent *); + int (*setattr) (struct dentry *, struct iattr *); ++ int (*setattr_raw) (struct inode *, struct iattr *); + int (*getattr) (struct dentry *, struct iattr *); + int (*setxattr) (struct dentry *, const char *, const void *, size_t, int); + ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); +@@ -1205,10 +1224,14 @@ + + asmlinkage long sys_open(const char *, int, int); + asmlinkage long sys_close(unsigned int); /* yes, it's really unsigned */ +-extern int do_truncate(struct dentry *, loff_t start); ++extern int do_truncate(struct dentry *, loff_t start, int called_from_open); + + extern struct file *filp_open(const char *, int, int); + extern struct file * dentry_open(struct dentry *, struct vfsmount *, int); ++extern int open_namei_it(const char *filename, int namei_flags, int mode, ++ struct nameidata *nd, struct lookup_intent *it); ++extern struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt, ++ int flags, struct lookup_intent *it); + extern int filp_close(struct file *, fl_owner_t id); + extern char * getname(const char *); + +@@ -1504,6 +1527,7 @@ + extern loff_t default_llseek(struct file *file, loff_t offset, int origin); + + extern int FASTCALL(__user_walk(const char *, unsigned, struct nameidata *)); ++extern int FASTCALL(__user_walk_it(const char *, unsigned, struct nameidata *, struct lookup_intent *it)); + extern int FASTCALL(path_init(const char *, unsigned, struct nameidata *)); + extern int FASTCALL(path_walk(const char *, struct nameidata *)); + extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *)); +@@ -1516,6 +1540,8 @@ + extern struct dentry * lookup_hash(struct qstr *, struct dentry *); + #define user_path_walk(name,nd) __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd) + #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd) ++#define user_path_walk_it(name,nd,it) __user_walk_it(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd, it) ++#define user_path_walk_link_it(name,nd,it) __user_walk_it(name, LOOKUP_POSITIVE, nd, it) + + extern void inode_init_once(struct inode *); + extern void _inode_init_once(struct inode *); +@@ -1667,6 +1693,8 @@ + + extern int vfs_readlink(struct dentry *, char *, int, const char *); + extern int vfs_follow_link(struct nameidata *, const char *); ++extern int vfs_follow_link_it(struct nameidata *, const char *, ++ struct lookup_intent *it); + extern int page_readlink(struct dentry *, char *, int); + extern int page_follow_link(struct dentry *, struct nameidata *); + extern struct inode_operations page_symlink_inode_operations; +Index: linux-2.4.21-suse2/include/linux/fs_struct.h +=================================================================== +--- linux-2.4.21-suse2.orig/include/linux/fs_struct.h 2001-07-14 02:10:44.000000000 +0400 ++++ linux-2.4.21-suse2/include/linux/fs_struct.h 2004-01-10 12:15:41.000000000 +0300 +@@ -34,10 +34,12 @@ + write_lock(&fs->lock); + old_root = fs->root; + old_rootmnt = fs->rootmnt; ++ PIN(dentry, mnt, 1); + fs->rootmnt = mntget(mnt); + fs->root = dget(dentry); + write_unlock(&fs->lock); + if (old_root) { ++ UNPIN(old_root, old_rootmnt, 1); + dput(old_root); + mntput(old_rootmnt); + } +@@ -57,10 +59,12 @@ + write_lock(&fs->lock); + old_pwd = fs->pwd; + old_pwdmnt = fs->pwdmnt; ++ PIN(dentry, mnt, 0); + fs->pwdmnt = mntget(mnt); + fs->pwd = dget(dentry); + write_unlock(&fs->lock); + if (old_pwd) { ++ UNPIN(old_pwd, old_pwdmnt, 0); + dput(old_pwd); + mntput(old_pwdmnt); + } +Index: linux-2.4.21-suse2/kernel/exit.c +=================================================================== +--- linux-2.4.21-suse2.orig/kernel/exit.c 2003-10-28 21:34:13.000000000 +0300 ++++ linux-2.4.21-suse2/kernel/exit.c 2004-01-10 12:15:41.000000000 +0300 +@@ -288,11 +288,14 @@ + { + /* No need to hold fs->lock if we are killing it */ + if (atomic_dec_and_test(&fs->count)) { ++ UNPIN(fs->pwd, fs->pwdmnt, 0); ++ UNPIN(fs->root, fs->rootmnt, 1); + dput(fs->root); + mntput(fs->rootmnt); + dput(fs->pwd); + mntput(fs->pwdmnt); + if (fs->altroot) { ++ UNPIN(fs->altroot, fs->altrootmnt, 1); + dput(fs->altroot); + mntput(fs->altrootmnt); + } +Index: linux-2.4.21-suse2/kernel/fork.c +=================================================================== +--- linux-2.4.21-suse2.orig/kernel/fork.c 2003-10-28 21:34:17.000000000 +0300 ++++ linux-2.4.21-suse2/kernel/fork.c 2004-01-10 12:15:41.000000000 +0300 +@@ -461,10 +461,13 @@ + fs->umask = old->umask; + read_lock(&old->lock); + fs->rootmnt = mntget(old->rootmnt); ++ PIN(old->pwd, old->pwdmnt, 0); ++ PIN(old->root, old->rootmnt, 1); + fs->root = dget(old->root); + fs->pwdmnt = mntget(old->pwdmnt); + fs->pwd = dget(old->pwd); + if (old->altroot) { ++ PIN(old->altroot, old->altrootmnt, 1); + fs->altrootmnt = mntget(old->altrootmnt); + fs->altroot = dget(old->altroot); + } else { +Index: linux-2.4.21-suse2/kernel/ksyms.c +=================================================================== +--- linux-2.4.21-suse2.orig/kernel/ksyms.c 2004-01-10 11:28:05.000000000 +0300 ++++ linux-2.4.21-suse2/kernel/ksyms.c 2004-01-10 12:15:41.000000000 +0300 +@@ -327,6 +327,7 @@ + EXPORT_SYMBOL(set_page_dirty); + EXPORT_SYMBOL(vfs_readlink); + EXPORT_SYMBOL(vfs_follow_link); ++EXPORT_SYMBOL(vfs_follow_link_it); + EXPORT_SYMBOL(page_readlink); + EXPORT_SYMBOL(page_follow_link); + EXPORT_SYMBOL(page_symlink_inode_operations); diff --git a/lustre/kernel_patches/series/suse-2.4.21-2 b/lustre/kernel_patches/series/suse-2.4.21-2 new file mode 100644 index 0000000..337a7df --- /dev/null +++ b/lustre/kernel_patches/series/suse-2.4.21-2 @@ -0,0 +1,30 @@ +configurable-x86-stack-2.4.21-suse2.patch +dev_read_only_2.4.20-rh.patch +exports_2.4.20-rh-hp.patch +lustre_version.patch +vfs_intent-2.4.21-suse2.patch +invalidate_show.patch +export-truncate.patch +iod-stock-24-exports_hp.patch +ext3-htree-2.4.21-chaos.patch +linux-2.4.21-xattr-0.8.54-suse2.patch +ext3-orphan_lock-2.4.22-rh.patch +ext3-noread-2.4.21-suse2.patch +ext3-delete_thread-2.4.21-chaos.patch +extN-wantedi-2.4.21-suse2.patch +ext3-san-2.4.20.patch +ext3-map_inode_page-2.4.21-suse2.patch +ext3-error-export.patch +iopen-2.4.19-suse.patch +tcp-zero-copy-2.4.21-suse2.patch +jbd-dont-account-blocks-twice.patch +jbd-commit-tricks.patch +ext3-no-write-super-chaos.patch +add_page_private.patch +nfs_export_kernel-2.4.21-suse2.patch +ext3-raw-lookup.patch +ext3-ea-in-inode-2.4.21-suse2.patch +listman-2.4.20.patch +gfp_memalloc-2.4.24.patch +ext3-xattr-ptr-arith-fix.patch +kernel_text_address-2.4.20-vanilla.patch -- 1.8.3.1