diff -urN linux-2.4.10/Documentation/Configure.help linux-2.4.10-lia/Documentation/Configure.help
--- linux-2.4.10/Documentation/Configure.help	Mon Sep 24 15:06:08 2001
+++ linux-2.4.10-lia/Documentation/Configure.help	Mon Sep 24 21:34:01 2001
@@ -12680,6 +12690,18 @@
   Say Y here if you would like to be able to read the hard disk
   partition table format used by SGI machines.
 
+Intel EFI GUID partition support
+CONFIG_EFI_PARTITION
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned using EFI GPT.  Presently only useful on the
+  IA-64 platform.
+
+/dev/guid support (EXPERIMENTAL)
+CONFIG_DEVFS_GUID
+  Say Y here if you would like to access disks and partitions by
+  their Globally Unique Identifiers (GUIDs) which will appear as
+  symbolic links in /dev/guid.
+
 Ultrix partition support
 CONFIG_ULTRIX_PARTITION
   Say Y here if you would like to be able to read the hard disk
diff -urN linux-2.4.10/fs/partitions/Config.in linux-2.4.10-lia/fs/partitions/Config.in
--- linux-2.4.10/fs/partitions/Config.in	Mon Aug 20 10:19:20 2001
+++ linux-2.4.10-lia/fs/partitions/Config.in	Mon Aug 20 12:21:01 2001
@@ -24,6 +24,8 @@
       bool '    Minix subpartition support' CONFIG_MINIX_SUBPARTITION
       bool '    Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION
       bool '    Unixware slices support' CONFIG_UNIXWARE_DISKLABEL
+      bool '    EFI GUID Partition support' CONFIG_EFI_PARTITION
+      dep_bool '    /dev/guid support (EXPERIMENTAL)' CONFIG_DEVFS_GUID $CONFIG_DEVFS_FS $CONFIG_EFI_PARTITION
    fi
    dep_bool '  Windows Logical Disk Manager (Dynamic Disk) support' CONFIG_LDM_PARTITION $CONFIG_EXPERIMENTAL
    if [ "$CONFIG_LDM_PARTITION" = "y" ]; then
diff -urN linux-2.4.10/fs/partitions/Makefile linux-2.4.10-lia/fs/partitions/Makefile
--- linux-2.4.10/fs/partitions/Makefile	Thu Jul 26 16:30:04 2001
+++ linux-2.4.10-lia/fs/partitions/Makefile	Mon Aug 13 23:46:06 2001
@@ -24,6 +24,7 @@
 obj-$(CONFIG_SUN_PARTITION) += sun.o
 obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o
 obj-$(CONFIG_IBM_PARTITION) += ibm.o
+obj-$(CONFIG_EFI_PARTITION) += efi.o
 
 include $(TOPDIR)/Rules.make
 
diff -urN linux-2.4.10/fs/partitions/check.c linux-2.4.10-lia/fs/partitions/check.c
--- linux-2.4.10/fs/partitions/check.c	Mon Sep 24 15:08:18 2001
+++ linux-2.4.10-lia/fs/partitions/check.c	Mon Sep 24 15:23:51 2001
@@ -34,6 +34,10 @@
 #include "ibm.h"
 #include "ultrix.h"
 
+#ifdef CONFIG_EFI_PARTITION
+# include "efi.h"
+#endif
+
 extern int *blk_size[];
 
 int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
@@ -42,6 +46,9 @@
 #ifdef CONFIG_ACORN_PARTITION
 	acorn_partition,
 #endif
+#ifdef CONFIG_EFI_PARTITION
+	efi_partition,
+#endif
 #ifdef CONFIG_LDM_PARTITION
 	ldm_partition,		/* this must come before msdos */
 #endif
@@ -75,6 +82,20 @@
 	NULL
 };
 
+#ifdef CONFIG_DEVFS_GUID
+static devfs_handle_t guid_top_handle;
+
+#define GUID_UNPARSED_LEN 36
+static void
+uuid_unparse_1(efi_guid_t *guid, char *out)
+{
+	sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+		guid->data1, guid->data2, guid->data3,
+ 		guid->data4[0], guid->data4[1], guid->data4[2], guid->data4[3],
+		guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]);
+}
+#endif
+
 /*
  *	This is ucking fugly but its probably the best thing for 2.4.x
  *	Take it as a clear reminder than we should put the device name
@@ -288,6 +309,101 @@
 	devfs_register_partitions (hd, i, hd->sizes ? 0 : 1);
 }
 
+#ifdef CONFIG_DEVFS_GUID
+/*
+  devfs_register_guid: create a /dev/guid entry for a disk or partition
+                       if it has a GUID.
+
+  The /dev/guid entry will be a symlink to the "real" devfs device.
+  It is marked as "slave" of the real device,
+  to be automatically unregistered by devfs if that device is unregistered.
+
+  If the partition already had a /dev/guid entry, delete (unregister) it.
+  (If the disk was repartitioned, it's likely the old GUID entry will be wrong).
+
+  dev, minor:  Device for which an entry is to be created.
+
+  Prerequisites: dev->part[minor].guid must be either NULL or point
+                 to a valid kmalloc'ed GUID.
+*/
+
+static void devfs_register_guid (struct gendisk *dev, int minor)
+{
+	efi_guid_t *guid = dev->part[minor].guid;
+	devfs_handle_t guid_handle, slave,
+		real_master = dev->part[minor].de;
+	devfs_handle_t master = real_master;
+	char guid_link[GUID_UNPARSED_LEN + 1];
+	char dirname[128];
+	int pos, st;
+
+	if (!guid_top_handle)
+		guid_top_handle = devfs_mk_dir (NULL, "guid", NULL);
+
+	if (!guid || !master) return;
+
+	do {
+		slave = devfs_get_unregister_slave (master);
+		if (slave) {
+			if (slave == master || slave == real_master) {
+				printk (KERN_WARNING
+					"devfs_register_guid: infinite slave loop!\n");
+				return;
+			} else if (devfs_get_parent (slave) == guid_top_handle) {
+				printk (KERN_INFO
+					"devfs_register_guid: unregistering %s\n",
+					devfs_get_name (slave, NULL));
+				devfs_unregister_slave (master);
+				slave = NULL;
+			} else
+				master = slave;
+		};
+	} while (slave);
+
+	uuid_unparse_1 (guid, guid_link);
+	pos = devfs_generate_path (real_master, dirname + 3,
+				   sizeof (dirname) - 3);
+	if (pos < 0) {
+		printk (KERN_WARNING
+			"devfs_register_guid: error generating path: %d\n",
+			pos);
+		return;
+	};
+
+	strncpy (dirname + pos, "../", 3);
+
+	st = devfs_mk_symlink (guid_top_handle, guid_link,
+			       DEVFS_FL_DEFAULT,
+			       dirname + pos, &guid_handle, NULL);
+
+	if (st < 0) {
+		printk ("Error %d creating symlink\n", st);
+	} else {
+		devfs_auto_unregister (master, guid_handle);
+	};
+};
+
+/*
+  free_disk_guids: kfree all guid data structures alloced for
+  the disk device specified by (dev, minor) and all its partitions.
+
+  This function does not remove symlinks in /dev/guid.
+*/
+static void free_disk_guids (struct gendisk *dev, int minor)
+{
+	int i;
+	efi_guid_t *guid;
+
+	for (i = 0; i < dev->max_p; i++) {
+		guid = dev->part[minor + i].guid;
+		if (!guid) continue;
+		kfree (guid);
+		dev->part[minor + i].guid = NULL;
+	};
+}
+
+#endif /* CONFIG_DEVFS_GUID */
+
 #ifdef CONFIG_DEVFS_FS
 static void devfs_register_partition (struct gendisk *dev, int minor, int part)
 {
@@ -296,7 +412,11 @@
 	unsigned int devfs_flags = DEVFS_FL_DEFAULT;
 	char devname[16];
 
-	if (dev->part[minor + part].de) return;
+	/* Even if the devfs handle is still up-to-date,
+	   the GUID entry probably isn't */
+	if (dev->part[minor + part].de)
+		goto do_guid;
+
 	dir = devfs_get_parent (dev->part[minor].de);
 	if (!dir) return;
 	if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) )
@@ -307,6 +427,11 @@
 			    dev->major, minor + part,
 			    S_IFBLK | S_IRUSR | S_IWUSR,
 			    dev->fops, NULL);
+ do_guid:
+#ifdef CONFIG_DEVFS_GUID
+	devfs_register_guid (dev, minor + part);
+#endif
+	return;
 }
 
 static struct unique_numspace disc_numspace = UNIQUE_NUMBERSPACE_INITIALISER;
@@ -320,7 +445,9 @@
 	char dirname[64], symlink[16];
 	static devfs_handle_t devfs_handle;
 
-	if (dev->part[minor].de) return;
+	if (dev->part[minor].de)
+		goto do_guid;
+
 	if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) )
 		devfs_flags |= DEVFS_FL_REMOVABLE;
 	if (dev->de_arr) {
@@ -348,6 +475,12 @@
 	devfs_auto_unregister (dev->part[minor].de, slave);
 	if (!dev->de_arr)
 		devfs_auto_unregister (slave, dir);
+
+ do_guid:
+#ifdef CONFIG_DEVFS_GUID
+	devfs_register_guid (dev, minor);
+#endif
+	return;
 }
 #endif  /*  CONFIG_DEVFS_FS  */
 
@@ -371,6 +504,9 @@
 		dev->part[minor].de = NULL;
 		devfs_dealloc_unique_number (&disc_numspace,
 					     dev->part[minor].number);
+# ifdef CONFIG_DEVFS_GUID
+		free_disk_guids (dev, minor);
+# endif
 	}
 #endif  /*  CONFIG_DEVFS_FS  */
 }
@@ -388,8 +524,21 @@
 void register_disk(struct gendisk *gdev, kdev_t dev, unsigned minors,
 	struct block_device_operations *ops, long size)
 {
+	int i;
+
 	if (!gdev)
 		return;
+
+#ifdef CONFIG_DEVFS_GUID
+	/* Initialize all guid fields to NULL (=^ not kmalloc'ed).
+	   It is assumed that drivers call register_disk after
+	   allocating the gen_hd structure, and call grok_partitions
+	   directly for a revalidate event, as those drives I've inspected
+	   (among which hd and sd) do. */
+	for (i = 0; i < gdev->max_p; i++)
+		gdev->part[MINOR(dev) + i].guid = NULL;
+#endif
+
 	grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size);
 }
 
@@ -407,6 +556,13 @@
 	if (!size || minors == 1)
 		return;
 
+#ifdef CONFIG_DEVFS_GUID
+	/* In case this is a revalidation, free GUID memory.
+	   On the first call for this device,
+	   register_disk has set all entries to NULL,
+	   and nothing will happen. */
+	free_disk_guids (dev, first_minor);
+#endif
 	check_partition(dev, MKDEV(dev->major, first_minor), 1 + first_minor);
 
  	/*
diff -urN linux-2.4.10/fs/partitions/efi.c linux-2.4.10-lia/fs/partitions/efi.c
--- linux-2.4.10/fs/partitions/efi.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.10-lia/fs/partitions/efi.c	Tue Jun 26 22:33:56 2001
@@ -0,0 +1,633 @@
+/************************************************************
+ * EFI GUID Partition Table handling
+ * Per Intel EFI Specification v0.99
+ * http://developer.intel.com/technology/efi/efi.htm
+ * efi.[ch] by Matt Domsch <Matt_Domsch@dell.com>
+ *   Copyright 2000 Dell Computer Corporation
+ *
+ * Note, the EFI Specification, v0.99, has a reference to
+ * Dr. Dobbs Journal, May 1994 (actually it's in May 1992)
+ * but that isn't the CRC function being used by EFI.  Intel's
+ * EFI Sample Implementation shows that they use the same function
+ * as was COPYRIGHT (C) 1986 Gary S. Brown.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * TODO:
+ *
+ * Changelog:
+ * Tue Dec  5 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Moved crc32() to linux/lib, added efi_crc32().
+ *
+ * Thu Nov 30 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Replaced Intel's CRC32 function with an equivalent
+ *   non-license-restricted version.
+ *
+ * Wed Oct 25 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Fixed the LastLBA() call to return the proper last block
+ *
+ * Thu Oct 12 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Thanks to Andries Brouwer for his debugging assistance.
+ * - Code works, detects all the partitions.
+ *
+ ************************************************************/
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/blkpg.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+#include <asm/system.h>
+#include <asm/efi.h>
+#include <linux/crc32.h>
+
+#include "check.h"
+#include "efi.h"
+
+#if CONFIG_BLK_DEV_MD
+extern void md_autodetect_dev(kdev_t dev);
+#endif
+
+
+#undef EFI_DEBUG
+#ifdef EFI_DEBUG
+static char *efi_printk_level = KERN_DEBUG;
+#define debug_printk printk
+#else
+#define debug_printk(...)
+#endif
+
+/************************************************************
+ * efi_crc32()
+ * Requires:
+ *  - a buffer of length len
+ * Modifies: nothing
+ * Returns:
+ *  EFI-style CRC32 value for buf
+ *
+ * This function uses the crc32 function by Gary S. Brown,
+ * but seeds the function with ~0, and xor's with ~0 at the end.
+ ************************************************************/
+
+u32 static inline
+efi_crc32(const void *buf, unsigned long len)
+{
+  return (crc32(buf, len, ~0L) ^ ~0L);
+}
+
+
+
+
+/************************************************************
+ * IsLegacyMBRValid()
+ * Requires:
+ *  - mbr is a pointer to a legacy mbr structure
+ * Modifies: nothing
+ * Returns:
+ *  1 on true
+ *  0 on false
+ ************************************************************/
+static inline int
+IsLegacyMBRValid(LegacyMBR_t *mbr)
+{
+	return (mbr ? (mbr->Signature == MSDOS_MBR_SIGNATURE) : 0);
+}
+
+
+
+/************************************************************
+ * LastLBA()
+ * Requires:
+ *  - struct gendisk hd
+ *  - kdev_t dev
+ * Modifies: nothing
+ * Returns:
+ *  Last LBA value on success.  This is stored (by sd and
+ *  ide-geometry) in
+ *  the part[0] entry for this disk, and is the number of
+ *  physical sectors available on the disk.
+ *  0 on error
+ ************************************************************/
+u64
+LastLBA(struct gendisk *hd, kdev_t dev)
+{
+  if (!hd || !hd->part) return 0;
+  return hd->part[MINOR(dev)].nr_sects - 1;
+}
+
+
+/************************************************************
+ * ReadLBA()
+ * Requires:
+ *  - hd is our disk device.
+ *  - dev is our device major number
+ *  - lba is the logical block address desired (disk hardsector number)
+ *  - buffer is a buffer of size size into which data copied
+ *  - size_t count is size of the read (in bytes)
+ * Modifies:
+ *  - buffer
+ * Returns:
+ *  - count of bytes read
+ *  - 0 on error
+ * Bugs:
+ *  - bread() takes second argument as a signed int, not a u64.
+ *    This is because getblk() takes the block number as a signed int.
+ *    This overflow is known on l-k.   We overflow at about 1TB.
+ *
+ ************************************************************/
+
+static size_t
+ReadLBA(struct gendisk *hd, kdev_t dev, u64 _lba, u8 *buffer, size_t count)
+{
+	struct buffer_head *bh;
+	size_t totalreadcount = 0, bytesread;
+	int lba = (_lba & 0x7FFFFFFF), i, blockstoread, blocksize;
+	debug_printk(efi_printk_level "ReadLBA(%p,%s,%x,%p,%x)\n",
+		     hd, kdevname(dev), lba, buffer, count);
+
+	if (!hd || !buffer || !count) return 0;
+
+
+	blocksize = get_hardsect_size(dev);
+	blockstoread = count / blocksize;
+	if (count % blocksize) blockstoread += 1;
+	debug_printk(efi_printk_level "about to read %d blocks\n",
+		     blockstoread);
+
+
+	for (i=0; i<blockstoread; i++) {
+		bh = bread(dev, lba+i, blocksize);
+		if (!bh) {
+			/* We hit the end of the disk */
+			debug_printk(efi_printk_level
+				     "bread returned NULL.\n");
+			return totalreadcount;
+		}
+
+		bytesread = (count > bh->b_size ? bh->b_size : count);
+		memcpy(buffer, bh->b_data, bytesread);
+
+		buffer += bytesread;         /* Advance the buffer pointer */
+		totalreadcount += bytesread; /* Advance the total read count */
+		count -= bytesread;         /* Subtract bytesread from count */
+
+		brelse(bh);
+	}
+
+	return totalreadcount;
+}
+
+void
+PrintGuidPartitionTableHeader(GuidPartitionTableHeader_t *gpt)
+{
+	debug_printk(efi_printk_level "GUID Partition Table Header\n");
+	if (!gpt) return;
+	debug_printk(efi_printk_level "Signature      : %lx\n",
+		     gpt->Signature);
+	debug_printk(efi_printk_level "Revision       : %x\n",
+		     gpt->Revision);
+	debug_printk(efi_printk_level "HeaderSize     : %x\n",
+		     gpt->HeaderSize);
+	debug_printk(efi_printk_level "HeaderCRC32    : %x\n",
+		     gpt->HeaderCRC32);
+	debug_printk(efi_printk_level "MyLBA          : %lx\n",
+		     gpt->MyLBA);
+	debug_printk(efi_printk_level "AlternateLBA   : %lx\n",
+		     gpt->AlternateLBA);
+	debug_printk(efi_printk_level "FirstUsableLBA : %lx\n",
+		     gpt->FirstUsableLBA);
+	debug_printk(efi_printk_level "LastUsableLBA  : %lx\n",
+		     gpt->LastUsableLBA);
+
+	debug_printk(efi_printk_level "PartitionEntryLBA : %lx\n",
+		     gpt->PartitionEntryLBA);
+	debug_printk(efi_printk_level "NumberOfPartitionEntries : %x\n",
+		     gpt->NumberOfPartitionEntries);
+	debug_printk(efi_printk_level "SizeOfPartitionEntry : %x\n",
+		     gpt->SizeOfPartitionEntry);
+	debug_printk(efi_printk_level "PartitionEntryArrayCRC32 : %x\n",
+		     gpt->PartitionEntryArrayCRC32);
+
+	return;
+}
+
+
+
+/************************************************************
+ * ReadGuidPartitionEntries()
+ * Requires:
+ *  - filedes is an open file descriptor, suitable for reading
+ *  - lba is the Logical Block Address of the partition table
+ *  - gpt is a buffer into which the GPT will be put
+ * Modifies:
+ *  - filedes file and pointer
+ *  - gpt
+ * Returns:
+ *   pte on success
+ *   NULL on error
+ * Notes: remember to free pte when you're done!
+ ************************************************************/
+GuidPartitionEntry_t *
+ReadGuidPartitionEntries(struct gendisk *hd, kdev_t dev,
+			 GuidPartitionTableHeader_t *gpt)
+{
+	size_t count;
+	GuidPartitionEntry_t *pte;
+	if (!hd || !gpt) return NULL;
+
+	count = gpt->NumberOfPartitionEntries * gpt->SizeOfPartitionEntry;
+	debug_printk(efi_printk_level "ReadGPTEs() kmallocing %x bytes\n",
+		     count);
+	if (!count) return NULL;
+	pte = kmalloc(count, GFP_KERNEL);
+	if (!pte)  return NULL;
+	memset(pte, 0, count);
+
+	if (ReadLBA(hd, dev, gpt->PartitionEntryLBA, (u8 *)pte,
+		    count) < count) {
+		kfree(pte);
+		return NULL;
+	}
+	return pte;
+}
+
+
+
+/************************************************************
+ * ReadGuidPartitionTableHeader()
+ * Requires:
+ *  - hd is our struct gendisk
+ *  - dev is our device major number
+ *  - lba is the Logical Block Address of the partition table
+ *  - gpt is a buffer into which the GPT will be put
+ *  - pte is a buffer into which the PTEs will be put
+ * Modifies:
+ *  - gpt and pte
+ * Returns:
+ *   1 on success
+ *   0 on error
+ ************************************************************/
+
+GuidPartitionTableHeader_t *
+ReadGuidPartitionTableHeader(struct gendisk *hd, kdev_t dev, u64 lba)
+
+{
+	GuidPartitionTableHeader_t *gpt;
+	if (!hd) return NULL;
+
+	gpt = kmalloc(sizeof(GuidPartitionTableHeader_t), GFP_KERNEL);
+	if (!gpt) return NULL;
+	memset(gpt, 0, sizeof(GuidPartitionTableHeader_t));
+
+	debug_printk(efi_printk_level "GPTH() calling ReadLBA().\n");
+	if (ReadLBA(hd, dev, lba, (u8 *)gpt,
+		    sizeof(GuidPartitionTableHeader_t)) <
+	    sizeof(GuidPartitionTableHeader_t)) {
+		debug_printk(efi_printk_level "ReadGPTH(%lx) read failed.\n",
+			     lba);
+		kfree(gpt);
+		return NULL;
+	}
+	PrintGuidPartitionTableHeader(gpt);
+
+	return gpt;
+}
+
+
+
+/************************************************************
+ * IsGuidPartitionTableValid()
+ * Requires:
+ *  - gd points to our struct gendisk
+ *  - dev is our device major number
+ *  - lba is the logical block address of the GPTH to test
+ *  - gpt is a GPTH if it's valid
+ *  - ptes is a PTEs if it's valid
+ * Modifies:
+ *  - gpt and ptes
+ * Returns:
+ *   1 if valid
+ *   0 on error
+ ************************************************************/
+static int
+IsGuidPartitionTableValid(struct gendisk *hd, kdev_t dev, u64 lba,
+			  GuidPartitionTableHeader_t **gpt,
+			  GuidPartitionEntry_t **ptes)
+{
+	u32 crc, origcrc;
+
+	if (!hd || !gpt || !ptes) return 0;
+	if (!(*gpt = ReadGuidPartitionTableHeader(hd, dev, lba))) return 0;
+
+	/* Check the GUID Partition Table Signature */
+	if ((*gpt)->Signature != GUID_PT_HEADER_SIGNATURE) {
+		debug_printk(efi_printk_level "GUID Partition Table Header Signature is wrong: %x != %x\n", (*gpt)->Signature, GUID_PT_HEADER_SIGNATURE);
+		kfree(*gpt);
+		*gpt = NULL;
+		return 0;
+	}
+
+	/* Check the GUID Partition Table CRC */
+	origcrc = (*gpt)->HeaderCRC32;
+	(*gpt)->HeaderCRC32 = 0;
+	crc = efi_crc32((const unsigned char *)(*gpt), (*gpt)->HeaderSize);
+
+
+	if (crc != origcrc) {
+		debug_printk(efi_printk_level "GUID Partition Table Header CRC is wrong: %x != %x\n", (*gpt)->HeaderCRC32, origcrc);
+		kfree(*gpt);
+		*gpt = NULL;
+		return 0;
+	}
+	(*gpt)->HeaderCRC32 = origcrc;
+
+	/* Check that the MyLBA entry points to the LBA that contains
+	 * the GUID Partition Table */
+	if ((*gpt)->MyLBA != lba) {
+		debug_printk(efi_printk_level "GPT MyLBA incorrect: %lx != %lx\n", (*gpt)->MyLBA, lba);
+		kfree(*gpt);
+		*gpt = NULL;
+		return 0;
+	}
+
+	if (!(*ptes = ReadGuidPartitionEntries(hd, dev, *gpt))) {
+		debug_printk(efi_printk_level "read PTEs failed.\n");
+		kfree(*gpt);
+		*gpt = NULL;
+		return 0;
+	}
+
+	/* Check the GUID Partition Entry Array CRC */
+	crc = efi_crc32((const unsigned char *)(*ptes),
+		    (*gpt)->NumberOfPartitionEntries *
+			   (*gpt)->SizeOfPartitionEntry);
+
+	if (crc != (*gpt)->PartitionEntryArrayCRC32)  {
+		debug_printk(efi_printk_level "GUID Partitition Entry Array CRC check failed.\n");
+		kfree(*gpt);
+		*gpt = NULL;
+		kfree(*ptes);
+		*ptes = NULL;
+		return 0;
+	}
+
+
+	/* We're done, all's well */
+	return 1;
+}
+
+
+
+/************************************************************
+ * FindValidGPT()
+ * Requires:
+ *  - gd points to our struct gendisk
+ *  - dev is our device major number
+ *  - gpt is a GPTH if it's valid
+ *  - ptes is a PTE
+ * Modifies:
+ *  - gpt & ptes
+ * Returns:
+ *   1 if valid
+ *   0 on error
+ ************************************************************/
+static int
+FindValidGPT(struct gendisk *hd, kdev_t dev,
+	     GuidPartitionTableHeader_t **gpt,
+	     GuidPartitionEntry_t **ptes)
+{
+	int rc = 0;
+	GuidPartitionTableHeader_t *pgpt = NULL, *agpt = NULL;
+	GuidPartitionEntry_t *pptes = NULL, *aptes = NULL;
+	u64 lastlba;
+	if (!hd || !gpt || !ptes) return 0;
+
+	lastlba = LastLBA(hd, dev);
+	/* Check the Primary GPT */
+	rc = IsGuidPartitionTableValid(hd, dev, 1, &pgpt, &pptes);
+	if (rc) {
+		/* Primary GPT is OK, check the alternate and warn if bad */
+		rc = IsGuidPartitionTableValid(hd, dev, pgpt->AlternateLBA,
+					       &agpt, &aptes);
+		if (!rc){
+			printk(KERN_WARNING "Alternate GPT is invalid, using primary GPT.\n");
+		}
+
+		*gpt = pgpt;
+		*ptes = pptes;
+		if (agpt)  kfree(agpt);
+		if (aptes) kfree(aptes);
+		return 1;
+	} /* if primary is valid */
+	else {
+		/* Primary GPT is bad, check the Alternate GPT */
+		rc = IsGuidPartitionTableValid(hd, dev, lastlba,
+					       &agpt, &aptes);
+		if (rc) {
+			/* Primary is bad, alternate is good.
+			   Return values from the alternate and warn.
+			*/
+			printk(KERN_WARNING "Primary GPT is invalid, using alternate GPT.\n");
+			*gpt = agpt;
+			*ptes = aptes;
+			return 1;
+		}
+		else {
+			/* Primary is bad, alternate is bad, try "other"
+			 * alternate.  This is necessary because if we
+			 * have an odd-sized disk, user-space might
+			 * have put the alternate in block lastlba-1.
+			 */
+			if (!(lastlba & 1)) {
+				lastlba--;
+				rc = IsGuidPartitionTableValid(hd, dev,
+							       lastlba,
+							       &agpt, &aptes);
+				if (rc) {
+					/* Primary is bad, alternate is good.
+					 * Return values from the alternate
+					 * and warn.
+					 */
+					printk("Primary GPT is invalid, using alternate GPT.\n");
+					*gpt = agpt;
+					*ptes = aptes;
+					return 1;
+				}
+			}
+		}
+	}
+	/* Both primary and alternate GPTs are bad.
+	 * This isn't our disk, return 0.
+	 */
+	return 0;
+}
+
+#ifdef CONFIG_DEVFS_GUID
+/* set_partition_guid */
+/* Fill in the GUID field of the partition.
+   It is set to NULL by register_disk before. */
+static void set_partition_guid (struct gendisk *hd,
+				const int minor,
+				const efi_guid_t *guid)
+{
+	efi_guid_t *part_guid = hd->part[minor].guid;
+
+	if (!guid || !hd) return;
+
+	part_guid = kmalloc (sizeof (efi_guid_t), GFP_KERNEL);
+
+        if (part_guid) {
+		memcpy (part_guid, guid, sizeof (efi_guid_t));
+	} else {
+		printk (KERN_WARNING
+                        "add_gpt_partitions: cannot allocate GUID memory!\n");
+	};
+
+	hd->part[minor].guid = part_guid;
+}
+#endif /* CONFIG_DEVFS_GUID */
+
+/*
+ * Create devices for each entry in the GUID Partition Table Entries.
+ * The first block of each partition is a Legacy MBR.
+ *
+ * We do not create a Linux partition for GPT, but
+ * only for the actual data partitions.
+ * Returns:
+ * -1 if unable to read the partition table
+ *  0 if this isn't our partition table
+ *  1 if successful
+ *
+ */
+
+static int
+add_gpt_partitions(struct gendisk *hd, kdev_t dev, int nextminor)
+{
+	GuidPartitionTableHeader_t *gpt = NULL;
+	GuidPartitionEntry_t *ptes = NULL;
+	u32 i, nummade=0;
+
+	efi_guid_t unusedGuid = UNUSED_ENTRY_GUID;
+#if CONFIG_BLK_DEV_MD
+	efi_guid_t raidGuid = PARTITION_LINUX_RAID_GUID;
+#endif
+
+	if (!hd) return -1;
+
+	if (!FindValidGPT(hd, dev, &gpt, &ptes) ||
+	    !gpt || !ptes) {
+		if (gpt) kfree(gpt);
+		if (ptes) kfree(ptes);
+		return 0;
+	}
+
+	debug_printk(efi_printk_level "GUID Partition Table is valid!  Yea!\n");
+
+#ifdef CONFIG_DEVFS_GUID
+	set_partition_guid (hd, nextminor - 1, &(gpt->DiskGUID));
+#endif
+
+	for (i = 0; i < gpt->NumberOfPartitionEntries &&
+		     nummade < (hd->max_p - 1); i++) {
+		if (!efi_guidcmp(unusedGuid, ptes[i].PartitionTypeGuid))
+			continue;
+
+		add_gd_partition(hd, nextminor, ptes[i].StartingLBA,
+				 (ptes[i].EndingLBA-ptes[i].StartingLBA + 1));
+
+#ifdef CONFIG_DEVFS_GUID
+		set_partition_guid (hd, nextminor, &(ptes[i].UniquePartitionGuid));
+#endif
+
+		/* If there's this is a RAID volume, tell md */
+#if CONFIG_BLK_DEV_MD
+		if (!efi_guidcmp(raidGuid, ptes[i].PartitionTypeGuid)) {
+			md_autodetect_dev(MKDEV(MAJOR(dev),nextminor));
+		}
+#endif
+		nummade++;
+		nextminor++;
+
+	}
+	kfree(ptes);
+	kfree(gpt);
+	printk("\n");
+	return 1;
+
+}
+
+
+/*
+ * efi_partition()
+ *
+ * If the first block on the disk is a legacy MBR,
+ * it got handled already by msdos_partition().
+ * If it's a Protective MBR, we'll handle it here.
+ *
+ * Returns:
+ * -1 if unable to read the partition table
+ *  0 if this isn't our partitoin table
+ *  1 if successful
+ *
+ */
+
+int
+efi_partition(struct gendisk *hd, kdev_t dev,
+	      unsigned long first_sector, int first_part_minor) {
+	int hardblocksize = get_hardsect_size(dev);
+	int orig_blksize_size = BLOCK_SIZE;
+	int rc = 0;
+
+	/* Need to change the block size that the block layer uses */
+	if (blksize_size[MAJOR(dev)]){
+		orig_blksize_size = blksize_size[MAJOR(dev)][MINOR(dev)];
+	}
+
+	if (orig_blksize_size != hardblocksize)
+		set_blocksize(dev, hardblocksize);
+
+	rc = add_gpt_partitions(hd, dev, first_part_minor);
+
+	/* change back */
+	if (orig_blksize_size != hardblocksize)
+		set_blocksize(dev, orig_blksize_size);
+
+	return rc;
+}
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -urN linux-2.4.10/fs/partitions/efi.h linux-2.4.10-lia/fs/partitions/efi.h
--- linux-2.4.10/fs/partitions/efi.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.10-lia/fs/partitions/efi.h	Mon Sep 24 23:00:15 2001
@@ -0,0 +1,154 @@
+/************************************************************
+ * EFI GUID Partition Table
+ * Per Intel EFI Specification v0.99
+ * http://developer.intel.com/technology/efi/efi.htm
+ *
+ * By Matt Domsch <Matt_Domsch@dell.com>  Fri Sep 22 22:15:56 CDT 2000  
+ *   Copyright 2000 Dell Computer Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ * 
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ ************************************************************/
+
+#ifndef FS_PART_EFI_H_INCLUDED
+#define FS_PART_EFI_H_INCLUDED
+
+#include <linux/types.h>
+#include <asm/efi.h>
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+
+#define MSDOS_MBR_SIGNATURE 0xaa55
+#define EFI_PMBR_OSTYPE_EFI 0xEF
+#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
+
+#define GUID_PT_BLOCK_SIZE 512
+
+#define GUID_PT_HEADER_SIGNATURE 0x5452415020494645L
+#define GUID_PT_HEADER_REVISION_V1 0x00010000
+#define GUID_PT_HEADER_REVISION_V0_99 0x00000099
+#define UNUSED_ENTRY_GUID    \
+    ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
+#define PARTITION_SYSTEM_GUID \
+((efi_guid_t) { 0xC12A7328, 0xF81F, 0x11d2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
+#define LEGACY_MBR_PARTITION_GUID \
+    ((efi_guid_t) { 0x024DEE41, 0x33E7, 0x11d3, { 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
+#define PARTITION_MSFT_RESERVED_GUID \
+    ((efi_guid_t) { 0xE3C9E316, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
+#define PARTITION_BASIC_DATA_GUID \
+    ((efi_guid_t) { 0xEBD0A0A2, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
+#define PARTITION_LINUX_RAID_GUID \
+    ((efi_guid_t) { 0xa19d880f, 0x05fc, 0x4d3b, { 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e  }})
+#define PARTITION_LINUX_SWAP_GUID \
+    ((efi_guid_t) { 0x0657fd6d, 0xa4ab, 0x43c4, { 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f  }})
+
+typedef struct _GuidPartitionTableHeader_t {
+  u64 Signature;
+  u32 Revision;
+  u32 HeaderSize;
+  u32 HeaderCRC32;
+  u32 Reserved1;
+  u64 MyLBA;
+  u64 AlternateLBA;
+  u64 FirstUsableLBA;
+  u64 LastUsableLBA;
+  efi_guid_t DiskGUID;
+  u64 PartitionEntryLBA;
+  u32 NumberOfPartitionEntries;
+  u32 SizeOfPartitionEntry;
+  u32 PartitionEntryArrayCRC32;
+  u8 Reserved2[GUID_PT_BLOCK_SIZE - 92];
+} GuidPartitionTableHeader_t;
+
+typedef struct _GuidPartitionEntryAttributes_t {
+  __u64 RequiredToFunction:1;
+  __u64 Reserved:63;
+} GuidPartitionEntryAttributes_t;
+
+typedef struct _GuidPartitionEntry_t {
+  efi_guid_t PartitionTypeGuid;
+  efi_guid_t UniquePartitionGuid;
+  u64 StartingLBA;
+  u64 EndingLBA;
+  GuidPartitionEntryAttributes_t Attributes;
+  efi_char16_t PartitionName[72/sizeof(efi_char16_t)];
+} GuidPartitionEntry_t;
+
+
+
+typedef struct _PartitionRecord_t {
+  u8 BootIndicator;  /* Not used by EFI firmware. Set to 0x80 to indicate that this
+                        is the bootable legacy partition. */
+  u8 StartHead;      /* Start of partition in CHS address, not used by EFI firmware. */
+  u8 StartSector;    /* Start of partition in CHS address, not used by EFI firmware. */
+  u8 StartTrack;     /* Start of partition in CHS address, not used by EFI firmware. */
+  u8 OSType;         /* OS type. A value of 0xEF defines an EFI system partition.
+                        Other values are reserved for legacy operating systems, and
+                        allocated independently of the EFI specification. */
+  u8 EndHead;        /* End of partition in CHS address, not used by EFI firmware. */
+  u8 EndSector;      /* End of partition in CHS address, not used by EFI firmware. */
+  u8 EndTrack;       /* End of partition in CHS address, not used by EFI firmware. */
+  u32 StartingLBA;   /* Starting LBA address of the partition on the disk. Used by
+                        EFI firmware to define the start of the partition. */
+  u32 SizeInLBA;     /* Size of partition in LBA. Used by EFI firmware to determine
+                        the size of the partition. */
+} PartitionRecord_t;
+
+typedef struct _LegacyMBR_t {
+  u8 BootCode[440];
+  u32 UniqueMBRSignature;
+  u16 Unknown;
+  PartitionRecord_t PartitionRecord[4];
+  u16 Signature;
+} __attribute__ ((packed)) LegacyMBR_t;
+
+
+
+#define EFI_GPT_PRIMARY_PARTITION_TABLE_LBA 1
+
+/* Functions */
+extern int
+efi_partition(struct gendisk *hd, kdev_t dev,
+              unsigned long first_sector, int first_part_minor);
+
+
+
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * --------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -urN linux-2.4.10/fs/partitions/msdos.c linux-2.4.10-lia/fs/partitions/msdos.c
--- linux-2.4.10/fs/partitions/msdos.c	Sat Jul 28 12:50:13 2001
+++ linux-2.4.10-lia/fs/partitions/msdos.c	Mon Aug 13 23:46:45 2001
@@ -36,6 +36,10 @@
 #include "check.h"
 #include "msdos.h"
 
+#ifdef CONFIG_EFI_PARTITION
+#include "efi.h"
+#endif
+
 #if CONFIG_BLK_DEV_MD
 extern void md_autodetect_dev(kdev_t dev);
 #endif
@@ -454,6 +458,16 @@
 		return 0;
 	}
 	p = (struct partition *) (data + 0x1be);
+#ifdef CONFIG_EFI_PARTITION
+	for (i=1 ; i<=4 ; i++,p++) {
+		/* If this is an EFI GPT disk, msdos should ignore it. */
+		if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) {
+			bforget(bh);
+			return 0;
+		}
+	}
+	p = (struct partition *) (data + 0x1be);
+#endif
 
 #ifdef CONFIG_BLK_DEV_IDE
 	if (!tested_for_xlate++) {	/* Do this only once per disk */
diff -urN linux-2.4.10/lib/crc32.c linux-2.4.10-lia/lib/crc32.c
--- linux-2.4.10/lib/crc32.c	Wed Dec 31 16:00:00 1969
+++ linux-2.4.10-lia/lib/crc32.c	Wed Dec  6 22:41:15 2000
@@ -0,0 +1,125 @@
+/* 
+ * Dec 5, 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Copied crc32.c from the linux/drivers/net/cipe directory.
+ * - Now pass seed as an arg
+ * - changed unsigned long to u32, added #include<linux/types.h>
+ * - changed len to be an unsigned long
+ * - changed crc32val to be a register
+ * - License remains unchanged!  It's still GPL-compatable!
+ */
+
+  /* ============================================================= */
+  /*  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or       */
+  /*  code or tables extracted from it, as desired without restriction.     */
+  /*                                                                        */
+  /*  First, the polynomial itself and its table of feedback terms.  The    */
+  /*  polynomial is                                                         */
+  /*  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0   */
+  /*                                                                        */
+  /*  Note that we take it "backwards" and put the highest-order term in    */
+  /*  the lowest-order bit.  The X^32 term is "implied"; the LSB is the     */
+  /*  X^31 term, etc.  The X^0 term (usually shown as "+1") results in      */
+  /*  the MSB being 1.                                                      */
+  /*                                                                        */
+  /*  Note that the usual hardware shift register implementation, which     */
+  /*  is what we're using (we're merely optimizing it by doing eight-bit    */
+  /*  chunks at a time) shifts bits into the lowest-order term.  In our     */
+  /*  implementation, that means shifting towards the right.  Why do we     */
+  /*  do it this way?  Because the calculated CRC must be transmitted in    */
+  /*  order from highest-order term to lowest-order term.  UARTs transmit   */
+  /*  characters in order from LSB to MSB.  By storing the CRC this way,    */
+  /*  we hand it to the UART in the order low-byte to high-byte; the UART   */
+  /*  sends each low-bit to hight-bit; and the result is transmission bit   */
+  /*  by bit from highest- to lowest-order term without requiring any bit   */
+  /*  shuffling on our part.  Reception works similarly.                    */
+  /*                                                                        */
+  /*  The feedback terms table consists of 256, 32-bit entries.  Notes:     */
+  /*                                                                        */
+  /*      The table can be generated at runtime if desired; code to do so   */
+  /*      is shown later.  It might not be obvious, but the feedback        */
+  /*      terms simply represent the results of eight shift/xor opera-      */
+  /*      tions for all combinations of data and CRC register values.       */
+  /*                                                                        */
+  /*      The values must be right-shifted by eight bits by the "updcrc"    */
+  /*      logic; the shift must be unsigned (bring in zeroes).  On some     */
+  /*      hardware you could probably optimize the shift in assembler by    */
+  /*      using byte-swap instructions.                                     */
+  /*      polynomial $edb88320                                              */
+  /*                                                                        */
+  /*  --------------------------------------------------------------------  */
+
+#include <linux/crc32.h>
+
+static u32 crc32_tab[] = {
+      0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+      0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+      0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+      0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+      0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+      0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+      0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+      0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+      0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+      0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+      0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+      0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+      0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+      0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+      0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+      0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+      0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+      0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+      0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+      0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+      0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+      0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+      0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+      0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+      0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+      0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+      0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+      0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+      0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+      0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+      0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+      0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+      0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+      0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+      0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+      0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+      0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+      0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+      0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+      0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+      0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+      0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+      0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+      0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+      0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+      0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+      0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+      0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+      0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+      0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+      0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+      0x2d02ef8dL
+   };
+
+/* Return a 32-bit CRC of the contents of the buffer. */
+
+u32
+crc32(const void *buf, unsigned long len, u32 seed)
+{
+  unsigned long i;
+  register u32 crc32val;
+  const unsigned char *s = buf;
+
+  crc32val = seed;
+  for (i = 0;  i < len;  i ++)
+    {
+      crc32val =
+	crc32_tab[(crc32val ^ s[i]) & 0xff] ^
+	  (crc32val >> 8);
+    }
+  return crc32val;
+}
diff -urN linux-2.4.10/include/linux/crc32.h linux-2.4.10-lia/include/linux/crc32.h
--- linux-2.4.10/include/linux/crc32.h	Wed Dec 31 16:00:00 1969
+++ linux-2.4.10-lia/include/linux/crc32.h	Wed Dec  6 22:40:05 2000
@@ -0,0 +1,17 @@
+/*
+ * crc32.h
+ * See linux/lib/crc32.c for license and changes
+ */
+#ifndef _LINUX_CRC32_H
+#define _LINUX_CRC32_H
+
+#include <linux/types.h>
+
+/*
+ * This computes a 32 bit CRC of the data in the buffer, and returns the CRC.
+ * The polynomial used is 0xedb88320.
+ */
+
+extern u32 crc32 (const void *buf, unsigned long len, u32 seed);
+
+#endif /* _LINUX_CRC32_H */
diff -urN linux-2.4.10/lib/Makefile linux-2.4.10-lia/lib/Makefile
--- linux-2.4.10/lib/Makefile	Mon Sep 24 15:08:39 2001
+++ linux-2.4.10-lia/lib/Makefile	Mon Sep 24 21:29:52 2001
@@ -10,7 +10,7 @@
 
 export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o
 
-obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o
+obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o crc32.o
 
 obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
 obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
