diff -Nru linux-old/arch/i386/config.in linux-new/arch/i386/config.in
--- linux-old/arch/i386/config.in	2002-10-23 21:21:29.000000000 -0400
+++ linux-new/arch/i386/config.in	2002-10-23 22:14:44.000000000 -0400
@@ -80,6 +80,7 @@
    define_bool CONFIG_X86_F00F_WORKS_OK n
 fi
 if [ "$CONFIG_M586" = "y" ]; then
+   define_bool CONFIG_X86_CMPXCHG8 y
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
@@ -87,6 +88,7 @@
    define_bool CONFIG_X86_F00F_WORKS_OK n
 fi
 if [ "$CONFIG_M586TSC" = "y" ]; then
+   define_bool CONFIG_X86_CMPXCHG8 y
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
@@ -95,6 +97,7 @@
    define_bool CONFIG_X86_F00F_WORKS_OK n
 fi
 if [ "$CONFIG_M586MMX" = "y" ]; then
+   define_bool CONFIG_X86_CMPXCHG8 y
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
@@ -104,6 +107,7 @@
    define_bool CONFIG_X86_F00F_WORKS_OK n
 fi
 if [ "$CONFIG_M586MMX31" = "y" ]; then
+   define_bool CONFIG_X86_CMPXCHG8 y
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
@@ -112,6 +116,7 @@
    define_bool CONFIG_X86_PPRO_FENCE y
 fi
 if [ "$CONFIG_M686" = "y" ]; then
+   define_bool CONFIG_X86_CMPXCHG8 y
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
@@ -121,6 +126,7 @@
    define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_M68631" = "y" ]; then
+   define_bool CONFIG_X86_CMPXCHG8 y
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
@@ -129,6 +135,7 @@
    define_bool CONFIG_X86_PPRO_FENCE y
 fi
 if [ "$CONFIG_MPENTIUMIII" = "y" ]; then
+   define_bool CONFIG_X86_CMPXCHG8 y
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
@@ -137,6 +144,7 @@
    define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MPENTIUMIII31" = "y" ]; then
+   define_bool CONFIG_X86_CMPXCHG8 y
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
@@ -144,6 +152,7 @@
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
 if [ "$CONFIG_MPENTIUM4" = "y" ]; then
+   define_bool CONFIG_X86_CMPXCHG8 y
    define_int  CONFIG_X86_L1_CACHE_SHIFT 7
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
@@ -152,6 +161,7 @@
    define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MPENTIUM431" = "y" ]; then
+   define_bool CONFIG_X86_CMPXCHG8 y
    define_int  CONFIG_X86_L1_CACHE_SHIFT 7
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
@@ -159,18 +169,21 @@
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
 if [ "$CONFIG_MK6" = "y" ]; then
+   define_bool CONFIG_X86_CMPXCHG8 y
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
 if [ "$CONFIG_MK6231" = "y" ]; then
+   define_bool CONFIG_X86_CMPXCHG8 y
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
 if [ "$CONFIG_MK7" = "y" ]; then
+   define_bool CONFIG_X86_CMPXCHG8 y
    define_int  CONFIG_X86_L1_CACHE_SHIFT 6
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
@@ -180,6 +193,7 @@
    define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MK731" = "y" ]; then
+   define_bool CONFIG_X86_CMPXCHG8 y
    define_int  CONFIG_X86_L1_CACHE_SHIFT 6
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
@@ -188,6 +202,7 @@
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
 if [ "$CONFIG_MXP31" = "y" ]; then
+   define_bool CONFIG_X86_CMPXCHG8 y
    define_int  CONFIG_X86_L1_CACHE_SHIFT 6
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
@@ -196,6 +211,7 @@
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
 if [ "$CONFIG_MMP31" = "y" ]; then
+   define_bool CONFIG_X86_CMPXCHG8 y
    define_int  CONFIG_X86_L1_CACHE_SHIFT 6
    define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
diff -Nru linux-old/fs/inode.c linux-new/fs/inode.c
--- linux-old/fs/inode.c	2002-10-23 22:05:09.000000000 -0400
+++ linux-new/fs/inode.c	2002-10-23 22:15:22.000000000 -0400
@@ -111,6 +111,7 @@
 		sema_init(&inode->i_sem, 1);
 		sema_init(&inode->i_zombie, 1);
 		spin_lock_init(&inode->i_data.i_shared_lock);
+		i_size_ordered_init(inode);
 	}
 }
 
diff -Nru linux-old/include/asm-i386/bugs.h linux-new/include/asm-i386/bugs.h
--- linux-old/include/asm-i386/bugs.h	2002-10-23 20:54:40.000000000 -0400
+++ linux-new/include/asm-i386/bugs.h	2002-10-23 22:13:40.000000000 -0400
@@ -200,6 +200,11 @@
 	    && (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11))
 		panic("Kernel compiled for PMMX+, assumes a local APIC without the read-before-write bug!");
 #endif
+
+#ifdef CONFIG_X86_CMPXCHG8
+	if (!cpu_has_cx8)
+		panic("Kernel compiled for Pentium+, requires CMPXCHG8B feature!");
+#endif
 }
 
 static void __init check_bugs(void)
diff -Nru linux-old/include/asm-i386/processor.h linux-new/include/asm-i386/processor.h
--- linux-old/include/asm-i386/processor.h	2002-10-23 21:21:29.000000000 -0400
+++ linux-new/include/asm-i386/processor.h	2002-10-23 22:13:40.000000000 -0400
@@ -91,6 +91,7 @@
 #define cpu_has_xmm	(test_bit(X86_FEATURE_XMM,  boot_cpu_data.x86_capability))
 #define cpu_has_fpu	(test_bit(X86_FEATURE_FPU,  boot_cpu_data.x86_capability))
 #define cpu_has_apic	(test_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability))
+#define cpu_has_cx8	(test_bit(X86_FEATURE_CX8, boot_cpu_data.x86_capability))
 
 extern char ignore_irq13;
 
diff -Nru linux-old/include/asm-i386/system.h linux-new/include/asm-i386/system.h
--- linux-old/include/asm-i386/system.h	2002-10-23 20:58:31.000000000 -0400
+++ linux-new/include/asm-i386/system.h	2002-10-23 22:13:40.000000000 -0400
@@ -143,6 +143,8 @@
 #define __xg(x) ((struct __xchg_dummy *)(x))
 
 
+#ifdef CONFIG_X86_CMPXCHG8
+#define __ARCH_HAS_GET_SET_64BIT 1
 /*
  * The semantics of XCHGCMP8B are a bit strange, this is why
  * there is a loop and the loading of %%eax and %%edx has to
@@ -167,7 +169,7 @@
 		"lock cmpxchg8b (%0)\n\t"
 		"jnz 1b"
 		: /* no outputs */
-		:	"D"(ptr),
+		:	"r"(ptr),
 			"b"(low),
 			"c"(high)
 		:	"ax","dx","memory");
@@ -197,6 +199,32 @@
  __set_64bit(ptr, (unsigned int)(value), (unsigned int)((value)>>32ULL) ) : \
  __set_64bit(ptr, ll_low(value), ll_high(value)) )
 
+
+/*
+ * The memory clobber is needed in the read side only if
+ * there is an unsafe writer before the get_64bit, which should
+ * never be the case, but just to be safe.
+ */
+static inline unsigned long long get_64bit(unsigned long long * ptr)
+{
+        unsigned long low, high;
+
+        __asm__ __volatile__ (
+                "\n1:\t"
+                "movl (%2), %%eax\n\t"
+                "movl 4(%2), %%edx\n\t"
+                "movl %%eax, %%ebx\n\t"
+                "movl %%edx, %%ecx\n\t"
+                "lock cmpxchg8b (%2)\n\t"
+                "jnz 1b"
+                : "=&b" (low), "=&c" (high)
+                : "r" (ptr)
+                : "ax","dx","memory");
+
+        return low | ((unsigned long long) high << 32);
+}
+#endif /* CONFIG_X86_CMPXCHG */
+
 /*
  * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
  * Note 2: xchg has side effect, so that attribute volatile is necessary,
diff -Nru linux-old/include/linux/fs.h linux-new/include/linux/fs.h
--- linux-old/include/linux/fs.h	2002-10-23 22:12:52.000000000 -0400
+++ linux-new/include/linux/fs.h	2002-10-23 22:13:40.000000000 -0400
@@ -434,6 +434,13 @@
 	struct list_head	bd_inodes;
 };
 
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP) && !defined(__ARCH_HAS_GET_SET_64BIT)
+#define __NEED_I_SIZE_ORDERED
+#define i_size_ordered_init(inode) do { (inode)->i_size_version1 = (inode)->i_size_version2 = 0; } while (0)
+#else
+#define i_size_ordered_init(inode) do { } while (0)
+#endif
+
 struct inode {
 	struct list_head	i_hash;
 	struct list_head	i_list;
@@ -517,8 +524,65 @@
 		struct jffs2_inode_info		jffs2_i;
 		void				*generic_ip;
 	} u;
+#ifdef __NEED_I_SIZE_ORDERED
+	volatile int		i_size_version1;
+	volatile int		i_size_version2;
+#endif
 };
 
+/*
+ * NOTE: in a 32bit arch with a preemptable kernel and
+ * an UP compile the i_size_read/write must be atomic
+ * with respect to the local cpu (unlike with preempt disabled),
+ * but they don't need to be atomic with respect to other cpus like in
+ * true SMP (so they need either to either locally disable irq around
+ * the read or for example on x86 they can be still implemented as a
+ * cmpxchg8b without the need of the lock prefix). For SMP compiles
+ * and 64bit archs it makes no difference if preempt is enabled or not.
+ */
+static inline loff_t i_size_read(struct inode * inode)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+#ifdef __ARCH_HAS_GET_SET_64BIT
+	return (loff_t) get_64bit((unsigned long long *) &inode->i_size);
+#else
+	loff_t i_size;
+	int v1, v2;
+
+	/* Retry if i_size was possibly modified while sampling. */
+	do {
+		v1 = inode->i_size_version1;
+		rmb();
+		i_size = inode->i_size;
+		rmb();
+		v2 = inode->i_size_version2;
+	} while (v1 != v2);
+
+	return i_size;
+#endif
+#elif BITS_PER_LONG==64 || !defined(CONFIG_SMP)
+	return inode->i_size;
+#endif
+}
+
+static inline void i_size_write(struct inode * inode, loff_t i_size)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+#ifdef __ARCH_HAS_GET_SET_64BIT
+	set_64bit((unsigned long long *) &inode->i_size, (unsigned long long) i_size);
+#else
+	inode->i_size_version2++;
+	wmb();
+	inode->i_size = i_size;
+	wmb();
+	inode->i_size_version1++;
+	wmb(); /* make it visible ASAP */
+#endif
+#elif BITS_PER_LONG==64 || !defined(CONFIG_SMP)
+	inode->i_size = i_size;
+#endif
+}
+
 static inline void inode_add_bytes(struct inode *inode, loff_t bytes)
 {
 	inode->i_blocks += bytes >> 9;
