r2309 - in trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian: . patches patches/series

Christoph Hellwig hch-guest@costa.debian.org
Sun, 16 Jan 2005 14:59:05 +0100


Author: hch-guest
Date: 2005-01-16 14:59:04 +0100 (Sun, 16 Jan 2005)
New Revision: 2309

Added:
   trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/fs-partitions-efi-update.dpatch
Modified:
   trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/changelog
   trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/series/2.6.8-13
Log:

  * Backport EFI partition support fixes from 2.6.10.  Patch supplied by Tore
    Anderson <tore@debian.org> (Christoph Hellwig) (closes: #281905).



Modified: trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/changelog
===================================================================
--- trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/changelog	2005-01-16 11:27:01 UTC (rev 2308)
+++ trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/changelog	2005-01-16 13:59:04 UTC (rev 2309)
@@ -20,6 +20,9 @@
     is used (Andres Salomon).
  
   * Apply patch to fix compat cmsg_len checks (Christoph Hellwig).
+
+  * Backport EFI partition support fixes from 2.6.10.  Patch supplied by Tore
+    Anderson <tore@debian.org> (Christoph Hellwig) (closes: #281905).
  
  -- Norbert Tretkowski <nobse@debian.org>  Thu, 13 Jan 2005 17:23:35 +0100
 

Added: trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/fs-partitions-efi-update.dpatch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/fs-partitions-efi-update.dpatch	2005-01-16 11:27:01 UTC (rev 2308)
+++ trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/fs-partitions-efi-update.dpatch	2005-01-16 13:59:04 UTC (rev 2309)
@@ -0,0 +1,447 @@
+#! /bin/sh -e
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description:  EFI GPT: reduce alternate header probing
+## DP: Patch author: Matt Domsch <Matt_Domsch@dell.com>
+## DP: Upstream status: backport
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+#   2004/11/09 17:07:52-08:00 Matt_Domsch@dell.com 
+#   [PATCH] EFI GPT: reduce alternate header probing
+#   
+#   EFI partitioning scheme was reading the last reported sector of the
+#   block device to look for the alternate GPT header, before it had
+#   confirmed that it should.  This causes problems for devices with the
+#   following problems:  a) those who misreport their size (typically
+#   off-by-one), and b) those who fail when asked to read a block
+#   outside their range.
+#   
+#   This patch moves the test for the Protective Master Boot Record (PMBR)
+#   ahead of the tests for the Primary and Alternate GPT headers.  If the
+#   PMBR is not valid, the disk is assumed to not be a GPT disk.  This can
+#   be overridden with the 'gpt' kernel command line option.  If the
+#   Primary GPT header is not valid, the Alternate GPT header is not
+#   probed automatically unless the 'gpt' kernel command line option is
+#   passed.  If the both the PMBR and Primary GPT header are valid, then
+#   the Alternate GPT header at the end of the disk is probed.
+#   
+#   Also re-enables CONFIG_EFI_PARTITION for all architectures.
+#   
+#   Signed-off-by: Matt Domsch <Matt_Domsch@dell.com>
+#   Signed-off-by: Linus Torvalds <torvalds@osdl.org>
+# 
+# fs/partitions/efi.c
+#   2004/11/09 12:43:34-08:00 Matt_Domsch@dell.com +129 -129
+#   EFI GPT: reduce alternate header probing
+# 
+diff -Nru a/fs/partitions/efi.c b/fs/partitions/efi.c
+--- a/fs/partitions/efi.c	2005-01-13 14:43:37 -08:00
++++ b/fs/partitions/efi.c	2005-01-13 14:43:37 -08:00
+@@ -3,7 +3,7 @@
+  * Per Intel EFI Specification v1.02
+  * http://developer.intel.com/technology/efi/efi.htm
+  * efi.[ch] by Matt Domsch <Matt_Domsch@dell.com>
+- *   Copyright 2000,2001,2002 Dell Inc.
++ *   Copyright 2000,2001,2002,2004 Dell Inc.
+  *
+  *  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
+@@ -23,6 +23,11 @@
+  * TODO:
+  *
+  * Changelog:
++ * Mon Nov 09 2004 Matt Domsch <Matt_Domsch@dell.com>
++ * - test for valid PMBR and valid PGPT before ever reading
++ *   AGPT, allow override with 'gpt' kernel command line option.
++ * - check for first/last_usable_lba outside of size of disk
++ *
+  * Tue  Mar 26 2002 Matt Domsch <Matt_Domsch@dell.com>
+  * - Ported to 2.5.7-pre1 and 2.5.7-dj2
+  * - Applied patch to avoid fault in alternate header handling
+@@ -131,32 +136,6 @@
+ }
+ 
+ /**
+- * is_pmbr_valid(): test Protective MBR for validity
+- * @mbr: pointer to a legacy mbr structure
+- *
+- * Description: Returns 1 if PMBR is valid, 0 otherwise.
+- * Validity depends on two things:
+- *  1) MSDOS signature is in the last two bytes of the MBR
+- *  2) One partition of type 0xEE is found
+- */
+-static int
+-is_pmbr_valid(legacy_mbr *mbr)
+-{
+-	int i, found = 0, signature = 0;
+-	if (!mbr)
+-		return 0;
+-	signature = (le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE);
+-	for (i = 0; signature && i < 4; i++) {
+-		if (mbr->partition_record[i].sys_ind ==
+-                    EFI_PMBR_OSTYPE_EFI_GPT) {
+-			found = 1;
+-			break;
+-		}
+-	}
+-	return (signature && found);
+-}
+-
+-/**
+  * last_lba(): return number of last logical block of device
+  * @bdev: block device
+  * 
+@@ -168,7 +147,40 @@
+ static u64
+ last_lba(struct block_device *bdev)
+ {
+-	return (bdev->bd_inode->i_size >> 9) - 1;
++	if (!bdev || !bdev->bd_inode)
++		return 0;
++	return (bdev->bd_inode->i_size >> 9) - 1ULL;
++}
++
++static inline int
++pmbr_part_valid(struct partition *part, u64 lastlba)
++{
++        if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
++            le32_to_cpu(part->start_sect) == 1UL)
++                return 1;
++        return 0;
++}
++
++/**
++ * is_pmbr_valid(): test Protective MBR for validity
++ * @mbr: pointer to a legacy mbr structure
++ * @lastlba: last_lba for the whole device
++ *
++ * Description: Returns 1 if PMBR is valid, 0 otherwise.
++ * Validity depends on two things:
++ *  1) MSDOS signature is in the last two bytes of the MBR
++ *  2) One partition of type 0xEE is found
++ */
++static int
++is_pmbr_valid(legacy_mbr *mbr, u64 lastlba)
++{
++	int i;
++	if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
++                return 0;
++	for (i = 0; i < 4; i++)
++		if (pmbr_part_valid(&mbr->partition_record[i], lastlba))
++                        return 1;
++	return 0;
+ }
+ 
+ /**
+@@ -186,8 +198,8 @@
+ {
+ 	size_t totalreadcount = 0;
+ 
+-	if (!bdev || !buffer)
+-		return 0;
++	if (!bdev || !buffer || lba > last_lba(bdev))
++                return 0;
+ 
+ 	while (count) {
+ 		int copied = 512;
+@@ -206,7 +218,6 @@
+ 	return totalreadcount;
+ }
+ 
+-
+ /**
+  * alloc_read_gpt_entries(): reads partition entries from disk
+  * @bdev
+@@ -289,6 +300,7 @@
+ 	     gpt_header **gpt, gpt_entry **ptes)
+ {
+ 	u32 crc, origcrc;
++	u64 lastlba;
+ 
+ 	if (!bdev || !gpt || !ptes)
+ 		return 0;
+@@ -301,9 +313,7 @@
+ 			"%lld != %lld\n",
+ 			(unsigned long long)le64_to_cpu((*gpt)->signature),
+ 			(unsigned long long)GPT_HEADER_SIGNATURE);
+-		kfree(*gpt);
+-		*gpt = NULL;
+-		return 0;
++		goto fail;
+ 	}
+ 
+ 	/* Check the GUID Partition Table CRC */
+@@ -315,9 +325,7 @@
+ 		Dprintk
+ 		    ("GUID Partition Table Header CRC is wrong: %x != %x\n",
+ 		     crc, origcrc);
+-		kfree(*gpt);
+-		*gpt = NULL;
+-		return 0;
++		goto fail;
+ 	}
+ 	(*gpt)->header_crc32 = cpu_to_le32(origcrc);
+ 
+@@ -327,16 +335,28 @@
+ 		Dprintk("GPT my_lba incorrect: %lld != %lld\n",
+ 			(unsigned long long)le64_to_cpu((*gpt)->my_lba),
+ 			(unsigned long long)lba);
+-		kfree(*gpt);
+-		*gpt = NULL;
+-		return 0;
++		goto fail;
+ 	}
+ 
+-	if (!(*ptes = alloc_read_gpt_entries(bdev, *gpt))) {
+-		kfree(*gpt);
+-		*gpt = NULL;
+-		return 0;
++	/* Check the first_usable_lba and last_usable_lba are
++	 * within the disk.
++	 */
++	lastlba = last_lba(bdev);
++	if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) {
++		Dprintk("GPT: first_usable_lba incorrect: %lld > %lld\n",
++			(unsigned long long)le64_to_cpu((*gpt)->first_usable_lba),
++			(unsigned long long)lastlba);
++		goto fail;
+ 	}
++	if (le64_to_cpu((*gpt)->last_usable_lba) > lastlba) {
++		Dprintk("GPT: last_usable_lba incorrect: %lld > %lld\n",
++			(unsigned long long)le64_to_cpu((*gpt)->last_usable_lba),
++			(unsigned long long)lastlba);
++		goto fail;
++	}
++
++	if (!(*ptes = alloc_read_gpt_entries(bdev, *gpt)))
++		goto fail;
+ 
+ 	/* Check the GUID Partition Entry Array CRC */
+ 	crc = efi_crc32((const unsigned char *) (*ptes),
+@@ -345,15 +365,36 @@
+ 
+ 	if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
+ 		Dprintk("GUID Partitition Entry Array CRC check failed.\n");
+-		kfree(*gpt);
+-		*gpt = NULL;
+-		kfree(*ptes);
+-		*ptes = NULL;
+-		return 0;
++		goto fail_ptes;
+ 	}
+ 
+ 	/* We're done, all's well */
+ 	return 1;
++
++ fail_ptes:
++	kfree(*ptes);
++	*ptes = NULL;
++ fail:
++	kfree(*gpt);
++	*gpt = NULL;
++	return 0;
++}
++
++/**
++ * is_pte_valid() - tests one PTE for validity
++ * @pte is the pte to check
++ * @lastlba is last lba of the disk
++ *
++ * Description: returns 1 if valid,  0 on error.
++ */
++static inline int
++is_pte_valid(const gpt_entry *pte, const u64 lastlba)
++{
++	if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
++	    le64_to_cpu(pte->starting_lba) > lastlba         ||
++	    le64_to_cpu(pte->ending_lba)   > lastlba)
++		return 0;
++	return 1;
+ }
+ 
+ /**
+@@ -464,8 +505,13 @@
+  * @ptes is a PTEs ptr, filled on return.
+  * Description: Returns 1 if valid, 0 on error.
+  * If valid, returns pointers to newly allocated GPT header and PTEs.
+- * Validity depends on finding either the Primary GPT header and PTEs valid,
+- * or the Alternate GPT header and PTEs valid, and the PMBR valid.
++ * Validity depends on PMBR being valid (or being overridden by the
++ * 'gpt' kernel command line option) and finding either the Primary
++ * GPT header and PTEs valid, or the Alternate GPT header and PTEs
++ * valid.  If the Primary GPT header is not valid, the Alternate GPT header
++ * is not checked unless the 'gpt' kernel command line option is passed.
++ * This protects against devices which misreport their size, and forces
++ * the user to decide to use the Alternate GPT.
+  */
+ static int
+ find_valid_gpt(struct block_device *bdev, gpt_header **gpt, gpt_entry **ptes)
+@@ -479,70 +525,43 @@
+ 		return 0;
+ 
+ 	lastlba = last_lba(bdev);
++        if (!force_gpt) {
++                /* This will be added to the EFI Spec. per Intel after v1.02. */
++                legacymbr = kmalloc(sizeof (*legacymbr), GFP_KERNEL);
++                if (legacymbr) {
++                        memset(legacymbr, 0, sizeof (*legacymbr));
++                        read_lba(bdev, 0, (u8 *) legacymbr,
++                                 sizeof (*legacymbr));
++                        good_pmbr = is_pmbr_valid(legacymbr, lastlba);
++                        kfree(legacymbr);
++                        legacymbr=NULL;
++                }
++                if (!good_pmbr)
++                        goto fail;
++        }
++
+ 	good_pgpt = is_gpt_valid(bdev, GPT_PRIMARY_PARTITION_TABLE_LBA,
+ 				 &pgpt, &pptes);
+-        if (good_pgpt) {
++        if (good_pgpt)
+ 		good_agpt = is_gpt_valid(bdev,
+-                                         le64_to_cpu(pgpt->alternate_lba),
++					 le64_to_cpu(pgpt->alternate_lba),
+ 					 &agpt, &aptes);
+-                if (!good_agpt) {
+-                        good_agpt = is_gpt_valid(bdev, lastlba,
+-                                                 &agpt, &aptes);
+-                }
+-        }
+-        else {
++        if (!good_agpt && force_gpt)
+                 good_agpt = is_gpt_valid(bdev, lastlba,
+                                          &agpt, &aptes);
+-        }
+ 
+         /* The obviously unsuccessful case */
+-        if (!good_pgpt && !good_agpt) {
+-                goto fail;
+-        }
+-
+-	/* This will be added to the EFI Spec. per Intel after v1.02. */
+-        legacymbr = kmalloc(sizeof (*legacymbr), GFP_KERNEL);
+-        if (legacymbr) {
+-                memset(legacymbr, 0, sizeof (*legacymbr));
+-                read_lba(bdev, 0, (u8 *) legacymbr,
+-                         sizeof (*legacymbr));
+-                good_pmbr = is_pmbr_valid(legacymbr);
+-                kfree(legacymbr);
+-                legacymbr=NULL;
+-        }
+-
+-        /* Failure due to bad PMBR */
+-        if ((good_pgpt || good_agpt) && !good_pmbr && !force_gpt) {
+-                printk(KERN_WARNING 
+-                       "  Warning: Disk has a valid GPT signature "
+-                       "but invalid PMBR.\n");
+-                printk(KERN_WARNING
+-                       "  Assuming this disk is *not* a GPT disk anymore.\n");
+-                printk(KERN_WARNING
+-                       "  Use gpt kernel option to override.  "
+-                       "Use GNU Parted to correct disk.\n");
++        if (!good_pgpt && !good_agpt)
+                 goto fail;
+-        }
+-
+-        /* Would fail due to bad PMBR, but force GPT anyhow */
+-        if ((good_pgpt || good_agpt) && !good_pmbr && force_gpt) {
+-                printk(KERN_WARNING
+-                       "  Warning: Disk has a valid GPT signature but "
+-                       "invalid PMBR.\n");
+-                printk(KERN_WARNING
+-                       "  Use GNU Parted to correct disk.\n");
+-                printk(KERN_WARNING
+-                       "  gpt option taken, disk treated as GPT.\n");
+-        }
+ 
+         compare_gpts(pgpt, agpt, lastlba);
+ 
+         /* The good cases */
+-        if (good_pgpt && (good_pmbr || force_gpt)) {
++        if (good_pgpt) {
+                 *gpt  = pgpt;
+                 *ptes = pptes;
+-                if (agpt)  { kfree(agpt);   agpt = NULL; }
+-                if (aptes) { kfree(aptes); aptes = NULL; }
++                kfree(agpt);
++                kfree(aptes);
+                 if (!good_agpt) {
+                         printk(KERN_WARNING 
+ 			       "Alternate GPT is invalid, "
+@@ -550,21 +569,21 @@
+                 }
+                 return 1;
+         }
+-        else if (good_agpt && (good_pmbr || force_gpt)) {
++        else if (good_agpt) {
+                 *gpt  = agpt;
+                 *ptes = aptes;
+-                if (pgpt)  { kfree(pgpt);   pgpt = NULL; }
+-                if (pptes) { kfree(pptes); pptes = NULL; }
++                kfree(pgpt);
++                kfree(pptes);
+                 printk(KERN_WARNING 
+                        "Primary GPT is invalid, using alternate GPT.\n");
+                 return 1;
+         }
+ 
+  fail:
+-        if (pgpt)  { kfree(pgpt);   pgpt=NULL; }
+-        if (agpt)  { kfree(agpt);   agpt=NULL; }
+-        if (pptes) { kfree(pptes); pptes=NULL; }
+-        if (aptes) { kfree(aptes); aptes=NULL; }
++        kfree(pgpt);
++        kfree(agpt);
++        kfree(pptes);
++        kfree(aptes);
+         *gpt = NULL;
+         *ptes = NULL;
+         return 0;
+@@ -606,15 +625,15 @@
+ 	Dprintk("GUID Partition Table is valid!  Yea!\n");
+ 
+ 	for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) {
+-		if (!efi_guidcmp(ptes[i].partition_type_guid, NULL_GUID))
++		if (!is_pte_valid(&ptes[i], last_lba(bdev)))
+ 			continue;
+ 
+ 		put_partition(state, i+1, le64_to_cpu(ptes[i].starting_lba),
+ 				 (le64_to_cpu(ptes[i].ending_lba) -
+                                   le64_to_cpu(ptes[i].starting_lba) +
+-				  1));
++				  1ULL));
+ 
+-		/* If there's this is a RAID volume, tell md */
++		/* If this is a RAID volume, tell md */
+ 		if (!efi_guidcmp(ptes[i].partition_type_guid,
+ 				 PARTITION_LINUX_RAID_GUID))
+ 			state->parts[i+1].flags = 1;
+@@ -624,22 +643,3 @@
+ 	printk("\n");
+ 	return 1;
+ }
+-
+-/*
+- * 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:
+- */

Modified: trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/series/2.6.8-13
===================================================================
--- trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/series/2.6.8-13	2005-01-16 11:27:01 UTC (rev 2308)
+++ trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/series/2.6.8-13	2005-01-16 13:59:04 UTC (rev 2309)
@@ -4,3 +4,4 @@
 + 034-stack_resize_exploit.dpatch
 + 035-do_brk_security_fixes-2.dpatch
 + cmsg-compat-signedness-fix-fix.dpatch
++ fs-partitions-efi-update.dpatch