All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] nested partitions
@ 2009-06-11 15:51 Vladimir 'phcoder' Serbinenko
  2009-07-16 20:52 ` Vladimir 'phcoder' Serbinenko
  0 siblings, 1 reply; 36+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-06-11 15:51 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 280 bytes --]

Hello. Here is a first version of nested partition support. Beware
it's EXPERIMENTAL and may be dagerous. Try at your own risk. With this
patch you lose however the ability to specify bsd partition without
specifying slice. Use search.


-- 
Regards
Vladimir 'phcoder' Serbinenko

[-- Attachment #2: nestpart.diff --]
[-- Type: text/x-patch, Size: 60229 bytes --]

diff --git a/ChangeLog b/ChangeLog
index 9802e0e..d748cc8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,71 @@
+2009-06-08  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	Nested partitions
+	
+	* commands/blocklist.c (grub_cmd_blocklist): handle nested partitions
+	* commands/hexdump.c (grub_cmd_hexdump): use grub_disk_read
+	* commands/loadenv.c (check_blocklists): handle nested partitions
+	* conf/common.rmk (grub_probe_SOURCES): add partmap/bsdlabel.c
+	(grub_fstest_SOURCES): likewise
+	(pkglib_MODULES): add bsdlabel.mod
+	(bsdlabel_mod_SOURCES): new variable
+	(bsdlabel_mod_CFLAGS): likewise
+	(bsdlabel_mod_LDFLAGS):likewise
+	* conf/i386-coreboot.rmk (grub_emu_SOURCES): add partmap/bsdlabel.c
+	* conf/i386-pc.rmk (grub_setup_SOURCES): likewise
+	(grub_emu_SOURCES): likewise
+	* conf/powerpc-ieee1275.rmk (grub_emu_SOURCES): likewise
+	* conf/sparc64-ieee1275.rmk (grub_emu_SOURCES): likewise
+	* include/grub/bsdlabel.h: new file
+	* include/grub/partition.h (grub_partition_map): remove probe and 
+	get_name
+	(grub_partition): add parent and number, remove index
+	* include/grub/pc_partition.h: Remove bsd-related entries
+	(grub_pc_partition): remove dos_part, bsd_part, add index. 
+	* kern/disk.c (grub_disk_open): free partition data
+	(grub_disk_adjust_range): handle nested partitions
+	* kern/partition.c (grub_partition_map_probe): new function
+	(grub_partition_probe): parse name to number, handle subpartitions
+	(get_partmap): new function
+	(grub_partition_iterate): handle subpartitions
+	(grub_partition_get_name): likewise
+	* loader/i386/pc/chainloader.c (grub_chainloader_cmd): likewise
+	* partmap/acorn.c (acorn_partition_map_iterate): don't force raw access
+	Use number instead of index
+	(acorn_partition_map_probe): remove
+	(acorn_partition_map_get_name): likewise
+	* partmap/amiga.c (amiga_partition_map_iterate): don't force raw access
+	Use number instead of index
+	(amiga_partition_map_probe): remove
+	(amiga_partition_map_get_name): likewise
+	* partmap/apple.c (apple_partition_map_iterate): don't force raw access
+	Use number instead of index
+	(apple_partition_map_probe): remove
+	(apple_partition_map_get_name): likewise
+	* partmap/bsdlabel.c: new file
+	* partmap/gpt.c (gpt_partition_map_iterate): don't force raw access
+	Use number instead of index
+	(gpt_partition_map_probe): remove
+	(gpt_partition_map_get_name): likewise
+	* partmap/pc.c (grub_partition_parse): remove
+	(pc_partition_map_iterate): don't force raw access
+	move index to pcdata
+	make pcdata a pointer
+	don't handle bsd labels
+	prevent pc_parition from being nested
+	(pc_partition_map_probe): remove
+	(pc_partition_map_get_name): remove
+	* partmap/sun.c (sun_partition_map_iterate): don't force raw access
+	Use number instead of index
+	(sun_partition_map_probe): remove
+	(sun_partition_map_get_name): likewise
+	* parttool/pcpart.c (grub_pcpart_boot): handle nested partitions
+	use index from data
+	(grub_pcpart_type): likewise
+	* util/hostdisk.c (open_device): handle new numbering scheme
+	(grub_util_biosdisk_get_grub_dev): handle nested partitions
+	* util/i386/pc/grub-setup.c (setuo): handle new numbering scheme
+	
 2009-06-10  Pavel Roskin  <proski@gnu.org>
 
 	* io/gzio.c (test_header): Don't reuse one buffer for all data.
diff --git a/commands/blocklist.c b/commands/blocklist.c
index b457b7c..796455a 100644
--- a/commands/blocklist.c
+++ b/commands/blocklist.c
@@ -35,6 +35,8 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)),
   unsigned num_sectors = 0;
   int num_entries = 0;
   grub_disk_addr_t part_start = 0;
+  grub_partition_t part;
+
   auto void NESTED_FUNC_ATTR read_blocklist (grub_disk_addr_t sector, unsigned offset,
 			    unsigned length);
   auto void NESTED_FUNC_ATTR print_blocklist (grub_disk_addr_t sector, unsigned num,
@@ -89,8 +91,9 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)),
     return grub_error (GRUB_ERR_BAD_DEVICE,
 		       "this command is available only for disk devices.");
 
-  if (file->device->disk->partition)
-    part_start = grub_partition_get_start (file->device->disk->partition);
+  part_start = 0;
+  for (part = file->device->disk->partition; part; part = part->parent)
+    part_start += grub_partition_get_start (part);
 
   file->read_hook = read_blocklist;
 
diff --git a/commands/hexdump.c b/commands/hexdump.c
index 0e560c0..f59ba36 100644
--- a/commands/hexdump.c
+++ b/commands/hexdump.c
@@ -22,7 +22,6 @@
 #include <grub/disk.h>
 #include <grub/misc.h>
 #include <grub/gzio.h>
-#include <grub/partition.h>
 #include <grub/lib/hexdump.h>
 #include <grub/extcmd.h>
 
@@ -62,25 +61,20 @@ grub_cmd_hexdump (grub_extcmd_t cmd, int argc, char **args)
       if (! disk)
         return 0;
 
-      if (disk->partition)
-        skip += grub_partition_get_start (disk->partition) << GRUB_DISK_SECTOR_BITS;
-
       sector = (skip >> (GRUB_DISK_SECTOR_BITS + 2)) * 4;
       ofs = skip & (GRUB_DISK_SECTOR_SIZE * 4 - 1);
       while (length)
         {
-          grub_size_t len, n;
+          grub_size_t len;
 
           len = length;
-          if (ofs + len > sizeof (buf))
-            len = sizeof (buf) - ofs;
+          if (len > sizeof (buf))
+            len = sizeof (buf);
 
-          n = ((ofs + len + GRUB_DISK_SECTOR_SIZE - 1)
-               >> GRUB_DISK_SECTOR_BITS);
-          if (disk->dev->read (disk, sector, n, buf))
+          if (grub_disk_read (disk, sector, ofs, len, buf))
             break;
 
-          hexdump (skip, &buf[ofs], len);
+          hexdump (skip, buf, len);
 
           ofs = 0;
           skip += len;
diff --git a/commands/loadenv.c b/commands/loadenv.c
index 22665f9..1cbf0d4 100644
--- a/commands/loadenv.c
+++ b/commands/loadenv.c
@@ -204,6 +204,7 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
   grub_disk_t disk;
   grub_disk_addr_t part_start;
   struct blocklist *p;
+  grub_partition_t part;
   char *buf;
 
   /* Sanity checks.  */
@@ -236,10 +237,10 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
   /* One more sanity check. Re-read all sectors by blocklists, and compare
      those with the data read via a file.  */
   disk = file->device->disk;
-  if (disk->partition)
-    part_start = grub_partition_get_start (disk->partition);
-  else
-    part_start = 0;
+
+  part_start = 0;
+  for (part = disk->partition; part; part = part->parent)
+    part_start += grub_partition_get_start (part);
 
   buf = grub_envblk_buffer (envblk);
   for (p = blocklists, index = 0; p; p = p->next, index += p->length)
diff --git a/conf/common.rmk b/conf/common.rmk
index 027eff2..79b61a2 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -19,7 +19,8 @@ grub_probe_SOURCES = util/grub-probe.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/xfs.c fs/afs.c fs/tar.c			\
 	\
-	partmap/pc.c partmap/apple.c partmap/sun.c partmap/gpt.c\
+	partmap/pc.c partmap/bsdlabel.c partmap/apple.c \
+	partmap/sun.c partmap/gpt.c\
 	kern/fs.c kern/env.c fs/fshelp.c			\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c grub_probe_init.c
 
@@ -40,8 +41,8 @@ grub_fstest_SOURCES = util/grub-fstest.c util/hostfs.c util/misc.c 	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c			\
 	fs/ufs.c fs/xfs.c fs/afs.c fs/tar.c				\
 	\
-	kern/partition.c partmap/pc.c partmap/apple.c partmap/sun.c	\
-	partmap/gpt.c							\
+	kern/partition.c partmap/pc.c partmap/bsdlabel.c partmap/apple.c\
+	partmap/sun.c partmap/gpt.c					\
 	kern/fs.c kern/env.c fs/fshelp.c disk/raid.c			\
 	disk/raid5_recover.c disk/raid6_recover.c 			\
 	disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c 		\
@@ -275,7 +276,8 @@ afs_mod_CFLAGS = $(COMMON_CFLAGS)
 afs_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # Partition maps.
-pkglib_MODULES += amiga.mod apple.mod pc.mod sun.mod acorn.mod gpt.mod
+pkglib_MODULES += amiga.mod apple.mod pc.mod sun.mod acorn.mod gpt.mod \
+		  bsdlabel.mod
 
 # For amiga.mod
 amiga_mod_SOURCES = partmap/amiga.c
@@ -292,6 +294,11 @@ pc_mod_SOURCES = partmap/pc.c
 pc_mod_CFLAGS = $(COMMON_CFLAGS)
 pc_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For pc.mod
+bsdlabel_mod_SOURCES = partmap/bsdlabel.c
+bsdlabel_mod_CFLAGS = $(COMMON_CFLAGS)
+bsdlabel_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For sun.mod
 sun_mod_SOURCES = partmap/sun.c
 sun_mod_CFLAGS = $(COMMON_CFLAGS)
diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk
index 2f768c0..8ffd7da 100644
--- a/conf/i386-coreboot.rmk
+++ b/conf/i386-coreboot.rmk
@@ -86,8 +86,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c       \
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c          \
-	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/bsdlabel.c \
+	partmap/sun.c partmap/acorn.c partmap/gpt.c			\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	util/i386/pc/misc.c 						\
diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk
index 961e616..8036eb1 100644
--- a/conf/i386-ieee1275.rmk
+++ b/conf/i386-ieee1275.rmk
@@ -84,8 +84,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c		\
-	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/bsdlabel.c \
+	partmap/sun.c partmap/acorn.c partmap/gpt.c			\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	util/i386/pc/misc.c						\
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index 4a94443..f79e350 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -110,7 +110,7 @@ grub_setup_SOURCES = util/i386/pc/grub-setup.c util/hostdisk.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/xfs.c fs/afs.c fs/tar.c			\
 	\
-	partmap/pc.c partmap/gpt.c				\
+	partmap/pc.c partmap/bsdlabel.c partmap/gpt.c		\
 	\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
 	util/raid.c util/lvm.c					\
@@ -145,8 +145,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/menu_text.c						\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c		\
-	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/bsdlabel.c partmap/pc.c \
+	partmap/sun.c partmap/acorn.c partmap/gpt.c			\
 	\
 	fs/affs.c fs/cpio.c  fs/fat.c fs/ext2.c fs/hfs.c		\
 	fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c		\
diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk
index 6411111..66c0ce4 100644
--- a/conf/powerpc-ieee1275.rmk
+++ b/conf/powerpc-ieee1275.rmk
@@ -69,8 +69,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c 	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c				\
-	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
-	partmap/acorn.c							\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/bsdlabel.c \
+	partmap/sun.c partmap/acorn.c					\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	util/powerpc/ieee1275/misc.c					\
diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk
index d061416..8d831eb 100644
--- a/conf/sparc64-ieee1275.rmk
+++ b/conf/sparc64-ieee1275.rmk
@@ -80,8 +80,8 @@ grub_setup_SOURCES = util/sparc64/ieee1275/grub-setup.c util/hostdisk.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/xfs.c fs/afs.c fs/tar.c			\
 	\
-	partmap/amiga.c	partmap/apple.c partmap/pc.c		\
-	partmap/sun.c partmap/acorn.c				\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c 		\
+	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c	\
 	\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
 	util/raid.c util/lvm.c					\
diff --git a/include/grub/bsdlabel.h b/include/grub/bsdlabel.h
new file mode 100644
index 0000000..ba75897
--- /dev/null
+++ b/include/grub/bsdlabel.h
@@ -0,0 +1,91 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2004,2007  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_BSDLABEL_PARTITION_HEADER
+#define GRUB_BSDLABEL_PARTITION_HEADER	1
+
+/* Constants for BSD disk label.  */
+#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR	1
+#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC	0x82564557
+#define GRUB_PC_PARTITION_BSD_MAX_ENTRIES	8
+
+/* BSD partition types.  */
+#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED	0
+#define GRUB_PC_PARTITION_BSD_TYPE_SWAP		1
+#define GRUB_PC_PARTITION_BSD_TYPE_V6		2
+#define GRUB_PC_PARTITION_BSD_TYPE_V7		3
+#define GRUB_PC_PARTITION_BSD_TYPE_SYSV		4
+#define GRUB_PC_PARTITION_BSD_TYPE_V71K		5
+#define GRUB_PC_PARTITION_BSD_TYPE_V8		6
+#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS	7
+#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS	8
+#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS	9
+#define GRUB_PC_PARTITION_BSD_TYPE_OTHER	10
+#define GRUB_PC_PARTITION_BSD_TYPE_HPFS		11
+#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660	12
+#define GRUB_PC_PARTITION_BSD_TYPE_BOOT		13
+
+/* FreeBSD-specific types.  */
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM	14
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID	15
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2	21
+
+/* NetBSD-specific types.  */
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_ADOS	14
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_HFS	15
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE	16
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS	17
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_NTFS	18
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_RAID	19
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_CCD	20
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_JFS2	21
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS	22
+
+/* OpenBSD-specific types.  */
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS	14
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_HFS	15
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE	16
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS	17
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS	18
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_RAID	19
+
+/* The BSD partition entry.  */
+struct grub_pc_partition_bsd_entry
+{
+  grub_uint32_t size;
+  grub_uint32_t offset;
+  grub_uint32_t fragment_size;
+  grub_uint8_t fs_type;
+  grub_uint8_t fs_fragments;
+  grub_uint16_t fs_cylinders;
+} __attribute__ ((packed));
+
+/* The BSD disk label. Only define members useful for GRUB.  */
+struct grub_pc_partition_disk_label
+{
+  grub_uint32_t magic;
+  grub_uint8_t padding[128];
+  grub_uint32_t magic2;
+  grub_uint16_t checksum;
+  grub_uint16_t num_partitions;
+  grub_uint32_t boot_size;
+  grub_uint32_t superblock_size;
+  struct grub_pc_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES];
+} __attribute__ ((packed));
+
+#endif /* ! GRUB_PC_PARTITION_HEADER */
diff --git a/include/grub/partition.h b/include/grub/partition.h
index 37c5f24..4b174ff 100644
--- a/include/grub/partition.h
+++ b/include/grub/partition.h
@@ -36,13 +36,6 @@ struct grub_partition_map
 			 int (*hook) (struct grub_disk *disk,
 				      const grub_partition_t partition));
 
-  /* Return the partition named STR on the disk DISK.  */
-  grub_partition_t (*probe) (struct grub_disk *disk,
-			     const char *str);
-
-  /* Return the name of the partition PARTITION.  */
-  char *(*get_name) (const grub_partition_t partition);
-
   /* The next partition map type.  */
   struct grub_partition_map *next;
 };
@@ -51,6 +44,9 @@ typedef struct grub_partition_map *grub_partition_map_t;
 /* Partition description.  */
 struct grub_partition
 {
+  /* The partition number.  */
+  int number;
+
   /* The start sector.  */
   grub_disk_addr_t start;
 
@@ -60,12 +56,12 @@ struct grub_partition
   /* The offset of the partition table.  */
   grub_disk_addr_t offset;
 
-  /* The index of this partition in the partition table.  */
-  int index;
-
   /* Partition map type specific data.  */
   void *data;
 
+  /* Parent partition map.  */
+  struct grub_partition *parent;
+
   /* The type partition map.  */
   grub_partition_map_t partmap;
 };
diff --git a/include/grub/pc_partition.h b/include/grub/pc_partition.h
index 67c312e..8f6a8b9 100644
--- a/include/grub/pc_partition.h
+++ b/include/grub/pc_partition.h
@@ -53,75 +53,6 @@
 #define GRUB_PC_PARTITION_TYPE_GPT_DISK		0xee
 #define GRUB_PC_PARTITION_TYPE_LINUX_RAID	0xfd
 
-/* Constants for BSD disk label.  */
-#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR	1
-#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC	0x82564557
-#define GRUB_PC_PARTITION_BSD_MAX_ENTRIES	8
-
-/* BSD partition types.  */
-#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED	0
-#define GRUB_PC_PARTITION_BSD_TYPE_SWAP		1
-#define GRUB_PC_PARTITION_BSD_TYPE_V6		2
-#define GRUB_PC_PARTITION_BSD_TYPE_V7		3
-#define GRUB_PC_PARTITION_BSD_TYPE_SYSV		4
-#define GRUB_PC_PARTITION_BSD_TYPE_V71K		5
-#define GRUB_PC_PARTITION_BSD_TYPE_V8		6
-#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS	7
-#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS	8
-#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS	9
-#define GRUB_PC_PARTITION_BSD_TYPE_OTHER	10
-#define GRUB_PC_PARTITION_BSD_TYPE_HPFS		11
-#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660	12
-#define GRUB_PC_PARTITION_BSD_TYPE_BOOT		13
-
-/* FreeBSD-specific types.  */
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM	14
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID	15
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2	21
-
-/* NetBSD-specific types.  */
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_ADOS	14
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_HFS	15
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE	16
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS	17
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_NTFS	18
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_RAID	19
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_CCD	20
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_JFS2	21
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS	22
-
-/* OpenBSD-specific types.  */
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS	14
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_HFS	15
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE	16
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS	17
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS	18
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_RAID	19
-
-/* The BSD partition entry.  */
-struct grub_pc_partition_bsd_entry
-{
-  grub_uint32_t size;
-  grub_uint32_t offset;
-  grub_uint32_t fragment_size;
-  grub_uint8_t fs_type;
-  grub_uint8_t fs_fragments;
-  grub_uint16_t fs_cylinders;
-} __attribute__ ((packed));
-
-/* The BSD disk label. Only define members useful for GRUB.  */
-struct grub_pc_partition_disk_label
-{
-  grub_uint32_t magic;
-  grub_uint8_t padding[128];
-  grub_uint32_t magic2;
-  grub_uint16_t checksum;
-  grub_uint16_t num_partitions;
-  grub_uint32_t boot_size;
-  grub_uint32_t superblock_size;
-  struct grub_pc_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES];
-} __attribute__ ((packed));
-
 /* The partition entry.  */
 struct grub_pc_partition_entry
 {
@@ -170,20 +101,14 @@ struct grub_pc_partition_mbr
 \f
 struct grub_pc_partition
 {
-    /* The DOS partition number.  */
-  int dos_part;
-
-  /* The BSD partition number (a == 0).  */
-  int bsd_part;
-
   /* The DOS partition type.  */
   int dos_type;
 
-  /* The BSD partition type.  */
-  int bsd_type;
-
   /* The offset of the extended partition.  */
   unsigned long ext_offset;
+
+  /* The index of this partition in the partition table.  */
+  int index;
 };
 
 static inline int
@@ -200,12 +125,4 @@ grub_pc_partition_is_extended (int type)
 	  || type == GRUB_PC_PARTITION_TYPE_LINUX_EXTENDED);
 }
 
-static inline int
-grub_pc_partition_is_bsd (int type)
-{
-  return (type == GRUB_PC_PARTITION_TYPE_FREEBSD
-	  || type == GRUB_PC_PARTITION_TYPE_OPENBSD
-	  || type == GRUB_PC_PARTITION_TYPE_NETBSD);
-}
-
 #endif /* ! GRUB_PC_PARTITION_HEADER */
diff --git a/kern/disk.c b/kern/disk.c
index ad778d4..7ef2ae1 100644
--- a/kern/disk.c
+++ b/kern/disk.c
@@ -334,6 +334,7 @@ grub_disk_open (const char *name)
 void
 grub_disk_close (grub_disk_t disk)
 {
+  grub_partition_t part;
   grub_dprintf ("disk", "Closing `%s'.\n", disk->name);
 
   if (disk->dev && disk->dev->close)
@@ -342,7 +343,13 @@ grub_disk_close (grub_disk_t disk)
   /* Reset the timer.  */
   grub_last_time = grub_get_time_ms ();
 
-  grub_free (disk->partition);
+  while (disk->partition)
+    {
+      part = disk->partition->parent;
+      grub_free (disk->partition->data);
+      grub_free (disk->partition);
+      disk->partition = part;
+    }
   grub_free ((void *) disk->name);
   grub_free (disk);
 }
@@ -353,18 +360,19 @@ grub_disk_close (grub_disk_t disk)
    - Verify that the range is inside the partition.  */
 static grub_err_t
 grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
-		       grub_off_t *offset, grub_size_t size)
+			grub_off_t *offset, grub_size_t size)
 {
+  grub_partition_t part;
   *sector += *offset >> GRUB_DISK_SECTOR_BITS;
   *offset &= GRUB_DISK_SECTOR_SIZE - 1;
-
-  if (disk->partition)
+  
+  for (part = disk->partition; part; part = part->parent)
     {
       grub_disk_addr_t start;
       grub_uint64_t len;
 
-      start = grub_partition_get_start (disk->partition);
-      len = grub_partition_get_len (disk->partition);
+      start = grub_partition_get_start (part);
+      len = grub_partition_get_len (part);
 
       if (*sector >= len
 	  || len - *sector < ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
diff --git a/kern/partition.c b/kern/partition.c
index 4d5c63a..4f7f2d7 100644
--- a/kern/partition.c
+++ b/kern/partition.c
@@ -17,6 +17,7 @@
  */
 
 #include <grub/misc.h>
+#include <grub/mm.h>
 #include <grub/partition.h>
 #include <grub/disk.h>
 
@@ -54,17 +55,58 @@ grub_partition_map_iterate (int (*hook) (const grub_partition_map_t partmap))
   return 0;
 }
 
+static grub_partition_t
+grub_partition_map_probe (const grub_partition_map_t partmap,
+			  grub_disk_t disk, int partnum)
+{
+  grub_partition_t p = 0;
+
+  auto int find_func (grub_disk_t d, const grub_partition_t partition);
+    
+  int find_func (grub_disk_t d __attribute__ ((unused)),
+		 const grub_partition_t partition)
+    {
+      if (partnum == partition->number)
+	{
+	  p = (grub_partition_t) grub_malloc (sizeof (*p));
+	  if (! p)
+	    return 1;
+	  
+	  grub_memcpy (p, partition, sizeof (*p));
+	  return 1;
+	}
+      
+      return 0;
+    }
+  
+  partmap->iterate (disk, find_func);
+  if (grub_errno)
+    goto fail;
+
+  return p;
+
+ fail:
+  grub_free (p);
+  return 0;
+}
+
 grub_partition_t
 grub_partition_probe (struct grub_disk *disk, const char *str)
 {
   grub_partition_t part = 0;
+  grub_partition_t curpart = 0;
+  grub_partition_t tail;
+  const char *ptr;
+  int num;
 
   auto int part_map_probe (const grub_partition_map_t partmap);
 
   int part_map_probe (const grub_partition_map_t partmap)
     {
-      part = partmap->probe (disk, str);
-      if (part)
+      disk->partition = part;
+      curpart = grub_partition_map_probe (partmap, disk, num);
+      disk->partition = tail;
+      if (curpart)
 	return 1;
 
       if (grub_errno == GRUB_ERR_BAD_PART_TABLE)
@@ -77,27 +119,54 @@ grub_partition_probe (struct grub_disk *disk, const char *str)
       return 1;
     }
 
-  /* Use the first partition map type found.  */
-  grub_partition_map_iterate (part_map_probe);
+  part = tail = disk->partition;
+
+  for (ptr = str; *ptr;)
+    {
+      /* BSD-like partition specification.  */
+      if (*ptr >= 'a' && *ptr <= 'z')
+	num = *(ptr++) - 'a';
+      else
+	num = grub_strtoul (ptr, (char **) &ptr, 0) - 1;
+      
+      curpart = 0;
+      /* Use the first partition map type found.  */
+      grub_partition_map_iterate (part_map_probe);
+      
+      if (! curpart)
+	{
+	  while (part)
+	    {
+	      curpart = part->parent;
+	      grub_free (part);
+	      part = curpart;
+	    }
+	  return 0;
+	}
+      curpart->parent = part;
+      part = curpart;
+      if (! ptr || *ptr != ',')
+	break;
+      ptr++;
+    }
 
   return part;
 }
 
-int
-grub_partition_iterate (struct grub_disk *disk,
-			int (*hook) (grub_disk_t disk,
-				     const grub_partition_t partition))
+static grub_partition_map_t
+get_partmap (struct grub_disk *disk)
 {
   grub_partition_map_t partmap = 0;
-  int ret = 0;
-
+  struct grub_partition part;
+  int found = 0;
   auto int part_map_iterate (const grub_partition_map_t p);
   auto int part_map_iterate_hook (grub_disk_t d,
 				  const grub_partition_t partition);
-
   int part_map_iterate_hook (grub_disk_t d __attribute__ ((unused)),
-			     const grub_partition_t partition __attribute__ ((unused)))
+			     const grub_partition_t partition)
     {
+      found = 1;
+      part = *partition;
       return 1;
     }
 
@@ -106,28 +175,89 @@ grub_partition_iterate (struct grub_disk *disk,
       grub_dprintf ("partition", "Detecting %s...\n", p->name);
       p->iterate (disk, part_map_iterate_hook);
 
-      if (grub_errno != GRUB_ERR_NONE)
+      if (grub_errno != GRUB_ERR_NONE || ! found)
 	{
 	  /* Continue to next partition map type.  */
 	  grub_dprintf ("partition", "%s detection failed.\n", p->name);
 	  grub_errno = GRUB_ERR_NONE;
 	  return 0;
 	}
+      grub_free (part.data);
 
       grub_dprintf ("partition", "%s detection succeeded.\n", p->name);
       partmap = p;
       return 1;
     }
-
   grub_partition_map_iterate (part_map_iterate);
-  if (partmap)
-    ret = partmap->iterate (disk, hook);
+  return partmap;
+}
+
+int
+grub_partition_iterate (struct grub_disk *disk,
+			int (*hook) (grub_disk_t disk,
+				     const grub_partition_t partition))
+{
+  int ret = 0;
+  
+  auto int part_iterate (grub_disk_t dsk, const grub_partition_t p);
 
+  int part_iterate (grub_disk_t dsk,
+		    const grub_partition_t partition)
+    {
+      struct grub_partition p = *partition;
+      grub_partition_map_t partmap = 0;
+      p.parent = dsk->partition;
+      dsk->partition = 0;
+      if (hook (dsk, &p))
+	  return 1;
+      if (p.start != 0)
+	{
+	  dsk->partition = &p;
+	  partmap = get_partmap (dsk);
+	  if (partmap)
+	    ret = partmap->iterate (dsk, part_iterate);
+	}
+      dsk->partition = p.parent;
+      return ret;
+    }
+
+  {
+    grub_partition_map_t partmap = 0;
+    partmap = get_partmap (disk);
+    if (partmap)
+      ret = partmap->iterate (disk, part_iterate);
+  }
+  
   return ret;
 }
 
 char *
 grub_partition_get_name (const grub_partition_t partition)
 {
-  return partition->partmap->get_name (partition);
+  char *out = 0;
+  /* Even on 64-bit machines this buffer is enough to hold longest number.  */
+  char buf[25];
+  int curlen = 0;
+  grub_partition_t part;
+  for (part = partition; part; part = part->parent)
+    {
+      int strl;
+      grub_sprintf (buf, "%d", part->number + 1);
+      strl = grub_strlen (buf);
+      if (curlen)
+	{
+	  out = grub_realloc (out, curlen + strl + 2);
+	  grub_memcpy (out + strl + 1, out, curlen);
+	  out[curlen + 1 + strl] = 0;
+	  grub_memcpy (out, buf, strl);
+	  out[strl] = ',';
+	  curlen = curlen + 1 + strl;
+	}
+      else
+	{
+	  curlen = strl;
+	  out = grub_strdup (buf);
+	}
+    }
+  return out;
 }
diff --git a/loader/i386/pc/chainloader.c b/loader/i386/pc/chainloader.c
index 3befd5e..bcd69f0 100644
--- a/loader/i386/pc/chainloader.c
+++ b/loader/i386/pc/chainloader.c
@@ -101,12 +101,15 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
 	  /* In i386-pc, the id is equal to the BIOS drive number.  */
 	  drive = (int) disk->id;
 
-	  if (p)
+	  if (p && grub_strcmp (p->partmap->name, "pc_partition_map") == 0)
 	    {
+	      disk->parition = p->parent;
 	      grub_disk_read (disk, p->offset, 446, 64,
 			      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
 	      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
-				    + (p->index << 4));
+				    + (((struct grub_pc_partition *) p->data)
+				       ->index << 4));
+	      disk->parition = p;
 	    }
 	}
 
diff --git a/partmap/acorn.c b/partmap/acorn.c
index 42fd61f..0abd961 100644
--- a/partmap/acorn.c
+++ b/partmap/acorn.c
@@ -96,21 +96,17 @@ acorn_partition_map_iterate (grub_disk_t disk,
 					  const grub_partition_t partition))
 {
   struct grub_partition part;
-  struct grub_disk raw;
   struct linux_part map[LINUX_MAP_ENTRIES];
   int i;
-  grub_disk_addr_t sector;
+  grub_disk_addr_t sector = 0;
   grub_err_t err;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
-  err = acorn_partition_map_find (&raw, map, &sector);
+  err = acorn_partition_map_find (disk, map, &sector);
   if (err)
     return err;
 
   part.partmap = &grub_acorn_partition_map;
+  part.data = 0;
 
   for (i = 0; i != LINUX_MAP_ENTRIES; ++i)
     {
@@ -121,7 +117,7 @@ acorn_partition_map_iterate (grub_disk_t disk,
       part.start = sector + map[i].start;
       part.len = map[i].size;
       part.offset = 6;
-      part.index = i;
+      part.number = i;
 
       if (hook (disk, &part))
 	return grub_errno;
@@ -130,60 +126,6 @@ acorn_partition_map_iterate (grub_disk_t disk,
   return GRUB_ERR_NONE;
 }
 
-
-static grub_partition_t
-acorn_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  struct linux_part map[LINUX_MAP_ENTRIES];
-  struct grub_disk raw = *disk;
-  unsigned long partnum = grub_strtoul (str, 0, 10) - 1;
-  grub_disk_addr_t sector;
-  grub_err_t err;
-  grub_partition_t p;
-
-  /* Enforce raw disk access.  */
-  raw.partition = 0;
-
-  /* Get the partition number.  */
-  if (partnum > LINUX_MAP_ENTRIES)
-    goto fail;
-
-  err = acorn_partition_map_find (&raw, map, &sector);
-  if (err)
-    return 0;
-
-  if (map[partnum].magic != LINUX_NATIVE_MAGIC
-      && map[partnum].magic != LINUX_SWAP_MAGIC)
-    goto fail;
-
-  p = grub_malloc (sizeof (struct grub_partition));
-  if (! p)
-    return 0;
-
-  p->start = sector + map[partnum].start;
-  p->len = map[partnum].size;
-  p->offset = 6;
-  p->index = partnum;
-  return p;
-
-fail:
-  grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-  return 0;
-}
-
-
-static char *
-acorn_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
 \f
 
 /* Partition map type.  */
@@ -191,8 +133,6 @@ static struct grub_partition_map grub_acorn_partition_map =
 {
   .name = "Linux/ADFS partition map",
   .iterate = acorn_partition_map_iterate,
-  .probe = acorn_partition_map_probe,
-  .get_name = acorn_partition_map_get_name
 };
 
 GRUB_MOD_INIT(acorn_partition_map)
diff --git a/partmap/amiga.c b/partmap/amiga.c
index ffb807f..b246ca4 100644
--- a/partmap/amiga.c
+++ b/partmap/amiga.c
@@ -76,20 +76,15 @@ amiga_partition_map_iterate (grub_disk_t disk,
 {
   struct grub_partition part;
   struct grub_amiga_rdsk rdsk;
-  struct grub_disk raw;
   int partno = 0;
   int next = -1;
   unsigned pos;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   /* The RDSK block is one of the first 15 blocks.  */
   for (pos = 0; pos < 15; pos++)
     {
       /* Read the RDSK block which is a descriptor for the entire disk.  */
-      if (grub_disk_read (&raw, pos, 0, sizeof (rdsk), &rdsk))
+      if (grub_disk_read (disk, pos, 0, sizeof (rdsk), &rdsk))
 	return grub_errno;
 
       if (grub_strcmp ((char *) rdsk.magic, "RDSK") == 0)
@@ -104,13 +99,15 @@ amiga_partition_map_iterate (grub_disk_t disk,
     return grub_error (GRUB_ERR_BAD_PART_TABLE,
 		       "Amiga partition map not found.");
 
+  part.data = 0;
+
   /* The end of the partition list is marked using "-1".  */
   while (next != -1)
     {
       struct grub_amiga_partition apart;
 
       /* Read the RDSK block which is a descriptor for the entire disk.  */
-      if (grub_disk_read (&raw, next, 0, sizeof (apart), &apart))
+      if (grub_disk_read (disk, next, 0, sizeof (apart), &apart))
 	return grub_errno;
 
       /* Calculate the first block and the size of the partition.  */
@@ -123,7 +120,7 @@ amiga_partition_map_iterate (grub_disk_t disk,
 		  * grub_be_to_cpu32 (apart.block_per_track));
 
       part.offset = (grub_off_t) next * 512;
-      part.index = partno;
+      part.number = partno;
       part.partmap = &grub_amiga_partition_map;
 
       if (hook (disk, &part))
@@ -136,72 +133,12 @@ amiga_partition_map_iterate (grub_disk_t disk,
   return 0;
 }
 
-
-static grub_partition_t
-amiga_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  if (amiga_partition_map_iterate (disk, find_func))
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-amiga_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_amiga_partition_map =
   {
     .name = "amiga_partition_map",
     .iterate = amiga_partition_map_iterate,
-    .probe = amiga_partition_map_probe,
-    .get_name = amiga_partition_map_get_name
   };
 
 GRUB_MOD_INIT(amiga_partition_map)
diff --git a/partmap/apple.c b/partmap/apple.c
index fce2f2c..1621086 100644
--- a/partmap/apple.c
+++ b/partmap/apple.c
@@ -104,17 +104,12 @@ apple_partition_map_iterate (grub_disk_t disk,
   struct grub_partition part;
   struct grub_apple_header aheader;
   struct grub_apple_part apart;
-  struct grub_disk raw;
   int partno = 0;
   unsigned pos = GRUB_DISK_SECTOR_SIZE;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   part.partmap = &grub_apple_partition_map;
 
-  if (grub_disk_read (&raw, 0, 0, sizeof (aheader), &aheader))
+  if (grub_disk_read (disk, 0, 0, sizeof (aheader), &aheader))
     return grub_errno;
 
   if (grub_be_to_cpu16 (aheader.magic) != GRUB_APPLE_HEADER_MAGIC)
@@ -126,9 +121,11 @@ apple_partition_map_iterate (grub_disk_t disk,
       goto fail;
     }
 
+  part.data = 0;
+
   for (;;)
     {
-      if (grub_disk_read (&raw, pos / GRUB_DISK_SECTOR_SIZE,
+      if (grub_disk_read (disk, pos / GRUB_DISK_SECTOR_SIZE,
 			  pos % GRUB_DISK_SECTOR_SIZE,
 			  sizeof (struct grub_apple_part),  &apart))
 	return grub_errno;
@@ -145,7 +142,7 @@ apple_partition_map_iterate (grub_disk_t disk,
       part.start = grub_be_to_cpu32 (apart.first_phys_block);
       part.len = grub_be_to_cpu32 (apart.blockcnt);
       part.offset = pos;
-      part.index = partno;
+      part.number = partno;
 
       grub_dprintf ("partition",
 		    "partition %d: name %s, type %s, start 0x%x, len 0x%x\n",
@@ -172,72 +169,12 @@ apple_partition_map_iterate (grub_disk_t disk,
 		     "Apple partition map not found.");
 }
 
-
-static grub_partition_t
-apple_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  if (apple_partition_map_iterate (disk, find_func))
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-apple_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_apple_partition_map =
   {
     .name = "apple_partition_map",
     .iterate = apple_partition_map_iterate,
-    .probe = apple_partition_map_probe,
-    .get_name = apple_partition_map_get_name
   };
 
 GRUB_MOD_INIT(apple_partition_map)
diff --git a/partmap/bsdlabel.c b/partmap/bsdlabel.c
new file mode 100644
index 0000000..b7cbfb2
--- /dev/null
+++ b/partmap/bsdlabel.c
@@ -0,0 +1,89 @@
+/* bsdlabel.c - Read BSD style partition tables.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2004,2005,2006,2007,2008,2009  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/partition.h>
+#include <grub/bsdlabel.h>
+#include <grub/disk.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/dl.h>
+
+static struct grub_partition_map grub_bsdlabel_partition_map;
+\f
+
+static grub_err_t
+bsdlabel_partition_map_iterate (grub_disk_t disk,
+			  int (*hook) (grub_disk_t disk,
+				       const grub_partition_t partition))
+{
+  struct grub_pc_partition_disk_label label;  
+  struct grub_partition p;
+  grub_partition_t part;
+  grub_disk_addr_t delta = 0;
+
+  /* BSDLabel offsets are absolute even when it's embed inside partition.  */
+  for (part = disk->partition; part; part = part->parent)
+    delta += grub_partition_get_start (part);
+
+  /* Read the BSD label.  */
+  if (grub_disk_read (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR,
+		      0, sizeof (label), &label))
+    goto finish;
+
+  /* Check if it is valid.  */
+  if (label.magic != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
+    return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
+  for (p.number = 0;
+       p.number < grub_cpu_to_le16 (label.num_partitions);
+       p.number++)
+    {
+      struct grub_pc_partition_bsd_entry *be
+	= label.entries + p.number;
+
+      p.start = grub_le_to_cpu32 (be->offset) - delta;
+      p.len = grub_le_to_cpu32 (be->size);
+      p.offset = GRUB_PC_PARTITION_BSD_LABEL_SECTOR;
+      p.partmap = &grub_bsdlabel_partition_map;
+      p.data = 0;
+		      
+      if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
+	if (hook (disk, &p))
+	  return 1;
+    }
+ finish:
+  return grub_errno;
+}
+
+\f
+/* Partition map type.  */
+static struct grub_partition_map grub_bsdlabel_partition_map =
+  {
+    .name = "bsdlabel_partition_map",
+    .iterate = bsdlabel_partition_map_iterate,
+  };
+
+GRUB_MOD_INIT(bsdlabel_partition_map)
+{
+  grub_partition_map_register (&grub_bsdlabel_partition_map);
+}
+
+GRUB_MOD_FINI(bsdlabel_partition_map)
+{
+  grub_partition_map_unregister (&grub_bsdlabel_partition_map);
+}
diff --git a/partmap/gpt.c b/partmap/gpt.c
index d646d41..bfe6269 100644
--- a/partmap/gpt.c
+++ b/partmap/gpt.c
@@ -44,18 +44,13 @@ gpt_partition_map_iterate (grub_disk_t disk,
   struct grub_partition part;
   struct grub_gpt_header gpt;
   struct grub_gpt_partentry entry;
-  struct grub_disk raw;
   struct grub_pc_partition_mbr mbr;
   grub_uint64_t entries;
   unsigned int i;
   int last_offset = 0;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   /* Read the protective MBR.  */
-  if (grub_disk_read (&raw, 0, 0, sizeof (mbr), &mbr))
+  if (grub_disk_read (disk, 0, 0, sizeof (mbr), &mbr))
     return grub_errno;
 
   /* Check if it is valid.  */
@@ -67,7 +62,7 @@ gpt_partition_map_iterate (grub_disk_t disk,
     return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
 
   /* Read the GPT header.  */
-  if (grub_disk_read (&raw, 1, 0, sizeof (gpt), &gpt))
+  if (grub_disk_read (disk, 1, 0, sizeof (gpt), &gpt))
     return grub_errno;
 
   if (grub_memcmp (gpt.magic, grub_gpt_magic, sizeof (grub_gpt_magic)))
@@ -78,7 +73,7 @@ gpt_partition_map_iterate (grub_disk_t disk,
   entries = grub_le_to_cpu64 (gpt.partitions);
   for (i = 0; i < grub_le_to_cpu32 (gpt.maxpart); i++)
     {
-      if (grub_disk_read (&raw, entries, last_offset,
+      if (grub_disk_read (disk, entries, last_offset,
 			  sizeof (entry), &entry))
 	return grub_errno;
 
@@ -90,9 +85,9 @@ gpt_partition_map_iterate (grub_disk_t disk,
 	  part.len = (grub_le_to_cpu64 (entry.end)
 		      - grub_le_to_cpu64 (entry.start) + 1);
 	  part.offset = entries;
-	  part.index = i;
+	  part.number = i;
 	  part.partmap = &grub_gpt_partition_map;
-	  part.data = &entry;
+	  part.data = 0;
 
 	  grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", i,
 			(unsigned long long) part.start,
@@ -113,73 +108,12 @@ gpt_partition_map_iterate (grub_disk_t disk,
   return 0;
 }
 
-
-static grub_partition_t
-gpt_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  gpt_partition_map_iterate (disk, find_func);
-  if (grub_errno)
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-gpt_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_gpt_partition_map =
   {
     .name = "gpt_partition_map",
     .iterate = gpt_partition_map_iterate,
-    .probe = gpt_partition_map_probe,
-    .get_name = gpt_partition_map_get_name
   };
 
 GRUB_MOD_INIT(gpt_partition_map)
diff --git a/partmap/pc.c b/partmap/pc.c
index 6f68ecf..fdc2e5c 100644
--- a/partmap/pc.c
+++ b/partmap/pc.c
@@ -27,178 +27,82 @@
 static struct grub_partition_map grub_pc_partition_map;
 \f
 
-/* Parse the partition representation in STR and return a partition.  */
-static grub_partition_t
-grub_partition_parse (const char *str)
-{
-  grub_partition_t p;
-  struct grub_pc_partition *pcdata;
-
-  char *s = (char *) str;
-
-  p = (grub_partition_t) grub_malloc (sizeof (*p));
-  if (! p)
-    return 0;
-
-  pcdata = (struct grub_pc_partition *) grub_malloc (sizeof (*pcdata));
-  if (! pcdata)
-    goto fail;
-
-  p->data = pcdata;
-  p->partmap = &grub_pc_partition_map;
-
-  /* Initialize some of the fields with invalid values.  */
-  pcdata->bsd_part = pcdata->dos_type = pcdata->bsd_type = p->index = -1;
-
-  /* Get the DOS partition number. The number is counted from one for
-     the user interface, and from zero internally.  */
-  pcdata->dos_part = grub_strtoul (s, &s, 0) - 1;
-
-  if (grub_errno)
-    {
-      /* Not found. Maybe only a BSD label is specified.  */
-      pcdata->dos_part = -1;
-      grub_errno = GRUB_ERR_NONE;
-    }
-  else if (*s == ',')
-    s++;
-
-  if (*s)
-    {
-      if (*s >= 'a' && *s <= 'h')
-	{
-	  pcdata->bsd_part = *s - 'a';
-	  s++;
-	}
-
-      if (*s)
-	goto fail;
-    }
-
-  if (pcdata->dos_part == -1 && pcdata->bsd_part == -1)
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  grub_free (pcdata);
-  grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-  return 0;
-}
-
 static grub_err_t
 pc_partition_map_iterate (grub_disk_t disk,
 			  int (*hook) (grub_disk_t disk,
 				       const grub_partition_t partition))
 {
   struct grub_partition p;
-  struct grub_pc_partition pcdata;
+  struct grub_pc_partition *pcdata;
   struct grub_pc_partition_mbr mbr;
-  struct grub_pc_partition_disk_label label;
-  struct grub_disk raw;
-
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
 
+  pcdata = grub_malloc (sizeof (*pcdata));
   p.offset = 0;
-  pcdata.ext_offset = 0;
-  pcdata.dos_part = -1;
-  p.data = &pcdata;
+  pcdata->ext_offset = 0;
+  p.data = pcdata;
+  p.number = -1;
   p.partmap = &grub_pc_partition_map;
 
+  /* Signature check is known to cause false positives 
+     because the same signature is used for bootsectors.  */
+  if (disk->partition)
+    {
+      grub_free (pcdata);
+      return grub_error (GRUB_ERR_BAD_PART_TABLE, 
+			 "pc partition can't be nested");
+    }
+
   while (1)
     {
       int i;
       struct grub_pc_partition_entry *e;
 
       /* Read the MBR.  */
-      if (grub_disk_read (&raw, p.offset, 0, sizeof (mbr), &mbr))
+      if (grub_disk_read (disk, p.offset, 0, sizeof (mbr), &mbr))
 	goto finish;
 
       /* Check if it is valid.  */
       if (mbr.signature != grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE))
-	return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
+	{
+	  grub_free (pcdata);
+	  return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
+	}
 
       /* Analyze DOS partitions.  */
-      for (p.index = 0; p.index < 4; p.index++)
+      for (pcdata->index = 0; pcdata->index < 4; pcdata->index++)
 	{
-	  e = mbr.entries + p.index;
-
+	  e = mbr.entries + pcdata->index;
+	  
 	  p.start = p.offset + grub_le_to_cpu32 (e->start);
 	  p.len = grub_le_to_cpu32 (e->length);
-	  pcdata.bsd_part = -1;
-	  pcdata.dos_type = e->type;
-	  pcdata.bsd_type = -1;
+	  pcdata->dos_type = e->type;
 
 	  grub_dprintf ("partition",
 			"partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n",
-			p.index, e->flag, pcdata.dos_type,
+			pcdata->index, e->flag, pcdata->dos_type,
 			(unsigned long long) p.start,
 			(unsigned long long) p.len);
 
 	  /* If this is a GPT partition, this MBR is just a dummy.  */
-	  if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && p.index == 0)
-	    return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr");
+	  if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && pcdata->index == 0)
+	    {
+	      grub_free (pcdata);
+	      return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr");
+	    }
 
 	  /* If this partition is a normal one, call the hook.  */
 	  if (! grub_pc_partition_is_empty (e->type)
 	      && ! grub_pc_partition_is_extended (e->type))
 	    {
-	      pcdata.dos_part++;
-
+	      p.number++;
+	      
 	      if (hook (disk, &p))
 		return 1;
-
-	      /* Check if this is a BSD partition.  */
-	      if (grub_pc_partition_is_bsd (e->type))
-		{
-		  /* Check if the BSD label is within the DOS partition.  */
-		  if (p.len <= GRUB_PC_PARTITION_BSD_LABEL_SECTOR)
-		    {
-		      grub_dprintf ("partition", "no space for disk label\n");
-		      continue;
-		    }
-		  /* Read the BSD label.  */
-		  if (grub_disk_read (&raw,
-				      (p.start
-				       + GRUB_PC_PARTITION_BSD_LABEL_SECTOR),
-				      0,
-				      sizeof (label),
-				      &label))
-		    goto finish;
-
-		  /* Check if it is valid.  */
-		  if (label.magic
-		      != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
-		    {
-		      grub_dprintf ("partition",
-				    "invalid disk label magic 0x%x on partition %d\n",
-				    label.magic, p.index);
-		      continue;
-		    }
-		  for (pcdata.bsd_part = 0;
-		       pcdata.bsd_part < grub_cpu_to_le16 (label.num_partitions);
-		       pcdata.bsd_part++)
-		    {
-		      struct grub_pc_partition_bsd_entry *be
-			= label.entries + pcdata.bsd_part;
-
-		      p.start = grub_le_to_cpu32 (be->offset);
-		      p.len = grub_le_to_cpu32 (be->size);
-		      pcdata.bsd_type = be->fs_type;
-
-		      if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
-			if (hook (disk, &p))
-			  return 1;
-		    }
-		}
 	    }
-	  else if (pcdata.dos_part < 4)
+	  else if (p.number < 4)
 	    /* If this partition is a logical one, shouldn't increase the
 	       partition number.  */
-	    pcdata.dos_part++;
+	    p.number++;
 	}
 
       /* Find an extended partition.  */
@@ -208,9 +112,9 @@ pc_partition_map_iterate (grub_disk_t disk,
 
 	  if (grub_pc_partition_is_extended (e->type))
 	    {
-	      p.offset = pcdata.ext_offset + grub_le_to_cpu32 (e->start);
-	      if (! pcdata.ext_offset)
-		pcdata.ext_offset = p.offset;
+	      p.offset = pcdata->ext_offset + grub_le_to_cpu32 (e->start);
+	      if (! pcdata->ext_offset)
+		pcdata->ext_offset = p.offset;
 
 	      break;
 	    }
@@ -222,77 +126,8 @@ pc_partition_map_iterate (grub_disk_t disk,
     }
 
  finish:
-  return grub_errno;
-}
-
-
-static grub_partition_t
-pc_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p;
-  struct grub_pc_partition *pcdata;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      struct grub_pc_partition *partdata = partition->data;
-
-      if ((pcdata->dos_part == partdata->dos_part || pcdata->dos_part == -1)
-	  && pcdata->bsd_part == partdata->bsd_part)
-	{
-	  grub_memcpy (p, partition, sizeof (*p));
-	  p->data = pcdata;
-	  grub_memcpy (pcdata, partdata, sizeof (*pcdata));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  p = grub_partition_parse (str);
-  if (! p)
-    return 0;
-
-  pcdata = p->data;
-  pc_partition_map_iterate (disk, find_func);
-  if (grub_errno)
-    goto fail;
-
-  if (p->index < 0)
-    {
-      grub_error (GRUB_ERR_BAD_DEVICE, "no such partition");
-      goto fail;
-    }
-
-  return p;
-
- fail:
-  grub_free (p);
   grub_free (pcdata);
-  return 0;
-}
-
-
-static char *
-pc_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-  struct grub_pc_partition *pcdata = p->data;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  if (pcdata->bsd_part < 0)
-    grub_sprintf (name, "%d", pcdata->dos_part + 1);
-  else if (pcdata->dos_part < 0)
-    grub_sprintf (name, "%c", pcdata->bsd_part + 'a');
-  else
-    grub_sprintf (name, "%d,%c", pcdata->dos_part + 1, pcdata->bsd_part + 'a');
-
-  return name;
+  return grub_errno;
 }
 
 \f
@@ -301,8 +136,6 @@ static struct grub_partition_map grub_pc_partition_map =
   {
     .name = "pc_partition_map",
     .iterate = pc_partition_map_iterate,
-    .probe = pc_partition_map_probe,
-    .get_name = pc_partition_map_get_name
   };
 
 GRUB_MOD_INIT(pc_partition_map)
diff --git a/partmap/sun.c b/partmap/sun.c
index 6094777..c6633a1 100644
--- a/partmap/sun.c
+++ b/partmap/sun.c
@@ -88,13 +88,9 @@ sun_partition_map_iterate (grub_disk_t disk,
 					const grub_partition_t partition))
 {
   grub_partition_t p;
-  struct grub_disk raw;
   struct grub_sun_block block;
   int partnum;
 
-  raw = *disk;
-  raw.partition = 0;
-
   p = (grub_partition_t) grub_malloc (sizeof (struct grub_partition));
   if (! p)
     return grub_errno;
@@ -102,7 +98,7 @@ sun_partition_map_iterate (grub_disk_t disk,
   p->offset = 0;
   p->data = 0;
   p->partmap = &grub_sun_partition_map;
-  if (grub_disk_read (&raw, 0, 0, sizeof (struct grub_sun_block),
+  if (grub_disk_read (disk, 0, 0, sizeof (struct grub_sun_block),
 		      &block) == GRUB_ERR_NONE)
     {
       if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.magic))
@@ -126,7 +122,7 @@ sun_partition_map_iterate (grub_disk_t disk,
 		      * grub_be_to_cpu16 (block.ntrks)
 		      * grub_be_to_cpu16 (block.nsect));
 	  p->len = grub_be_to_cpu32 (desc->num_sectors);
-	  p->index = partnum;
+	  p->number = partnum;
 	  if (p->len)
 	    {
 	      if (hook (disk, p))
@@ -140,68 +136,11 @@ sun_partition_map_iterate (grub_disk_t disk,
   return grub_errno;
 }
 
-static grub_partition_t
-sun_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-        {
-          p = (grub_partition_t) grub_malloc (sizeof (*p));
-          if (p)
-            grub_memcpy (p, partition, sizeof (*p));
-
-          return 1;
-        }
-
-      return 0;
-    }
-
-  grub_errno = GRUB_ERR_NONE;
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno == GRUB_ERR_NONE)
-    {
-      if (sun_partition_map_iterate (disk, find_func))
-        {
-          grub_free (p);
-          p = 0;
-        }
-    }
-  else
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      p = 0;
-    }
-
-  return p;
-}
-
-static char *
-sun_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (name)
-    grub_sprintf (name, "%d", p->index + 1);
-
-  return name;
-}
-
 /* Partition map type.  */
 static struct grub_partition_map grub_sun_partition_map =
   {
     .name = "sun_partition_map",
     .iterate = sun_partition_map_iterate,
-    .probe = sun_partition_map_probe,
-    .get_name = sun_partition_map_get_name
   };
 
 GRUB_MOD_INIT(sun_partition_map)
diff --git a/parttool/pcpart.c b/parttool/pcpart.c
index 6876d0d..c0c53e6 100644
--- a/parttool/pcpart.c
+++ b/parttool/pcpart.c
@@ -47,9 +47,9 @@ static grub_err_t grub_pcpart_boot (const grub_device_t dev,
   if (dev->disk->partition->offset)
     return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a primary partition");
 
-  index = dev->disk->partition->index;
+  index = ((struct grub_pc_partition *) dev->disk->partition->data)->index;
   part = dev->disk->partition;
-  dev->disk->partition = 0;
+  dev->disk->partition = part->parent;
 
   /* Read the MBR.  */
   if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr))
@@ -94,9 +94,9 @@ static grub_err_t grub_pcpart_type (const grub_device_t dev,
   grub_partition_t part;
   struct grub_pc_partition_mbr mbr;
 
-  index = dev->disk->partition->index;
+  index = ((struct grub_pc_partition *) dev->disk->partition->data)->index;
   part = dev->disk->partition;
-  dev->disk->partition = 0;
+  dev->disk->partition = part->parent;
 
   /* Read the parttable.  */
   if (grub_disk_read (dev->disk, part->offset, 0,
diff --git a/util/hostdisk.c b/util/hostdisk.c
index 1844a7e..675d117 100644
--- a/util/hostdisk.c
+++ b/util/hostdisk.c
@@ -321,10 +321,15 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
   {
     int is_partition = 0;
     char dev[PATH_MAX];
+    grub_partition_t part;
+    grub_disk_addr_t part_start = 0;
+
+    for (part = disk->partition; part; part = part->parent)
+      part_start += grub_partition_get_start (part);
 
     strcpy (dev, map[disk->id].device);
     if (disk->partition && strncmp (map[disk->id].device, "/dev/", 5) == 0)
-      is_partition = linux_find_partition (dev, disk->partition->start);
+      is_partition = linux_find_partition (dev, part_start);
 
     /* Open the partition.  */
     grub_dprintf ("hostdisk", "opening the device `%s' in open_device()", dev);
@@ -339,7 +344,7 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
     ioctl (fd, BLKFLSBUF, 0);
 
     if (is_partition)
-      sector -= disk->partition->start;
+      sector -= part_start;
   }
 #else /* ! __linux__ */
 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -917,39 +922,27 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
     int find_partition (grub_disk_t disk __attribute__ ((unused)),
 			const grub_partition_t partition)
       {
- 	struct grub_pc_partition *pcdata = NULL;
-
-	if (strcmp (partition->partmap->name, "pc_partition_map") == 0)
-	  pcdata = partition->data;
+	grub_partition_t part;
+	grub_disk_addr_t part_start = 0;
+	grub_util_info ("Partition %d starts from %lu",
+			partition->number, partition->start);
 
-	if (pcdata)
-	  {
-	    if (pcdata->bsd_part < 0)
-	      grub_util_info ("DOS partition %d starts from %lu",
-			      pcdata->dos_part, partition->start);
-	    else
-	      grub_util_info ("BSD partition %d,%c starts from %lu",
-			      pcdata->dos_part, pcdata->bsd_part + 'a',
-			      partition->start);
-	  }
-	else
-	  {
-	      grub_util_info ("Partition %d starts from %lu",
-			      partition->index, partition->start);
-	  }
+	for (part = partition; part; part = part->parent)
+	  part_start += grub_partition_get_start (part);
 
-	if (hdg.start == partition->start)
+	if (hdg.start == part_start)
 	  {
-	    if (pcdata)
+	    if (partition->parent)
 	      {
-		dos_part = pcdata->dos_part;
-		bsd_part = pcdata->bsd_part;
+		dos_part = partition->parent->number;
+		bsd_part = partition->number;
 	      }
 	    else
 	      {
-		dos_part = partition->index;
+		dos_part = partition->number;	  
 		bsd_part = -1;
 	      }
+
 	    return 1;
 	  }
 
diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c
index bdf234c..193fa99 100644
--- a/util/i386/pc/grub-setup.c
+++ b/util/i386/pc/grub-setup.c
@@ -128,7 +128,6 @@ setup (const char *dir,
 
       /* For its end offset, include as many dummy partitions as we can.  */
       if (! grub_pc_partition_is_empty (pcdata->dos_type)
-	  && ! grub_pc_partition_is_bsd (pcdata->dos_type)
 	  && embed_region.end > p->start)
 	embed_region.end = p->start;
 
@@ -279,22 +278,19 @@ setup (const char *dir,
       /* Embed information about the installed location.  */
       if (root_dev->disk->partition)
 	{
-	  if (strcmp (root_dev->disk->partition->partmap->name,
-		      "pc_partition_map") == 0)
+	  if (root_dev->disk->partition->parent)
 	    {
-	      struct grub_pc_partition *pcdata =
-		root_dev->disk->partition->data;
-	      dos_part = pcdata->dos_part;
-	      bsd_part = pcdata->bsd_part;
+	      if (root_dev->disk->partition->parent->parent)
+		grub_util_error ("Installing on doubly nested partitiond is "
+				 "not supported");
+	      dos_part = root_dev->disk->partition->parent->number;
+	      bsd_part = root_dev->disk->partition->number;
 	    }
-	  else if (strcmp (root_dev->disk->partition->partmap->name,
-			   "gpt_partition_map") == 0)
+	  else
 	    {
-	      dos_part = root_dev->disk->partition->index;
+	      dos_part = root_dev->disk->partition->number;	  
 	      bsd_part = -1;
 	    }
-	  else
-	    grub_util_error ("No PC style partitions found");
 	}
       else
 	dos_part = bsd_part = -1;

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-06-11 15:51 [PATCH] nested partitions Vladimir 'phcoder' Serbinenko
@ 2009-07-16 20:52 ` Vladimir 'phcoder' Serbinenko
  2009-07-31  7:58   ` Marco Gerards
  2009-08-02 22:02   ` Robert Millan
  0 siblings, 2 replies; 36+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-07-16 20:52 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 503 bytes --]

Rediff

On Thu, Jun 11, 2009 at 5:51 PM, Vladimir 'phcoder'
Serbinenko<phcoder@gmail.com> wrote:
> Hello. Here is a first version of nested partition support. Beware
> it's EXPERIMENTAL and may be dagerous. Try at your own risk. With this
> patch you lose however the ability to specify bsd partition without
> specifying slice. Use search.
>
>
> --
> Regards
> Vladimir 'phcoder' Serbinenko
>



-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git

[-- Attachment #2: nestpart.diff --]
[-- Type: text/plain, Size: 62908 bytes --]

diff --git a/ChangeLog b/ChangeLog
index e617831..0e02e01 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,71 @@
+2009-06-08  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	Nested partitions
+
+	* commands/blocklist.c (grub_cmd_blocklist): handle nested partitions
+	* commands/hexdump.c (grub_cmd_hexdump): use grub_disk_read
+	* commands/loadenv.c (check_blocklists): handle nested partitions
+	* conf/common.rmk (grub_probe_SOURCES): add partmap/bsdlabel.c
+	(grub_fstest_SOURCES): likewise
+	(pkglib_MODULES): add bsdlabel.mod
+	(bsdlabel_mod_SOURCES): new variable
+	(bsdlabel_mod_CFLAGS): likewise
+	(bsdlabel_mod_LDFLAGS):likewise
+	* conf/i386-coreboot.rmk (grub_emu_SOURCES): add partmap/bsdlabel.c
+	* conf/i386-pc.rmk (grub_setup_SOURCES): likewise
+	(grub_emu_SOURCES): likewise
+	* conf/powerpc-ieee1275.rmk (grub_emu_SOURCES): likewise
+	* conf/sparc64-ieee1275.rmk (grub_emu_SOURCES): likewise
+	* include/grub/bsdlabel.h: new file
+	* include/grub/partition.h (grub_partition_map): remove probe and
+	get_name
+	(grub_partition): add parent and number, remove index
+	* include/grub/pc_partition.h: Remove bsd-related entries
+	(grub_pc_partition): remove dos_part, bsd_part, add index.
+	* kern/disk.c (grub_disk_open): free partition data
+	(grub_disk_adjust_range): handle nested partitions
+	* kern/partition.c (grub_partition_map_probe): new function
+	(grub_partition_probe): parse name to number, handle subpartitions
+	(get_partmap): new function
+	(grub_partition_iterate): handle subpartitions
+	(grub_partition_get_name): likewise
+	* loader/i386/pc/chainloader.c (grub_chainloader_cmd): likewise
+	* partmap/acorn.c (acorn_partition_map_iterate): don't force raw access
+	Use number instead of index
+	(acorn_partition_map_probe): remove
+	(acorn_partition_map_get_name): likewise
+	* partmap/amiga.c (amiga_partition_map_iterate): don't force raw access
+	Use number instead of index
+	(amiga_partition_map_probe): remove
+	(amiga_partition_map_get_name): likewise
+	* partmap/apple.c (apple_partition_map_iterate): don't force raw access
+	Use number instead of index
+	(apple_partition_map_probe): remove
+	(apple_partition_map_get_name): likewise
+	* partmap/bsdlabel.c: new file
+	* partmap/gpt.c (gpt_partition_map_iterate): don't force raw access
+	Use number instead of index
+	(gpt_partition_map_probe): remove
+	(gpt_partition_map_get_name): likewise
+	* partmap/pc.c (grub_partition_parse): remove
+	(pc_partition_map_iterate): don't force raw access
+	move index to pcdata
+	make pcdata a pointer
+	don't handle bsd labels
+	prevent pc_parition from being nested
+	(pc_partition_map_probe): remove
+	(pc_partition_map_get_name): remove
+	* partmap/sun.c (sun_partition_map_iterate): don't force raw access
+	Use number instead of index
+	(sun_partition_map_probe): remove
+	(sun_partition_map_get_name): likewise
+	* parttool/pcpart.c (grub_pcpart_boot): handle nested partitions
+	use index from data
+	(grub_pcpart_type): likewise
+	* util/hostdisk.c (open_device): handle new numbering scheme
+	(grub_util_biosdisk_get_grub_dev): handle nested partitions
+	* util/i386/pc/grub-setup.c (setuo): handle new numbering scheme
+
 2009-07-16  Vladimir Serbinenko  <phcoder@gmail.com>
 
 	Enable all targets that can be built by default
diff --git a/commands/blocklist.c b/commands/blocklist.c
index b457b7c..796455a 100644
--- a/commands/blocklist.c
+++ b/commands/blocklist.c
@@ -35,6 +35,8 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)),
   unsigned num_sectors = 0;
   int num_entries = 0;
   grub_disk_addr_t part_start = 0;
+  grub_partition_t part;
+
   auto void NESTED_FUNC_ATTR read_blocklist (grub_disk_addr_t sector, unsigned offset,
 			    unsigned length);
   auto void NESTED_FUNC_ATTR print_blocklist (grub_disk_addr_t sector, unsigned num,
@@ -89,8 +91,9 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)),
     return grub_error (GRUB_ERR_BAD_DEVICE,
 		       "this command is available only for disk devices.");
 
-  if (file->device->disk->partition)
-    part_start = grub_partition_get_start (file->device->disk->partition);
+  part_start = 0;
+  for (part = file->device->disk->partition; part; part = part->parent)
+    part_start += grub_partition_get_start (part);
 
   file->read_hook = read_blocklist;
 
diff --git a/commands/hexdump.c b/commands/hexdump.c
index 0e560c0..f59ba36 100644
--- a/commands/hexdump.c
+++ b/commands/hexdump.c
@@ -22,7 +22,6 @@
 #include <grub/disk.h>
 #include <grub/misc.h>
 #include <grub/gzio.h>
-#include <grub/partition.h>
 #include <grub/lib/hexdump.h>
 #include <grub/extcmd.h>
 
@@ -62,25 +61,20 @@ grub_cmd_hexdump (grub_extcmd_t cmd, int argc, char **args)
       if (! disk)
         return 0;
 
-      if (disk->partition)
-        skip += grub_partition_get_start (disk->partition) << GRUB_DISK_SECTOR_BITS;
-
       sector = (skip >> (GRUB_DISK_SECTOR_BITS + 2)) * 4;
       ofs = skip & (GRUB_DISK_SECTOR_SIZE * 4 - 1);
       while (length)
         {
-          grub_size_t len, n;
+          grub_size_t len;
 
           len = length;
-          if (ofs + len > sizeof (buf))
-            len = sizeof (buf) - ofs;
+          if (len > sizeof (buf))
+            len = sizeof (buf);
 
-          n = ((ofs + len + GRUB_DISK_SECTOR_SIZE - 1)
-               >> GRUB_DISK_SECTOR_BITS);
-          if (disk->dev->read (disk, sector, n, buf))
+          if (grub_disk_read (disk, sector, ofs, len, buf))
             break;
 
-          hexdump (skip, &buf[ofs], len);
+          hexdump (skip, buf, len);
 
           ofs = 0;
           skip += len;
diff --git a/commands/loadenv.c b/commands/loadenv.c
index 22665f9..1cbf0d4 100644
--- a/commands/loadenv.c
+++ b/commands/loadenv.c
@@ -204,6 +204,7 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
   grub_disk_t disk;
   grub_disk_addr_t part_start;
   struct blocklist *p;
+  grub_partition_t part;
   char *buf;
 
   /* Sanity checks.  */
@@ -236,10 +237,10 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
   /* One more sanity check. Re-read all sectors by blocklists, and compare
      those with the data read via a file.  */
   disk = file->device->disk;
-  if (disk->partition)
-    part_start = grub_partition_get_start (disk->partition);
-  else
-    part_start = 0;
+
+  part_start = 0;
+  for (part = disk->partition; part; part = part->parent)
+    part_start += grub_partition_get_start (part);
 
   buf = grub_envblk_buffer (envblk);
   for (p = blocklists, index = 0; p; p = p->next, index += p->length)
diff --git a/conf/common.rmk b/conf/common.rmk
index 07ff04e..8fec4f6 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -19,7 +19,8 @@ grub_probe_SOURCES = util/grub-probe.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/xfs.c fs/afs.c fs/tar.c			\
 	\
-	partmap/pc.c partmap/apple.c partmap/sun.c partmap/gpt.c\
+	partmap/pc.c partmap/bsdlabel.c partmap/apple.c \
+	partmap/sun.c partmap/gpt.c\
 	kern/fs.c kern/env.c fs/fshelp.c			\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c grub_probe_init.c
 
@@ -40,8 +41,8 @@ grub_fstest_SOURCES = util/grub-fstest.c util/hostfs.c util/misc.c 	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c			\
 	fs/ufs.c fs/xfs.c fs/afs.c fs/tar.c				\
 	\
-	kern/partition.c partmap/pc.c partmap/apple.c partmap/sun.c	\
-	partmap/gpt.c							\
+	kern/partition.c partmap/pc.c partmap/bsdlabel.c partmap/apple.c\
+	partmap/sun.c partmap/gpt.c					\
 	kern/fs.c kern/env.c fs/fshelp.c disk/raid.c			\
 	disk/raid5_recover.c disk/raid6_recover.c 			\
 	disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c 		\
@@ -275,7 +276,8 @@ afs_mod_CFLAGS = $(COMMON_CFLAGS)
 afs_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # Partition maps.
-pkglib_MODULES += amiga.mod apple.mod pc.mod sun.mod acorn.mod gpt.mod
+pkglib_MODULES += amiga.mod apple.mod pc.mod sun.mod acorn.mod gpt.mod \
+		  bsdlabel.mod
 
 # For amiga.mod
 amiga_mod_SOURCES = partmap/amiga.c
@@ -292,6 +294,11 @@ pc_mod_SOURCES = partmap/pc.c
 pc_mod_CFLAGS = $(COMMON_CFLAGS)
 pc_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For pc.mod
+bsdlabel_mod_SOURCES = partmap/bsdlabel.c
+bsdlabel_mod_CFLAGS = $(COMMON_CFLAGS)
+bsdlabel_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For sun.mod
 sun_mod_SOURCES = partmap/sun.c
 sun_mod_CFLAGS = $(COMMON_CFLAGS)
diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk
index c70f7d2..075569d 100644
--- a/conf/i386-coreboot.rmk
+++ b/conf/i386-coreboot.rmk
@@ -134,8 +134,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c       \
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c          \
-	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/bsdlabel.c \
+	partmap/sun.c partmap/acorn.c partmap/gpt.c			\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk
index 513e1b7..f109375 100644
--- a/conf/i386-ieee1275.rmk
+++ b/conf/i386-ieee1275.rmk
@@ -88,8 +88,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c		\
-	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/bsdlabel.c \
+	partmap/sun.c partmap/acorn.c partmap/gpt.c			\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index f1915b6..c4f7710 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -112,7 +112,7 @@ grub_setup_SOURCES = util/i386/pc/grub-setup.c util/hostdisk.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/xfs.c fs/afs.c fs/tar.c			\
 	\
-	partmap/pc.c partmap/gpt.c				\
+	partmap/pc.c partmap/bsdlabel.c partmap/gpt.c		\
 	\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
 	util/raid.c util/lvm.c					\
@@ -148,8 +148,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/menu_text.c						\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c		\
-	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/bsdlabel.c partmap/pc.c \
+	partmap/sun.c partmap/acorn.c partmap/gpt.c			\
 	\
 	fs/affs.c fs/cpio.c  fs/fat.c fs/ext2.c fs/hfs.c		\
 	fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c		\
diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk
index b12635e..74decbe 100644
--- a/conf/powerpc-ieee1275.rmk
+++ b/conf/powerpc-ieee1275.rmk
@@ -69,8 +69,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c 	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c				\
-	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
-	partmap/acorn.c							\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/bsdlabel.c \
+	partmap/sun.c partmap/acorn.c					\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk
index 8183cbc..af932d8 100644
--- a/conf/sparc64-ieee1275.rmk
+++ b/conf/sparc64-ieee1275.rmk
@@ -80,8 +80,8 @@ grub_setup_SOURCES = util/sparc64/ieee1275/grub-setup.c util/hostdisk.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/xfs.c fs/afs.c fs/tar.c			\
 	\
-	partmap/amiga.c	partmap/apple.c partmap/pc.c		\
-	partmap/sun.c partmap/acorn.c				\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c 		\
+	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c	\
 	\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
 	util/raid.c util/lvm.c					\
diff --git a/include/grub/bsdlabel.h b/include/grub/bsdlabel.h
new file mode 100644
index 0000000..ba75897
--- /dev/null
+++ b/include/grub/bsdlabel.h
@@ -0,0 +1,91 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2004,2007  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_BSDLABEL_PARTITION_HEADER
+#define GRUB_BSDLABEL_PARTITION_HEADER	1
+
+/* Constants for BSD disk label.  */
+#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR	1
+#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC	0x82564557
+#define GRUB_PC_PARTITION_BSD_MAX_ENTRIES	8
+
+/* BSD partition types.  */
+#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED	0
+#define GRUB_PC_PARTITION_BSD_TYPE_SWAP		1
+#define GRUB_PC_PARTITION_BSD_TYPE_V6		2
+#define GRUB_PC_PARTITION_BSD_TYPE_V7		3
+#define GRUB_PC_PARTITION_BSD_TYPE_SYSV		4
+#define GRUB_PC_PARTITION_BSD_TYPE_V71K		5
+#define GRUB_PC_PARTITION_BSD_TYPE_V8		6
+#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS	7
+#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS	8
+#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS	9
+#define GRUB_PC_PARTITION_BSD_TYPE_OTHER	10
+#define GRUB_PC_PARTITION_BSD_TYPE_HPFS		11
+#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660	12
+#define GRUB_PC_PARTITION_BSD_TYPE_BOOT		13
+
+/* FreeBSD-specific types.  */
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM	14
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID	15
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2	21
+
+/* NetBSD-specific types.  */
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_ADOS	14
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_HFS	15
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE	16
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS	17
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_NTFS	18
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_RAID	19
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_CCD	20
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_JFS2	21
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS	22
+
+/* OpenBSD-specific types.  */
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS	14
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_HFS	15
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE	16
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS	17
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS	18
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_RAID	19
+
+/* The BSD partition entry.  */
+struct grub_pc_partition_bsd_entry
+{
+  grub_uint32_t size;
+  grub_uint32_t offset;
+  grub_uint32_t fragment_size;
+  grub_uint8_t fs_type;
+  grub_uint8_t fs_fragments;
+  grub_uint16_t fs_cylinders;
+} __attribute__ ((packed));
+
+/* The BSD disk label. Only define members useful for GRUB.  */
+struct grub_pc_partition_disk_label
+{
+  grub_uint32_t magic;
+  grub_uint8_t padding[128];
+  grub_uint32_t magic2;
+  grub_uint16_t checksum;
+  grub_uint16_t num_partitions;
+  grub_uint32_t boot_size;
+  grub_uint32_t superblock_size;
+  struct grub_pc_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES];
+} __attribute__ ((packed));
+
+#endif /* ! GRUB_PC_PARTITION_HEADER */
diff --git a/include/grub/partition.h b/include/grub/partition.h
index 37c5f24..4b174ff 100644
--- a/include/grub/partition.h
+++ b/include/grub/partition.h
@@ -36,13 +36,6 @@ struct grub_partition_map
 			 int (*hook) (struct grub_disk *disk,
 				      const grub_partition_t partition));
 
-  /* Return the partition named STR on the disk DISK.  */
-  grub_partition_t (*probe) (struct grub_disk *disk,
-			     const char *str);
-
-  /* Return the name of the partition PARTITION.  */
-  char *(*get_name) (const grub_partition_t partition);
-
   /* The next partition map type.  */
   struct grub_partition_map *next;
 };
@@ -51,6 +44,9 @@ typedef struct grub_partition_map *grub_partition_map_t;
 /* Partition description.  */
 struct grub_partition
 {
+  /* The partition number.  */
+  int number;
+
   /* The start sector.  */
   grub_disk_addr_t start;
 
@@ -60,12 +56,12 @@ struct grub_partition
   /* The offset of the partition table.  */
   grub_disk_addr_t offset;
 
-  /* The index of this partition in the partition table.  */
-  int index;
-
   /* Partition map type specific data.  */
   void *data;
 
+  /* Parent partition map.  */
+  struct grub_partition *parent;
+
   /* The type partition map.  */
   grub_partition_map_t partmap;
 };
diff --git a/include/grub/pc_partition.h b/include/grub/pc_partition.h
index 67c312e..8f6a8b9 100644
--- a/include/grub/pc_partition.h
+++ b/include/grub/pc_partition.h
@@ -53,75 +53,6 @@
 #define GRUB_PC_PARTITION_TYPE_GPT_DISK		0xee
 #define GRUB_PC_PARTITION_TYPE_LINUX_RAID	0xfd
 
-/* Constants for BSD disk label.  */
-#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR	1
-#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC	0x82564557
-#define GRUB_PC_PARTITION_BSD_MAX_ENTRIES	8
-
-/* BSD partition types.  */
-#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED	0
-#define GRUB_PC_PARTITION_BSD_TYPE_SWAP		1
-#define GRUB_PC_PARTITION_BSD_TYPE_V6		2
-#define GRUB_PC_PARTITION_BSD_TYPE_V7		3
-#define GRUB_PC_PARTITION_BSD_TYPE_SYSV		4
-#define GRUB_PC_PARTITION_BSD_TYPE_V71K		5
-#define GRUB_PC_PARTITION_BSD_TYPE_V8		6
-#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS	7
-#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS	8
-#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS	9
-#define GRUB_PC_PARTITION_BSD_TYPE_OTHER	10
-#define GRUB_PC_PARTITION_BSD_TYPE_HPFS		11
-#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660	12
-#define GRUB_PC_PARTITION_BSD_TYPE_BOOT		13
-
-/* FreeBSD-specific types.  */
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM	14
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID	15
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2	21
-
-/* NetBSD-specific types.  */
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_ADOS	14
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_HFS	15
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE	16
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS	17
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_NTFS	18
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_RAID	19
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_CCD	20
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_JFS2	21
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS	22
-
-/* OpenBSD-specific types.  */
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS	14
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_HFS	15
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE	16
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS	17
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS	18
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_RAID	19
-
-/* The BSD partition entry.  */
-struct grub_pc_partition_bsd_entry
-{
-  grub_uint32_t size;
-  grub_uint32_t offset;
-  grub_uint32_t fragment_size;
-  grub_uint8_t fs_type;
-  grub_uint8_t fs_fragments;
-  grub_uint16_t fs_cylinders;
-} __attribute__ ((packed));
-
-/* The BSD disk label. Only define members useful for GRUB.  */
-struct grub_pc_partition_disk_label
-{
-  grub_uint32_t magic;
-  grub_uint8_t padding[128];
-  grub_uint32_t magic2;
-  grub_uint16_t checksum;
-  grub_uint16_t num_partitions;
-  grub_uint32_t boot_size;
-  grub_uint32_t superblock_size;
-  struct grub_pc_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES];
-} __attribute__ ((packed));
-
 /* The partition entry.  */
 struct grub_pc_partition_entry
 {
@@ -170,20 +101,14 @@ struct grub_pc_partition_mbr
 \f
 struct grub_pc_partition
 {
-    /* The DOS partition number.  */
-  int dos_part;
-
-  /* The BSD partition number (a == 0).  */
-  int bsd_part;
-
   /* The DOS partition type.  */
   int dos_type;
 
-  /* The BSD partition type.  */
-  int bsd_type;
-
   /* The offset of the extended partition.  */
   unsigned long ext_offset;
+
+  /* The index of this partition in the partition table.  */
+  int index;
 };
 
 static inline int
@@ -200,12 +125,4 @@ grub_pc_partition_is_extended (int type)
 	  || type == GRUB_PC_PARTITION_TYPE_LINUX_EXTENDED);
 }
 
-static inline int
-grub_pc_partition_is_bsd (int type)
-{
-  return (type == GRUB_PC_PARTITION_TYPE_FREEBSD
-	  || type == GRUB_PC_PARTITION_TYPE_OPENBSD
-	  || type == GRUB_PC_PARTITION_TYPE_NETBSD);
-}
-
 #endif /* ! GRUB_PC_PARTITION_HEADER */
diff --git a/kern/disk.c b/kern/disk.c
index e167fb6..6eb9e4b 100644
--- a/kern/disk.c
+++ b/kern/disk.c
@@ -334,6 +334,7 @@ grub_disk_open (const char *name)
 void
 grub_disk_close (grub_disk_t disk)
 {
+  grub_partition_t part;
   grub_dprintf ("disk", "Closing `%s'.\n", disk->name);
 
   if (disk->dev && disk->dev->close)
@@ -342,7 +343,13 @@ grub_disk_close (grub_disk_t disk)
   /* Reset the timer.  */
   grub_last_time = grub_get_time_ms ();
 
-  grub_free (disk->partition);
+  while (disk->partition)
+    {
+      part = disk->partition->parent;
+      grub_free (disk->partition->data);
+      grub_free (disk->partition);
+      disk->partition = part;
+    }
   grub_free ((void *) disk->name);
   grub_free (disk);
 }
@@ -353,18 +360,19 @@ grub_disk_close (grub_disk_t disk)
    - Verify that the range is inside the partition.  */
 static grub_err_t
 grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
-		       grub_off_t *offset, grub_size_t size)
+			grub_off_t *offset, grub_size_t size)
 {
+  grub_partition_t part;
   *sector += *offset >> GRUB_DISK_SECTOR_BITS;
   *offset &= GRUB_DISK_SECTOR_SIZE - 1;
 
-  if (disk->partition)
+  for (part = disk->partition; part; part = part->parent)
     {
       grub_disk_addr_t start;
       grub_uint64_t len;
 
-      start = grub_partition_get_start (disk->partition);
-      len = grub_partition_get_len (disk->partition);
+      start = grub_partition_get_start (part);
+      len = grub_partition_get_len (part);
 
       if (*sector >= len
 	  || len - *sector < ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
diff --git a/kern/partition.c b/kern/partition.c
index 4d5c63a..4bcd8c7 100644
--- a/kern/partition.c
+++ b/kern/partition.c
@@ -17,6 +17,7 @@
  */
 
 #include <grub/misc.h>
+#include <grub/mm.h>
 #include <grub/partition.h>
 #include <grub/disk.h>
 
@@ -54,17 +55,58 @@ grub_partition_map_iterate (int (*hook) (const grub_partition_map_t partmap))
   return 0;
 }
 
+static grub_partition_t
+grub_partition_map_probe (const grub_partition_map_t partmap,
+			  grub_disk_t disk, int partnum)
+{
+  grub_partition_t p = 0;
+
+  auto int find_func (grub_disk_t d, const grub_partition_t partition);
+
+  int find_func (grub_disk_t d __attribute__ ((unused)),
+		 const grub_partition_t partition)
+    {
+      if (partnum == partition->number)
+	{
+	  p = (grub_partition_t) grub_malloc (sizeof (*p));
+	  if (! p)
+	    return 1;
+
+	  grub_memcpy (p, partition, sizeof (*p));
+	  return 1;
+	}
+
+      return 0;
+    }
+
+  partmap->iterate (disk, find_func);
+  if (grub_errno)
+    goto fail;
+
+  return p;
+
+ fail:
+  grub_free (p);
+  return 0;
+}
+
 grub_partition_t
 grub_partition_probe (struct grub_disk *disk, const char *str)
 {
   grub_partition_t part = 0;
+  grub_partition_t curpart = 0;
+  grub_partition_t tail;
+  const char *ptr;
+  int num;
 
   auto int part_map_probe (const grub_partition_map_t partmap);
 
   int part_map_probe (const grub_partition_map_t partmap)
     {
-      part = partmap->probe (disk, str);
-      if (part)
+      disk->partition = part;
+      curpart = grub_partition_map_probe (partmap, disk, num);
+      disk->partition = tail;
+      if (curpart)
 	return 1;
 
       if (grub_errno == GRUB_ERR_BAD_PART_TABLE)
@@ -77,27 +119,54 @@ grub_partition_probe (struct grub_disk *disk, const char *str)
       return 1;
     }
 
-  /* Use the first partition map type found.  */
-  grub_partition_map_iterate (part_map_probe);
+  part = tail = disk->partition;
+
+  for (ptr = str; *ptr;)
+    {
+      /* BSD-like partition specification.  */
+      if (*ptr >= 'a' && *ptr <= 'z')
+	num = *(ptr++) - 'a';
+      else
+	num = grub_strtoul (ptr, (char **) &ptr, 0) - 1;
+
+      curpart = 0;
+      /* Use the first partition map type found.  */
+      grub_partition_map_iterate (part_map_probe);
+
+      if (! curpart)
+	{
+	  while (part)
+	    {
+	      curpart = part->parent;
+	      grub_free (part);
+	      part = curpart;
+	    }
+	  return 0;
+	}
+      curpart->parent = part;
+      part = curpart;
+      if (! ptr || *ptr != ',')
+	break;
+      ptr++;
+    }
 
   return part;
 }
 
-int
-grub_partition_iterate (struct grub_disk *disk,
-			int (*hook) (grub_disk_t disk,
-				     const grub_partition_t partition))
+static grub_partition_map_t
+get_partmap (struct grub_disk *disk)
 {
   grub_partition_map_t partmap = 0;
-  int ret = 0;
-
+  struct grub_partition part;
+  int found = 0;
   auto int part_map_iterate (const grub_partition_map_t p);
   auto int part_map_iterate_hook (grub_disk_t d,
 				  const grub_partition_t partition);
-
   int part_map_iterate_hook (grub_disk_t d __attribute__ ((unused)),
-			     const grub_partition_t partition __attribute__ ((unused)))
+			     const grub_partition_t partition)
     {
+      found = 1;
+      part = *partition;
       return 1;
     }
 
@@ -106,22 +175,58 @@ grub_partition_iterate (struct grub_disk *disk,
       grub_dprintf ("partition", "Detecting %s...\n", p->name);
       p->iterate (disk, part_map_iterate_hook);
 
-      if (grub_errno != GRUB_ERR_NONE)
+      if (grub_errno != GRUB_ERR_NONE || ! found)
 	{
 	  /* Continue to next partition map type.  */
 	  grub_dprintf ("partition", "%s detection failed.\n", p->name);
 	  grub_errno = GRUB_ERR_NONE;
 	  return 0;
 	}
+      grub_free (part.data);
 
       grub_dprintf ("partition", "%s detection succeeded.\n", p->name);
       partmap = p;
       return 1;
     }
-
   grub_partition_map_iterate (part_map_iterate);
-  if (partmap)
-    ret = partmap->iterate (disk, hook);
+  return partmap;
+}
+
+int
+grub_partition_iterate (struct grub_disk *disk,
+			int (*hook) (grub_disk_t disk,
+				     const grub_partition_t partition))
+{
+  int ret = 0;
+
+  auto int part_iterate (grub_disk_t dsk, const grub_partition_t p);
+
+  int part_iterate (grub_disk_t dsk,
+		    const grub_partition_t partition)
+    {
+      struct grub_partition p = *partition;
+      grub_partition_map_t partmap = 0;
+      p.parent = dsk->partition;
+      dsk->partition = 0;
+      if (hook (dsk, &p))
+	  return 1;
+      if (p.start != 0)
+	{
+	  dsk->partition = &p;
+	  partmap = get_partmap (dsk);
+	  if (partmap)
+	    ret = partmap->iterate (dsk, part_iterate);
+	}
+      dsk->partition = p.parent;
+      return ret;
+    }
+
+  {
+    grub_partition_map_t partmap = 0;
+    partmap = get_partmap (disk);
+    if (partmap)
+      ret = partmap->iterate (disk, part_iterate);
+  }
 
   return ret;
 }
@@ -129,5 +234,30 @@ grub_partition_iterate (struct grub_disk *disk,
 char *
 grub_partition_get_name (const grub_partition_t partition)
 {
-  return partition->partmap->get_name (partition);
+  char *out = 0;
+  /* Even on 64-bit machines this buffer is enough to hold longest number.  */
+  char buf[25];
+  int curlen = 0;
+  grub_partition_t part;
+  for (part = partition; part; part = part->parent)
+    {
+      int strl;
+      grub_sprintf (buf, "%d", part->number + 1);
+      strl = grub_strlen (buf);
+      if (curlen)
+	{
+	  out = grub_realloc (out, curlen + strl + 2);
+	  grub_memcpy (out + strl + 1, out, curlen);
+	  out[curlen + 1 + strl] = 0;
+	  grub_memcpy (out, buf, strl);
+	  out[strl] = ',';
+	  curlen = curlen + 1 + strl;
+	}
+      else
+	{
+	  curlen = strl;
+	  out = grub_strdup (buf);
+	}
+    }
+  return out;
 }
diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c
index 468e6d0..d9135b2 100644
--- a/loader/i386/bsd.c
+++ b/loader/i386/bsd.c
@@ -86,7 +86,6 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
 		     grub_uint32_t * unit,
 		     grub_uint32_t * slice, grub_uint32_t * part)
 {
-  char *p;
   grub_device_t dev; 
 
   *biosdev = grub_get_root_biosnumber () & 0xff;
@@ -96,21 +95,13 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-
-      p = dev->disk->partition->partmap->get_name (dev->disk->partition);
-      if (p)
+      if (dev->disk->partition->parent)
 	{
-	  if ((p[0] >= '0') && (p[0] <= '9'))
-	    {
-	      *slice = grub_strtoul (p, &p, 0);
-
-	      if ((p) && (p[0] == ','))
-		p++;
-	    }
-
-	  if ((p[0] >= 'a') && (p[0] <= 'z'))
-	    *part = p[0] - 'a';
+	  *part = dev->disk->partition->number;
+	  *slice = dev->disk->partition->parent->number + 1;
 	}
+      else
+	*slice = dev->disk->partition->number + 1;
     }
   if (dev)
     grub_device_close (dev);
diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c
index 8ce315e..8b8a1a9 100644
--- a/loader/i386/multiboot.c
+++ b/loader/i386/multiboot.c
@@ -155,7 +155,6 @@ static int
 grub_multiboot_get_bootdev (grub_uint32_t *bootdev)
 {
 #ifdef GRUB_MACHINE_PCBIOS
-  char *p;
   grub_uint32_t biosdev, slice = ~0, part = ~0;
   grub_device_t dev;
 
@@ -164,21 +163,13 @@ grub_multiboot_get_bootdev (grub_uint32_t *bootdev)
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-
-      p = dev->disk->partition->partmap->get_name (dev->disk->partition);
-      if (p)
+      if (dev->disk->partition->parent)
 	{
-	  if ((p[0] >= '0') && (p[0] <= '9'))
-	    {
-	      slice = grub_strtoul (p, &p, 0) - 1;
-
-	      if ((p) && (p[0] == ','))
-		p++;
-	    }
-
-	  if ((p[0] >= 'a') && (p[0] <= 'z'))
-	    part = p[0] - 'a';
+	  part = dev->disk->partition->number;
+	  slice = dev->disk->partition->parent->number;
 	}
+      else
+	slice = dev->disk->partition->number;
     }
   if (dev)
     grub_device_close (dev);
diff --git a/loader/i386/pc/chainloader.c b/loader/i386/pc/chainloader.c
index caf1450..108884b 100644
--- a/loader/i386/pc/chainloader.c
+++ b/loader/i386/pc/chainloader.c
@@ -31,6 +31,7 @@
 #include <grub/machine/memory.h>
 #include <grub/dl.h>
 #include <grub/command.h>
+#include <grub/pc_partition.h>
 #include <grub/machine/biosnum.h>
 
 static grub_dl_t my_mod;
@@ -94,10 +95,28 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-      grub_disk_read (dev->disk, dev->disk->partition->offset, 446, 64,
-		      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
-      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
-			    + (dev->disk->partition->index << 4));
+      grub_disk_t disk = dev->disk;
+
+      if (disk)
+	{
+	  grub_partition_t p = disk->partition;
+
+	  /* In i386-pc, the id is equal to the BIOS drive number.  */
+	  drive = (int) disk->id;
+
+	  if (p && grub_strcmp (p->partmap->name, "pc_partition_map") == 0)
+	    {
+	      disk->partition = p->parent;
+	      grub_disk_read (disk, p->offset, 446, 64,
+			      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
+	      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
+				    + (((struct grub_pc_partition *) p->data)
+				       ->index << 4));
+	      disk->partition = p;
+	    }
+	}
+
+      grub_device_close (dev);
     }
 
   if (dev)
diff --git a/partmap/acorn.c b/partmap/acorn.c
index 42fd61f..0abd961 100644
--- a/partmap/acorn.c
+++ b/partmap/acorn.c
@@ -96,21 +96,17 @@ acorn_partition_map_iterate (grub_disk_t disk,
 					  const grub_partition_t partition))
 {
   struct grub_partition part;
-  struct grub_disk raw;
   struct linux_part map[LINUX_MAP_ENTRIES];
   int i;
-  grub_disk_addr_t sector;
+  grub_disk_addr_t sector = 0;
   grub_err_t err;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
-  err = acorn_partition_map_find (&raw, map, &sector);
+  err = acorn_partition_map_find (disk, map, &sector);
   if (err)
     return err;
 
   part.partmap = &grub_acorn_partition_map;
+  part.data = 0;
 
   for (i = 0; i != LINUX_MAP_ENTRIES; ++i)
     {
@@ -121,7 +117,7 @@ acorn_partition_map_iterate (grub_disk_t disk,
       part.start = sector + map[i].start;
       part.len = map[i].size;
       part.offset = 6;
-      part.index = i;
+      part.number = i;
 
       if (hook (disk, &part))
 	return grub_errno;
@@ -130,60 +126,6 @@ acorn_partition_map_iterate (grub_disk_t disk,
   return GRUB_ERR_NONE;
 }
 
-
-static grub_partition_t
-acorn_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  struct linux_part map[LINUX_MAP_ENTRIES];
-  struct grub_disk raw = *disk;
-  unsigned long partnum = grub_strtoul (str, 0, 10) - 1;
-  grub_disk_addr_t sector;
-  grub_err_t err;
-  grub_partition_t p;
-
-  /* Enforce raw disk access.  */
-  raw.partition = 0;
-
-  /* Get the partition number.  */
-  if (partnum > LINUX_MAP_ENTRIES)
-    goto fail;
-
-  err = acorn_partition_map_find (&raw, map, &sector);
-  if (err)
-    return 0;
-
-  if (map[partnum].magic != LINUX_NATIVE_MAGIC
-      && map[partnum].magic != LINUX_SWAP_MAGIC)
-    goto fail;
-
-  p = grub_malloc (sizeof (struct grub_partition));
-  if (! p)
-    return 0;
-
-  p->start = sector + map[partnum].start;
-  p->len = map[partnum].size;
-  p->offset = 6;
-  p->index = partnum;
-  return p;
-
-fail:
-  grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-  return 0;
-}
-
-
-static char *
-acorn_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
 \f
 
 /* Partition map type.  */
@@ -191,8 +133,6 @@ static struct grub_partition_map grub_acorn_partition_map =
 {
   .name = "Linux/ADFS partition map",
   .iterate = acorn_partition_map_iterate,
-  .probe = acorn_partition_map_probe,
-  .get_name = acorn_partition_map_get_name
 };
 
 GRUB_MOD_INIT(acorn_partition_map)
diff --git a/partmap/amiga.c b/partmap/amiga.c
index ffb807f..b246ca4 100644
--- a/partmap/amiga.c
+++ b/partmap/amiga.c
@@ -76,20 +76,15 @@ amiga_partition_map_iterate (grub_disk_t disk,
 {
   struct grub_partition part;
   struct grub_amiga_rdsk rdsk;
-  struct grub_disk raw;
   int partno = 0;
   int next = -1;
   unsigned pos;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   /* The RDSK block is one of the first 15 blocks.  */
   for (pos = 0; pos < 15; pos++)
     {
       /* Read the RDSK block which is a descriptor for the entire disk.  */
-      if (grub_disk_read (&raw, pos, 0, sizeof (rdsk), &rdsk))
+      if (grub_disk_read (disk, pos, 0, sizeof (rdsk), &rdsk))
 	return grub_errno;
 
       if (grub_strcmp ((char *) rdsk.magic, "RDSK") == 0)
@@ -104,13 +99,15 @@ amiga_partition_map_iterate (grub_disk_t disk,
     return grub_error (GRUB_ERR_BAD_PART_TABLE,
 		       "Amiga partition map not found.");
 
+  part.data = 0;
+
   /* The end of the partition list is marked using "-1".  */
   while (next != -1)
     {
       struct grub_amiga_partition apart;
 
       /* Read the RDSK block which is a descriptor for the entire disk.  */
-      if (grub_disk_read (&raw, next, 0, sizeof (apart), &apart))
+      if (grub_disk_read (disk, next, 0, sizeof (apart), &apart))
 	return grub_errno;
 
       /* Calculate the first block and the size of the partition.  */
@@ -123,7 +120,7 @@ amiga_partition_map_iterate (grub_disk_t disk,
 		  * grub_be_to_cpu32 (apart.block_per_track));
 
       part.offset = (grub_off_t) next * 512;
-      part.index = partno;
+      part.number = partno;
       part.partmap = &grub_amiga_partition_map;
 
       if (hook (disk, &part))
@@ -136,72 +133,12 @@ amiga_partition_map_iterate (grub_disk_t disk,
   return 0;
 }
 
-
-static grub_partition_t
-amiga_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  if (amiga_partition_map_iterate (disk, find_func))
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-amiga_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_amiga_partition_map =
   {
     .name = "amiga_partition_map",
     .iterate = amiga_partition_map_iterate,
-    .probe = amiga_partition_map_probe,
-    .get_name = amiga_partition_map_get_name
   };
 
 GRUB_MOD_INIT(amiga_partition_map)
diff --git a/partmap/apple.c b/partmap/apple.c
index fce2f2c..1621086 100644
--- a/partmap/apple.c
+++ b/partmap/apple.c
@@ -104,17 +104,12 @@ apple_partition_map_iterate (grub_disk_t disk,
   struct grub_partition part;
   struct grub_apple_header aheader;
   struct grub_apple_part apart;
-  struct grub_disk raw;
   int partno = 0;
   unsigned pos = GRUB_DISK_SECTOR_SIZE;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   part.partmap = &grub_apple_partition_map;
 
-  if (grub_disk_read (&raw, 0, 0, sizeof (aheader), &aheader))
+  if (grub_disk_read (disk, 0, 0, sizeof (aheader), &aheader))
     return grub_errno;
 
   if (grub_be_to_cpu16 (aheader.magic) != GRUB_APPLE_HEADER_MAGIC)
@@ -126,9 +121,11 @@ apple_partition_map_iterate (grub_disk_t disk,
       goto fail;
     }
 
+  part.data = 0;
+
   for (;;)
     {
-      if (grub_disk_read (&raw, pos / GRUB_DISK_SECTOR_SIZE,
+      if (grub_disk_read (disk, pos / GRUB_DISK_SECTOR_SIZE,
 			  pos % GRUB_DISK_SECTOR_SIZE,
 			  sizeof (struct grub_apple_part),  &apart))
 	return grub_errno;
@@ -145,7 +142,7 @@ apple_partition_map_iterate (grub_disk_t disk,
       part.start = grub_be_to_cpu32 (apart.first_phys_block);
       part.len = grub_be_to_cpu32 (apart.blockcnt);
       part.offset = pos;
-      part.index = partno;
+      part.number = partno;
 
       grub_dprintf ("partition",
 		    "partition %d: name %s, type %s, start 0x%x, len 0x%x\n",
@@ -172,72 +169,12 @@ apple_partition_map_iterate (grub_disk_t disk,
 		     "Apple partition map not found.");
 }
 
-
-static grub_partition_t
-apple_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  if (apple_partition_map_iterate (disk, find_func))
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-apple_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_apple_partition_map =
   {
     .name = "apple_partition_map",
     .iterate = apple_partition_map_iterate,
-    .probe = apple_partition_map_probe,
-    .get_name = apple_partition_map_get_name
   };
 
 GRUB_MOD_INIT(apple_partition_map)
diff --git a/partmap/bsdlabel.c b/partmap/bsdlabel.c
new file mode 100644
index 0000000..68c199f
--- /dev/null
+++ b/partmap/bsdlabel.c
@@ -0,0 +1,89 @@
+/* bsdlabel.c - Read BSD style partition tables.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2004,2005,2006,2007,2008,2009  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/partition.h>
+#include <grub/bsdlabel.h>
+#include <grub/disk.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/dl.h>
+
+static struct grub_partition_map grub_bsdlabel_partition_map;
+\f
+
+static grub_err_t
+bsdlabel_partition_map_iterate (grub_disk_t disk,
+			  int (*hook) (grub_disk_t disk,
+				       const grub_partition_t partition))
+{
+  struct grub_pc_partition_disk_label label;
+  struct grub_partition p;
+  grub_partition_t part;
+  grub_disk_addr_t delta = 0;
+
+  /* BSDLabel offsets are absolute even when it's embed inside partition.  */
+  for (part = disk->partition; part; part = part->parent)
+    delta += grub_partition_get_start (part);
+
+  /* Read the BSD label.  */
+  if (grub_disk_read (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR,
+		      0, sizeof (label), &label))
+    goto finish;
+
+  /* Check if it is valid.  */
+  if (label.magic != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
+    return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
+  for (p.number = 0;
+       p.number < grub_cpu_to_le16 (label.num_partitions);
+       p.number++)
+    {
+      struct grub_pc_partition_bsd_entry *be
+	= label.entries + p.number;
+
+      p.start = grub_le_to_cpu32 (be->offset) - delta;
+      p.len = grub_le_to_cpu32 (be->size);
+      p.offset = GRUB_PC_PARTITION_BSD_LABEL_SECTOR;
+      p.partmap = &grub_bsdlabel_partition_map;
+      p.data = 0;
+
+      if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
+	if (hook (disk, &p))
+	  return 1;
+    }
+ finish:
+  return grub_errno;
+}
+
+\f
+/* Partition map type.  */
+static struct grub_partition_map grub_bsdlabel_partition_map =
+  {
+    .name = "bsdlabel_partition_map",
+    .iterate = bsdlabel_partition_map_iterate,
+  };
+
+GRUB_MOD_INIT(bsdlabel_partition_map)
+{
+  grub_partition_map_register (&grub_bsdlabel_partition_map);
+}
+
+GRUB_MOD_FINI(bsdlabel_partition_map)
+{
+  grub_partition_map_unregister (&grub_bsdlabel_partition_map);
+}
diff --git a/partmap/gpt.c b/partmap/gpt.c
index d646d41..bfe6269 100644
--- a/partmap/gpt.c
+++ b/partmap/gpt.c
@@ -44,18 +44,13 @@ gpt_partition_map_iterate (grub_disk_t disk,
   struct grub_partition part;
   struct grub_gpt_header gpt;
   struct grub_gpt_partentry entry;
-  struct grub_disk raw;
   struct grub_pc_partition_mbr mbr;
   grub_uint64_t entries;
   unsigned int i;
   int last_offset = 0;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   /* Read the protective MBR.  */
-  if (grub_disk_read (&raw, 0, 0, sizeof (mbr), &mbr))
+  if (grub_disk_read (disk, 0, 0, sizeof (mbr), &mbr))
     return grub_errno;
 
   /* Check if it is valid.  */
@@ -67,7 +62,7 @@ gpt_partition_map_iterate (grub_disk_t disk,
     return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
 
   /* Read the GPT header.  */
-  if (grub_disk_read (&raw, 1, 0, sizeof (gpt), &gpt))
+  if (grub_disk_read (disk, 1, 0, sizeof (gpt), &gpt))
     return grub_errno;
 
   if (grub_memcmp (gpt.magic, grub_gpt_magic, sizeof (grub_gpt_magic)))
@@ -78,7 +73,7 @@ gpt_partition_map_iterate (grub_disk_t disk,
   entries = grub_le_to_cpu64 (gpt.partitions);
   for (i = 0; i < grub_le_to_cpu32 (gpt.maxpart); i++)
     {
-      if (grub_disk_read (&raw, entries, last_offset,
+      if (grub_disk_read (disk, entries, last_offset,
 			  sizeof (entry), &entry))
 	return grub_errno;
 
@@ -90,9 +85,9 @@ gpt_partition_map_iterate (grub_disk_t disk,
 	  part.len = (grub_le_to_cpu64 (entry.end)
 		      - grub_le_to_cpu64 (entry.start) + 1);
 	  part.offset = entries;
-	  part.index = i;
+	  part.number = i;
 	  part.partmap = &grub_gpt_partition_map;
-	  part.data = &entry;
+	  part.data = 0;
 
 	  grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", i,
 			(unsigned long long) part.start,
@@ -113,73 +108,12 @@ gpt_partition_map_iterate (grub_disk_t disk,
   return 0;
 }
 
-
-static grub_partition_t
-gpt_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  gpt_partition_map_iterate (disk, find_func);
-  if (grub_errno)
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-gpt_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_gpt_partition_map =
   {
     .name = "gpt_partition_map",
     .iterate = gpt_partition_map_iterate,
-    .probe = gpt_partition_map_probe,
-    .get_name = gpt_partition_map_get_name
   };
 
 GRUB_MOD_INIT(gpt_partition_map)
diff --git a/partmap/pc.c b/partmap/pc.c
index 6f68ecf..b195087 100644
--- a/partmap/pc.c
+++ b/partmap/pc.c
@@ -27,178 +27,82 @@
 static struct grub_partition_map grub_pc_partition_map;
 \f
 
-/* Parse the partition representation in STR and return a partition.  */
-static grub_partition_t
-grub_partition_parse (const char *str)
-{
-  grub_partition_t p;
-  struct grub_pc_partition *pcdata;
-
-  char *s = (char *) str;
-
-  p = (grub_partition_t) grub_malloc (sizeof (*p));
-  if (! p)
-    return 0;
-
-  pcdata = (struct grub_pc_partition *) grub_malloc (sizeof (*pcdata));
-  if (! pcdata)
-    goto fail;
-
-  p->data = pcdata;
-  p->partmap = &grub_pc_partition_map;
-
-  /* Initialize some of the fields with invalid values.  */
-  pcdata->bsd_part = pcdata->dos_type = pcdata->bsd_type = p->index = -1;
-
-  /* Get the DOS partition number. The number is counted from one for
-     the user interface, and from zero internally.  */
-  pcdata->dos_part = grub_strtoul (s, &s, 0) - 1;
-
-  if (grub_errno)
-    {
-      /* Not found. Maybe only a BSD label is specified.  */
-      pcdata->dos_part = -1;
-      grub_errno = GRUB_ERR_NONE;
-    }
-  else if (*s == ',')
-    s++;
-
-  if (*s)
-    {
-      if (*s >= 'a' && *s <= 'h')
-	{
-	  pcdata->bsd_part = *s - 'a';
-	  s++;
-	}
-
-      if (*s)
-	goto fail;
-    }
-
-  if (pcdata->dos_part == -1 && pcdata->bsd_part == -1)
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  grub_free (pcdata);
-  grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-  return 0;
-}
-
 static grub_err_t
 pc_partition_map_iterate (grub_disk_t disk,
 			  int (*hook) (grub_disk_t disk,
 				       const grub_partition_t partition))
 {
   struct grub_partition p;
-  struct grub_pc_partition pcdata;
+  struct grub_pc_partition *pcdata;
   struct grub_pc_partition_mbr mbr;
-  struct grub_pc_partition_disk_label label;
-  struct grub_disk raw;
-
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
 
+  pcdata = grub_malloc (sizeof (*pcdata));
   p.offset = 0;
-  pcdata.ext_offset = 0;
-  pcdata.dos_part = -1;
-  p.data = &pcdata;
+  pcdata->ext_offset = 0;
+  p.data = pcdata;
+  p.number = -1;
   p.partmap = &grub_pc_partition_map;
 
+  /* Signature check is known to cause false positives
+     because the same signature is used for bootsectors.  */
+  if (disk->partition)
+    {
+      grub_free (pcdata);
+      return grub_error (GRUB_ERR_BAD_PART_TABLE,
+			 "pc partition can't be nested");
+    }
+
   while (1)
     {
       int i;
       struct grub_pc_partition_entry *e;
 
       /* Read the MBR.  */
-      if (grub_disk_read (&raw, p.offset, 0, sizeof (mbr), &mbr))
+      if (grub_disk_read (disk, p.offset, 0, sizeof (mbr), &mbr))
 	goto finish;
 
       /* Check if it is valid.  */
       if (mbr.signature != grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE))
-	return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
+	{
+	  grub_free (pcdata);
+	  return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
+	}
 
       /* Analyze DOS partitions.  */
-      for (p.index = 0; p.index < 4; p.index++)
+      for (pcdata->index = 0; pcdata->index < 4; pcdata->index++)
 	{
-	  e = mbr.entries + p.index;
+	  e = mbr.entries + pcdata->index;
 
 	  p.start = p.offset + grub_le_to_cpu32 (e->start);
 	  p.len = grub_le_to_cpu32 (e->length);
-	  pcdata.bsd_part = -1;
-	  pcdata.dos_type = e->type;
-	  pcdata.bsd_type = -1;
+	  pcdata->dos_type = e->type;
 
 	  grub_dprintf ("partition",
 			"partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n",
-			p.index, e->flag, pcdata.dos_type,
+			pcdata->index, e->flag, pcdata->dos_type,
 			(unsigned long long) p.start,
 			(unsigned long long) p.len);
 
 	  /* If this is a GPT partition, this MBR is just a dummy.  */
-	  if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && p.index == 0)
-	    return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr");
+	  if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && pcdata->index == 0)
+	    {
+	      grub_free (pcdata);
+	      return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr");
+	    }
 
 	  /* If this partition is a normal one, call the hook.  */
 	  if (! grub_pc_partition_is_empty (e->type)
 	      && ! grub_pc_partition_is_extended (e->type))
 	    {
-	      pcdata.dos_part++;
+	      p.number++;
 
 	      if (hook (disk, &p))
 		return 1;
-
-	      /* Check if this is a BSD partition.  */
-	      if (grub_pc_partition_is_bsd (e->type))
-		{
-		  /* Check if the BSD label is within the DOS partition.  */
-		  if (p.len <= GRUB_PC_PARTITION_BSD_LABEL_SECTOR)
-		    {
-		      grub_dprintf ("partition", "no space for disk label\n");
-		      continue;
-		    }
-		  /* Read the BSD label.  */
-		  if (grub_disk_read (&raw,
-				      (p.start
-				       + GRUB_PC_PARTITION_BSD_LABEL_SECTOR),
-				      0,
-				      sizeof (label),
-				      &label))
-		    goto finish;
-
-		  /* Check if it is valid.  */
-		  if (label.magic
-		      != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
-		    {
-		      grub_dprintf ("partition",
-				    "invalid disk label magic 0x%x on partition %d\n",
-				    label.magic, p.index);
-		      continue;
-		    }
-		  for (pcdata.bsd_part = 0;
-		       pcdata.bsd_part < grub_cpu_to_le16 (label.num_partitions);
-		       pcdata.bsd_part++)
-		    {
-		      struct grub_pc_partition_bsd_entry *be
-			= label.entries + pcdata.bsd_part;
-
-		      p.start = grub_le_to_cpu32 (be->offset);
-		      p.len = grub_le_to_cpu32 (be->size);
-		      pcdata.bsd_type = be->fs_type;
-
-		      if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
-			if (hook (disk, &p))
-			  return 1;
-		    }
-		}
 	    }
-	  else if (pcdata.dos_part < 4)
+	  else if (p.number < 4)
 	    /* If this partition is a logical one, shouldn't increase the
 	       partition number.  */
-	    pcdata.dos_part++;
+	    p.number++;
 	}
 
       /* Find an extended partition.  */
@@ -208,9 +112,9 @@ pc_partition_map_iterate (grub_disk_t disk,
 
 	  if (grub_pc_partition_is_extended (e->type))
 	    {
-	      p.offset = pcdata.ext_offset + grub_le_to_cpu32 (e->start);
-	      if (! pcdata.ext_offset)
-		pcdata.ext_offset = p.offset;
+	      p.offset = pcdata->ext_offset + grub_le_to_cpu32 (e->start);
+	      if (! pcdata->ext_offset)
+		pcdata->ext_offset = p.offset;
 
 	      break;
 	    }
@@ -222,77 +126,8 @@ pc_partition_map_iterate (grub_disk_t disk,
     }
 
  finish:
-  return grub_errno;
-}
-
-
-static grub_partition_t
-pc_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p;
-  struct grub_pc_partition *pcdata;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      struct grub_pc_partition *partdata = partition->data;
-
-      if ((pcdata->dos_part == partdata->dos_part || pcdata->dos_part == -1)
-	  && pcdata->bsd_part == partdata->bsd_part)
-	{
-	  grub_memcpy (p, partition, sizeof (*p));
-	  p->data = pcdata;
-	  grub_memcpy (pcdata, partdata, sizeof (*pcdata));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  p = grub_partition_parse (str);
-  if (! p)
-    return 0;
-
-  pcdata = p->data;
-  pc_partition_map_iterate (disk, find_func);
-  if (grub_errno)
-    goto fail;
-
-  if (p->index < 0)
-    {
-      grub_error (GRUB_ERR_BAD_DEVICE, "no such partition");
-      goto fail;
-    }
-
-  return p;
-
- fail:
-  grub_free (p);
   grub_free (pcdata);
-  return 0;
-}
-
-
-static char *
-pc_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-  struct grub_pc_partition *pcdata = p->data;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  if (pcdata->bsd_part < 0)
-    grub_sprintf (name, "%d", pcdata->dos_part + 1);
-  else if (pcdata->dos_part < 0)
-    grub_sprintf (name, "%c", pcdata->bsd_part + 'a');
-  else
-    grub_sprintf (name, "%d,%c", pcdata->dos_part + 1, pcdata->bsd_part + 'a');
-
-  return name;
+  return grub_errno;
 }
 
 \f
@@ -301,8 +136,6 @@ static struct grub_partition_map grub_pc_partition_map =
   {
     .name = "pc_partition_map",
     .iterate = pc_partition_map_iterate,
-    .probe = pc_partition_map_probe,
-    .get_name = pc_partition_map_get_name
   };
 
 GRUB_MOD_INIT(pc_partition_map)
diff --git a/partmap/sun.c b/partmap/sun.c
index 6094777..c6633a1 100644
--- a/partmap/sun.c
+++ b/partmap/sun.c
@@ -88,13 +88,9 @@ sun_partition_map_iterate (grub_disk_t disk,
 					const grub_partition_t partition))
 {
   grub_partition_t p;
-  struct grub_disk raw;
   struct grub_sun_block block;
   int partnum;
 
-  raw = *disk;
-  raw.partition = 0;
-
   p = (grub_partition_t) grub_malloc (sizeof (struct grub_partition));
   if (! p)
     return grub_errno;
@@ -102,7 +98,7 @@ sun_partition_map_iterate (grub_disk_t disk,
   p->offset = 0;
   p->data = 0;
   p->partmap = &grub_sun_partition_map;
-  if (grub_disk_read (&raw, 0, 0, sizeof (struct grub_sun_block),
+  if (grub_disk_read (disk, 0, 0, sizeof (struct grub_sun_block),
 		      &block) == GRUB_ERR_NONE)
     {
       if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.magic))
@@ -126,7 +122,7 @@ sun_partition_map_iterate (grub_disk_t disk,
 		      * grub_be_to_cpu16 (block.ntrks)
 		      * grub_be_to_cpu16 (block.nsect));
 	  p->len = grub_be_to_cpu32 (desc->num_sectors);
-	  p->index = partnum;
+	  p->number = partnum;
 	  if (p->len)
 	    {
 	      if (hook (disk, p))
@@ -140,68 +136,11 @@ sun_partition_map_iterate (grub_disk_t disk,
   return grub_errno;
 }
 
-static grub_partition_t
-sun_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-        {
-          p = (grub_partition_t) grub_malloc (sizeof (*p));
-          if (p)
-            grub_memcpy (p, partition, sizeof (*p));
-
-          return 1;
-        }
-
-      return 0;
-    }
-
-  grub_errno = GRUB_ERR_NONE;
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno == GRUB_ERR_NONE)
-    {
-      if (sun_partition_map_iterate (disk, find_func))
-        {
-          grub_free (p);
-          p = 0;
-        }
-    }
-  else
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      p = 0;
-    }
-
-  return p;
-}
-
-static char *
-sun_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (name)
-    grub_sprintf (name, "%d", p->index + 1);
-
-  return name;
-}
-
 /* Partition map type.  */
 static struct grub_partition_map grub_sun_partition_map =
   {
     .name = "sun_partition_map",
     .iterate = sun_partition_map_iterate,
-    .probe = sun_partition_map_probe,
-    .get_name = sun_partition_map_get_name
   };
 
 GRUB_MOD_INIT(sun_partition_map)
diff --git a/parttool/pcpart.c b/parttool/pcpart.c
index 6876d0d..c0c53e6 100644
--- a/parttool/pcpart.c
+++ b/parttool/pcpart.c
@@ -47,9 +47,9 @@ static grub_err_t grub_pcpart_boot (const grub_device_t dev,
   if (dev->disk->partition->offset)
     return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a primary partition");
 
-  index = dev->disk->partition->index;
+  index = ((struct grub_pc_partition *) dev->disk->partition->data)->index;
   part = dev->disk->partition;
-  dev->disk->partition = 0;
+  dev->disk->partition = part->parent;
 
   /* Read the MBR.  */
   if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr))
@@ -94,9 +94,9 @@ static grub_err_t grub_pcpart_type (const grub_device_t dev,
   grub_partition_t part;
   struct grub_pc_partition_mbr mbr;
 
-  index = dev->disk->partition->index;
+  index = ((struct grub_pc_partition *) dev->disk->partition->data)->index;
   part = dev->disk->partition;
-  dev->disk->partition = 0;
+  dev->disk->partition = part->parent;
 
   /* Read the parttable.  */
   if (grub_disk_read (dev->disk, part->offset, 0,
diff --git a/util/hostdisk.c b/util/hostdisk.c
index d84e7f3..994e256 100644
--- a/util/hostdisk.c
+++ b/util/hostdisk.c
@@ -321,10 +321,15 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
   {
     int is_partition = 0;
     char dev[PATH_MAX];
+    grub_partition_t part;
+    grub_disk_addr_t part_start = 0;
+
+    for (part = disk->partition; part; part = part->parent)
+      part_start += grub_partition_get_start (part);
 
     strcpy (dev, map[disk->id].device);
     if (disk->partition && strncmp (map[disk->id].device, "/dev/", 5) == 0)
-      is_partition = linux_find_partition (dev, disk->partition->start);
+      is_partition = linux_find_partition (dev, part_start);
 
     /* Open the partition.  */
     grub_dprintf ("hostdisk", "opening the device `%s' in open_device()", dev);
@@ -339,7 +344,7 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
     ioctl (fd, BLKFLSBUF, 0);
 
     if (is_partition)
-      sector -= disk->partition->start;
+      sector -= part_start;
   }
 #else /* ! __linux__ */
 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -919,39 +924,27 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
     int find_partition (grub_disk_t disk __attribute__ ((unused)),
 			const grub_partition_t partition)
       {
- 	struct grub_pc_partition *pcdata = NULL;
-
-	if (strcmp (partition->partmap->name, "pc_partition_map") == 0)
-	  pcdata = partition->data;
+	grub_partition_t part;
+	grub_disk_addr_t part_start = 0;
+	grub_util_info ("Partition %d starts from %lu",
+			partition->number, partition->start);
 
-	if (pcdata)
-	  {
-	    if (pcdata->bsd_part < 0)
-	      grub_util_info ("DOS partition %d starts from %lu",
-			      pcdata->dos_part, partition->start);
-	    else
-	      grub_util_info ("BSD partition %d,%c starts from %lu",
-			      pcdata->dos_part, pcdata->bsd_part + 'a',
-			      partition->start);
-	  }
-	else
-	  {
-	      grub_util_info ("Partition %d starts from %lu",
-			      partition->index, partition->start);
-	  }
+	for (part = partition; part; part = part->parent)
+	  part_start += grub_partition_get_start (part);
 
-	if (hdg.start == partition->start)
+	if (hdg.start == part_start)
 	  {
-	    if (pcdata)
+	    if (partition->parent)
 	      {
-		dos_part = pcdata->dos_part;
-		bsd_part = pcdata->bsd_part;
+		dos_part = partition->parent->number;
+		bsd_part = partition->number;
 	      }
 	    else
 	      {
-		dos_part = partition->index;
+		dos_part = partition->number;
 		bsd_part = -1;
 	      }
+
 	    return 1;
 	  }
 
diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c
index 5a51964..aa30fa3 100644
--- a/util/i386/pc/grub-setup.c
+++ b/util/i386/pc/grub-setup.c
@@ -128,7 +128,6 @@ setup (const char *dir,
 
       /* For its end offset, include as many dummy partitions as we can.  */
       if (! grub_pc_partition_is_empty (pcdata->dos_type)
-	  && ! grub_pc_partition_is_bsd (pcdata->dos_type)
 	  && embed_region.end > p->start)
 	embed_region.end = p->start;
 
@@ -278,22 +277,19 @@ setup (const char *dir,
       /* Embed information about the installed location.  */
       if (root_dev->disk->partition)
 	{
-	  if (strcmp (root_dev->disk->partition->partmap->name,
-		      "pc_partition_map") == 0)
+	  if (root_dev->disk->partition->parent)
 	    {
-	      struct grub_pc_partition *pcdata =
-		root_dev->disk->partition->data;
-	      dos_part = pcdata->dos_part;
-	      bsd_part = pcdata->bsd_part;
+	      if (root_dev->disk->partition->parent->parent)
+		grub_util_error ("Installing on doubly nested partitiond is "
+				 "not supported");
+	      dos_part = root_dev->disk->partition->parent->number;
+	      bsd_part = root_dev->disk->partition->number;
 	    }
-	  else if (strcmp (root_dev->disk->partition->partmap->name,
-			   "gpt_partition_map") == 0)
+	  else
 	    {
-	      dos_part = root_dev->disk->partition->index;
+	      dos_part = root_dev->disk->partition->number;
 	      bsd_part = -1;
 	    }
-	  else
-	    grub_util_error ("No PC style partitions found");
 	}
       else
 	dos_part = bsd_part = -1;

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-07-16 20:52 ` Vladimir 'phcoder' Serbinenko
@ 2009-07-31  7:58   ` Marco Gerards
  2009-07-31  9:39     ` Vladimir 'phcoder' Serbinenko
  2009-08-02 22:02   ` Robert Millan
  1 sibling, 1 reply; 36+ messages in thread
From: Marco Gerards @ 2009-07-31  7:58 UTC (permalink / raw)
  To: The development of GRUB 2

"Vladimir 'phcoder' Serbinenko" <phcoder@gmail.com> writes:

> Rediff
>
> On Thu, Jun 11, 2009 at 5:51 PM, Vladimir 'phcoder'
> Serbinenko<phcoder@gmail.com> wrote:
>> Hello. Here is a first version of nested partition support. Beware
>> it's EXPERIMENTAL and may be dagerous. Try at your own risk. With this
>> patch you lose however the ability to specify bsd partition without
>> specifying slice. Use search.

Can you please explain what you mean by that you have to specify the
slice and you have to use search?

What makes this experimental and dangerous?  Can you send in a patch
that isn't?

Here a only a few comments on this patch.  In order to properly review
it, can you explain what the design of the patch is and how it
essentially works?  It is important to discuss that as well.  Can you
also describe which problems the patch solves and introduces?

> Personal git repository: http://repo.or.cz/w/grub2/phcoder.git
>
> diff --git a/ChangeLog b/ChangeLog
> index e617831..0e02e01 100644
> --- a/ChangeLog
> +++ b/ChangeLog
> @@ -1,3 +1,71 @@
> +2009-06-08  Vladimir Serbinenko  <phcoder@gmail.com>
> +
> +	Nested partitions
> +
> +	* commands/blocklist.c (grub_cmd_blocklist): handle nested partitions

Please start with a capital letter and end with a `.'.  I noticed that
you have committed other patches with this problem in the changelog
entry.  If you commit something else and if you have the time, I would
be happy if you could fix that too :-)

> +	* commands/hexdump.c (grub_cmd_hexdump): use grub_disk_read
> +	* commands/loadenv.c (check_blocklists): handle nested partitions
> +	* conf/common.rmk (grub_probe_SOURCES): add partmap/bsdlabel.c
> +	(grub_fstest_SOURCES): likewise
> +	(pkglib_MODULES): add bsdlabel.mod
> +	(bsdlabel_mod_SOURCES): new variable
> +	(bsdlabel_mod_CFLAGS): likewise
> +	(bsdlabel_mod_LDFLAGS):likewise
> +	* conf/i386-coreboot.rmk (grub_emu_SOURCES): add partmap/bsdlabel.c
> +	* conf/i386-pc.rmk (grub_setup_SOURCES): likewise
> +	(grub_emu_SOURCES): likewise
> +	* conf/powerpc-ieee1275.rmk (grub_emu_SOURCES): likewise
> +	* conf/sparc64-ieee1275.rmk (grub_emu_SOURCES): likewise
> +	* include/grub/bsdlabel.h: new file
> +	* include/grub/partition.h (grub_partition_map): remove probe and
> +	get_name
> +	(grub_partition): add parent and number, remove index
> +	* include/grub/pc_partition.h: Remove bsd-related entries
> +	(grub_pc_partition): remove dos_part, bsd_part, add index.
> +	* kern/disk.c (grub_disk_open): free partition data
> +	(grub_disk_adjust_range): handle nested partitions
> +	* kern/partition.c (grub_partition_map_probe): new function
> +	(grub_partition_probe): parse name to number, handle subpartitions
> +	(get_partmap): new function
> +	(grub_partition_iterate): handle subpartitions
> +	(grub_partition_get_name): likewise
> +	* loader/i386/pc/chainloader.c (grub_chainloader_cmd): likewise
> +	* partmap/acorn.c (acorn_partition_map_iterate): don't force raw access
> +	Use number instead of index

What do you mean by "don't force raw access use number instead of
index"?

> +	(acorn_partition_map_probe): remove
> +	(acorn_partition_map_get_name): likewise
> +	* partmap/amiga.c (amiga_partition_map_iterate): don't force raw access
> +	Use number instead of index
> +	(amiga_partition_map_probe): remove
> +	(amiga_partition_map_get_name): likewise
> +	* partmap/apple.c (apple_partition_map_iterate): don't force raw access
> +	Use number instead of index
> +	(apple_partition_map_probe): remove
> +	(apple_partition_map_get_name): likewise
> +	* partmap/bsdlabel.c: new file
> +	* partmap/gpt.c (gpt_partition_map_iterate): don't force raw access
> +	Use number instead of index
> +	(gpt_partition_map_probe): remove
> +	(gpt_partition_map_get_name): likewise
> +	* partmap/pc.c (grub_partition_parse): remove
> +	(pc_partition_map_iterate): don't force raw access
> +	move index to pcdata
> +	make pcdata a pointer
> +	don't handle bsd labels
> +	prevent pc_parition from being nested
> +	(pc_partition_map_probe): remove
> +	(pc_partition_map_get_name): remove
> +	* partmap/sun.c (sun_partition_map_iterate): don't force raw access
> +	Use number instead of index
> +	(sun_partition_map_probe): remove
> +	(sun_partition_map_get_name): likewise
> +	* parttool/pcpart.c (grub_pcpart_boot): handle nested partitions
> +	use index from data
> +	(grub_pcpart_type): likewise
> +	* util/hostdisk.c (open_device): handle new numbering scheme
> +	(grub_util_biosdisk_get_grub_dev): handle nested partitions
> +	* util/i386/pc/grub-setup.c (setuo): handle new numbering scheme
> +
>  2009-07-16  Vladimir Serbinenko  <phcoder@gmail.com>
>  
>  	Enable all targets that can be built by default
> diff --git a/commands/blocklist.c b/commands/blocklist.c
> index b457b7c..796455a 100644
> --- a/commands/blocklist.c
> +++ b/commands/blocklist.c
> @@ -35,6 +35,8 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)),
>    unsigned num_sectors = 0;
>    int num_entries = 0;
>    grub_disk_addr_t part_start = 0;
> +  grub_partition_t part;
> +
>    auto void NESTED_FUNC_ATTR read_blocklist (grub_disk_addr_t sector, unsigned offset,
>  			    unsigned length);
>    auto void NESTED_FUNC_ATTR print_blocklist (grub_disk_addr_t sector, unsigned num,
> @@ -89,8 +91,9 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)),
>      return grub_error (GRUB_ERR_BAD_DEVICE,
>  		       "this command is available only for disk devices.");
>  
> -  if (file->device->disk->partition)
> -    part_start = grub_partition_get_start (file->device->disk->partition);
> +  part_start = 0;
> +  for (part = file->device->disk->partition; part; part = part->parent)
> +    part_start += grub_partition_get_start (part);

Why do you need this change?  Can you explain what this does?

>    file->read_hook = read_blocklist;
>  
> diff --git a/commands/hexdump.c b/commands/hexdump.c
> index 0e560c0..f59ba36 100644
> --- a/commands/hexdump.c
> +++ b/commands/hexdump.c
> @@ -22,7 +22,6 @@
>  #include <grub/disk.h>
>  #include <grub/misc.h>
>  #include <grub/gzio.h>
> -#include <grub/partition.h>
>  #include <grub/lib/hexdump.h>
>  #include <grub/extcmd.h>
>  
> @@ -62,25 +61,20 @@ grub_cmd_hexdump (grub_extcmd_t cmd, int argc, char **args)
>        if (! disk)
>          return 0;
>  
> -      if (disk->partition)
> -        skip += grub_partition_get_start (disk->partition) << GRUB_DISK_SECTOR_BITS;
> -
>        sector = (skip >> (GRUB_DISK_SECTOR_BITS + 2)) * 4;
>        ofs = skip & (GRUB_DISK_SECTOR_SIZE * 4 - 1);
>        while (length)
>          {
> -          grub_size_t len, n;
> +          grub_size_t len;
>  
>            len = length;
> -          if (ofs + len > sizeof (buf))
> -            len = sizeof (buf) - ofs;
> +          if (len > sizeof (buf))
> +            len = sizeof (buf);
>  
> -          n = ((ofs + len + GRUB_DISK_SECTOR_SIZE - 1)
> -               >> GRUB_DISK_SECTOR_BITS);
> -          if (disk->dev->read (disk, sector, n, buf))
> +          if (grub_disk_read (disk, sector, ofs, len, buf))
>              break;
>  
> -          hexdump (skip, &buf[ofs], len);
> +          hexdump (skip, buf, len);
>  
>            ofs = 0;
>            skip += len;
> diff --git a/commands/loadenv.c b/commands/loadenv.c
> index 22665f9..1cbf0d4 100644
> --- a/commands/loadenv.c
> +++ b/commands/loadenv.c
> @@ -204,6 +204,7 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
>    grub_disk_t disk;
>    grub_disk_addr_t part_start;
>    struct blocklist *p;
> +  grub_partition_t part;
>    char *buf;
>  
>    /* Sanity checks.  */
> @@ -236,10 +237,10 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
>    /* One more sanity check. Re-read all sectors by blocklists, and compare
>       those with the data read via a file.  */
>    disk = file->device->disk;
> -  if (disk->partition)
> -    part_start = grub_partition_get_start (disk->partition);
> -  else
> -    part_start = 0;
> +
> +  part_start = 0;
> +  for (part = disk->partition; part; part = part->parent)
> +    part_start += grub_partition_get_start (part);
>  
>    buf = grub_envblk_buffer (envblk);
>    for (p = blocklists, index = 0; p; p = p->next, index += p->length)
> diff --git a/conf/common.rmk b/conf/common.rmk
> index 07ff04e..8fec4f6 100644
> --- a/conf/common.rmk
> +++ b/conf/common.rmk
> @@ -19,7 +19,8 @@ grub_probe_SOURCES = util/grub-probe.c	\
>  	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
>  	fs/ufs.c fs/xfs.c fs/afs.c fs/tar.c			\
>  	\
> -	partmap/pc.c partmap/apple.c partmap/sun.c partmap/gpt.c\
> +	partmap/pc.c partmap/bsdlabel.c partmap/apple.c \
> +	partmap/sun.c partmap/gpt.c\
>  	kern/fs.c kern/env.c fs/fshelp.c			\
>  	disk/raid.c disk/mdraid_linux.c disk/lvm.c grub_probe_init.c
>  
> @@ -40,8 +41,8 @@ grub_fstest_SOURCES = util/grub-fstest.c util/hostfs.c util/misc.c 	\
>  	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c			\
>  	fs/ufs.c fs/xfs.c fs/afs.c fs/tar.c				\
>  	\
> -	kern/partition.c partmap/pc.c partmap/apple.c partmap/sun.c	\
> -	partmap/gpt.c							\
> +	kern/partition.c partmap/pc.c partmap/bsdlabel.c partmap/apple.c\
> +	partmap/sun.c partmap/gpt.c					\
>  	kern/fs.c kern/env.c fs/fshelp.c disk/raid.c			\
>  	disk/raid5_recover.c disk/raid6_recover.c 			\
>  	disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c 		\
> @@ -275,7 +276,8 @@ afs_mod_CFLAGS = $(COMMON_CFLAGS)
>  afs_mod_LDFLAGS = $(COMMON_LDFLAGS)
>  
>  # Partition maps.
> -pkglib_MODULES += amiga.mod apple.mod pc.mod sun.mod acorn.mod gpt.mod
> +pkglib_MODULES += amiga.mod apple.mod pc.mod sun.mod acorn.mod gpt.mod \
> +		  bsdlabel.mod
>  
>  # For amiga.mod
>  amiga_mod_SOURCES = partmap/amiga.c
> @@ -292,6 +294,11 @@ pc_mod_SOURCES = partmap/pc.c
>  pc_mod_CFLAGS = $(COMMON_CFLAGS)
>  pc_mod_LDFLAGS = $(COMMON_LDFLAGS)
>  
> +# For pc.mod
> +bsdlabel_mod_SOURCES = partmap/bsdlabel.c
> +bsdlabel_mod_CFLAGS = $(COMMON_CFLAGS)
> +bsdlabel_mod_LDFLAGS = $(COMMON_LDFLAGS)
> +
>  # For sun.mod
>  sun_mod_SOURCES = partmap/sun.c
>  sun_mod_CFLAGS = $(COMMON_CFLAGS)
> diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk
> index c70f7d2..075569d 100644
> --- a/conf/i386-coreboot.rmk
> +++ b/conf/i386-coreboot.rmk
> @@ -134,8 +134,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
>  	normal/color.c							\
>  	script/sh/main.c script/sh/execute.c script/sh/function.c       \
>  	script/sh/lexer.c script/sh/script.c grub_script.tab.c          \
> -	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
> -	partmap/acorn.c partmap/gpt.c					\
> +	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/bsdlabel.c \
> +	partmap/sun.c partmap/acorn.c partmap/gpt.c			\
>  	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
>  	util/hostdisk.c util/getroot.c					\
>  	\
> diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk
> index 513e1b7..f109375 100644
> --- a/conf/i386-ieee1275.rmk
> +++ b/conf/i386-ieee1275.rmk
> @@ -88,8 +88,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
>  	normal/color.c							\
>  	script/sh/main.c script/sh/execute.c script/sh/function.c	\
>  	script/sh/lexer.c script/sh/script.c grub_script.tab.c		\
> -	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
> -	partmap/acorn.c partmap/gpt.c					\
> +	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/bsdlabel.c \
> +	partmap/sun.c partmap/acorn.c partmap/gpt.c			\
>  	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
>  	util/hostdisk.c util/getroot.c					\
>  	\
> diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
> index f1915b6..c4f7710 100644
> --- a/conf/i386-pc.rmk
> +++ b/conf/i386-pc.rmk
> @@ -112,7 +112,7 @@ grub_setup_SOURCES = util/i386/pc/grub-setup.c util/hostdisk.c	\
>  	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
>  	fs/ufs.c fs/xfs.c fs/afs.c fs/tar.c			\
>  	\
> -	partmap/pc.c partmap/gpt.c				\
> +	partmap/pc.c partmap/bsdlabel.c partmap/gpt.c		\
>  	\
>  	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
>  	util/raid.c util/lvm.c					\
> @@ -148,8 +148,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
>  	normal/menu_text.c						\
>  	script/sh/main.c script/sh/execute.c script/sh/function.c	\
>  	script/sh/lexer.c script/sh/script.c grub_script.tab.c		\
> -	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
> -	partmap/acorn.c partmap/gpt.c					\
> +	partmap/amiga.c	partmap/apple.c partmap/bsdlabel.c partmap/pc.c \
> +	partmap/sun.c partmap/acorn.c partmap/gpt.c			\
>  	\
>  	fs/affs.c fs/cpio.c  fs/fat.c fs/ext2.c fs/hfs.c		\
>  	fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c		\
> diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk
> index b12635e..74decbe 100644
> --- a/conf/powerpc-ieee1275.rmk
> +++ b/conf/powerpc-ieee1275.rmk
> @@ -69,8 +69,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c 	\
>  	normal/color.c							\
>  	script/sh/main.c script/sh/execute.c script/sh/function.c	\
>  	script/sh/lexer.c script/sh/script.c				\
> -	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
> -	partmap/acorn.c							\
> +	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/bsdlabel.c \
> +	partmap/sun.c partmap/acorn.c					\
>  	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
>  	util/hostdisk.c util/getroot.c					\
>  	\
> diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk
> index 8183cbc..af932d8 100644
> --- a/conf/sparc64-ieee1275.rmk
> +++ b/conf/sparc64-ieee1275.rmk
> @@ -80,8 +80,8 @@ grub_setup_SOURCES = util/sparc64/ieee1275/grub-setup.c util/hostdisk.c	\
>  	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
>  	fs/ufs.c fs/xfs.c fs/afs.c fs/tar.c			\
>  	\
> -	partmap/amiga.c	partmap/apple.c partmap/pc.c		\
> -	partmap/sun.c partmap/acorn.c				\
> +	partmap/amiga.c	partmap/apple.c partmap/pc.c 		\
> +	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c	\
>  	\
>  	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
>  	util/raid.c util/lvm.c					\
> diff --git a/include/grub/bsdlabel.h b/include/grub/bsdlabel.h
> new file mode 100644
> index 0000000..ba75897
> --- /dev/null
> +++ b/include/grub/bsdlabel.h
> @@ -0,0 +1,91 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 1999,2000,2001,2002,2004,2007  Free Software Foundation, Inc.

2009?

> + *  GRUB 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 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef GRUB_BSDLABEL_PARTITION_HEADER
> +#define GRUB_BSDLABEL_PARTITION_HEADER	1
> +
> +/* Constants for BSD disk label.  */
> +#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR	1
> +#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC	0x82564557
> +#define GRUB_PC_PARTITION_BSD_MAX_ENTRIES	8
> +
> +/* BSD partition types.  */
> +#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED	0
> +#define GRUB_PC_PARTITION_BSD_TYPE_SWAP		1
> +#define GRUB_PC_PARTITION_BSD_TYPE_V6		2
> +#define GRUB_PC_PARTITION_BSD_TYPE_V7		3
> +#define GRUB_PC_PARTITION_BSD_TYPE_SYSV		4
> +#define GRUB_PC_PARTITION_BSD_TYPE_V71K		5
> +#define GRUB_PC_PARTITION_BSD_TYPE_V8		6
> +#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS	7
> +#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS	8
> +#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS	9
> +#define GRUB_PC_PARTITION_BSD_TYPE_OTHER	10
> +#define GRUB_PC_PARTITION_BSD_TYPE_HPFS		11
> +#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660	12
> +#define GRUB_PC_PARTITION_BSD_TYPE_BOOT		13
> +
> +/* FreeBSD-specific types.  */
> +#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM	14
> +#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID	15
> +#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2	21
> +
> +/* NetBSD-specific types.  */
> +#define	GRUB_PC_PARTITION_NETBSD_TYPE_ADOS	14
> +#define	GRUB_PC_PARTITION_NETBSD_TYPE_HFS	15
> +#define	GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE	16
> +#define	GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS	17
> +#define	GRUB_PC_PARTITION_NETBSD_TYPE_NTFS	18
> +#define	GRUB_PC_PARTITION_NETBSD_TYPE_RAID	19
> +#define	GRUB_PC_PARTITION_NETBSD_TYPE_CCD	20
> +#define	GRUB_PC_PARTITION_NETBSD_TYPE_JFS2	21
> +#define	GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS	22
> +
> +/* OpenBSD-specific types.  */
> +#define	GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS	14
> +#define	GRUB_PC_PARTITION_OPENBSD_TYPE_HFS	15
> +#define	GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE	16
> +#define	GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS	17
> +#define	GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS	18
> +#define	GRUB_PC_PARTITION_OPENBSD_TYPE_RAID	19
> +
> +/* The BSD partition entry.  */
> +struct grub_pc_partition_bsd_entry
> +{
> +  grub_uint32_t size;
> +  grub_uint32_t offset;
> +  grub_uint32_t fragment_size;
> +  grub_uint8_t fs_type;
> +  grub_uint8_t fs_fragments;
> +  grub_uint16_t fs_cylinders;
> +} __attribute__ ((packed));
> +
> +/* The BSD disk label. Only define members useful for GRUB.  */
> +struct grub_pc_partition_disk_label
> +{
> +  grub_uint32_t magic;
> +  grub_uint8_t padding[128];
> +  grub_uint32_t magic2;
> +  grub_uint16_t checksum;
> +  grub_uint16_t num_partitions;
> +  grub_uint32_t boot_size;
> +  grub_uint32_t superblock_size;
> +  struct grub_pc_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES];
> +} __attribute__ ((packed));
> +
> +#endif /* ! GRUB_PC_PARTITION_HEADER */
> diff --git a/include/grub/partition.h b/include/grub/partition.h
> index 37c5f24..4b174ff 100644
> --- a/include/grub/partition.h
> +++ b/include/grub/partition.h
> @@ -36,13 +36,6 @@ struct grub_partition_map
>  			 int (*hook) (struct grub_disk *disk,
>  				      const grub_partition_t partition));
>  
> -  /* Return the partition named STR on the disk DISK.  */
> -  grub_partition_t (*probe) (struct grub_disk *disk,
> -			     const char *str);
> -
> -  /* Return the name of the partition PARTITION.  */
> -  char *(*get_name) (const grub_partition_t partition);
> -
>    /* The next partition map type.  */
>    struct grub_partition_map *next;
>  };
> @@ -51,6 +44,9 @@ typedef struct grub_partition_map *grub_partition_map_t;
>  /* Partition description.  */
>  struct grub_partition
>  {
> +  /* The partition number.  */
> +  int number;
> +
>    /* The start sector.  */
>    grub_disk_addr_t start;
>  
> @@ -60,12 +56,12 @@ struct grub_partition
>    /* The offset of the partition table.  */
>    grub_disk_addr_t offset;
>  
> -  /* The index of this partition in the partition table.  */
> -  int index;
> -
>    /* Partition map type specific data.  */
>    void *data;
>  
> +  /* Parent partition map.  */
> +  struct grub_partition *parent;
> +
>    /* The type partition map.  */
>    grub_partition_map_t partmap;
>  };
> diff --git a/include/grub/pc_partition.h b/include/grub/pc_partition.h
> index 67c312e..8f6a8b9 100644
> --- a/include/grub/pc_partition.h
> +++ b/include/grub/pc_partition.h
> @@ -53,75 +53,6 @@
>  #define GRUB_PC_PARTITION_TYPE_GPT_DISK		0xee
>  #define GRUB_PC_PARTITION_TYPE_LINUX_RAID	0xfd
>  
> -/* Constants for BSD disk label.  */
> -#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR	1
> -#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC	0x82564557
> -#define GRUB_PC_PARTITION_BSD_MAX_ENTRIES	8
> -
> -/* BSD partition types.  */
> -#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED	0
> -#define GRUB_PC_PARTITION_BSD_TYPE_SWAP		1
> -#define GRUB_PC_PARTITION_BSD_TYPE_V6		2
> -#define GRUB_PC_PARTITION_BSD_TYPE_V7		3
> -#define GRUB_PC_PARTITION_BSD_TYPE_SYSV		4
> -#define GRUB_PC_PARTITION_BSD_TYPE_V71K		5
> -#define GRUB_PC_PARTITION_BSD_TYPE_V8		6
> -#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS	7
> -#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS	8
> -#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS	9
> -#define GRUB_PC_PARTITION_BSD_TYPE_OTHER	10
> -#define GRUB_PC_PARTITION_BSD_TYPE_HPFS		11
> -#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660	12
> -#define GRUB_PC_PARTITION_BSD_TYPE_BOOT		13
> -
> -/* FreeBSD-specific types.  */
> -#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM	14
> -#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID	15
> -#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2	21
> -
> -/* NetBSD-specific types.  */
> -#define	GRUB_PC_PARTITION_NETBSD_TYPE_ADOS	14
> -#define	GRUB_PC_PARTITION_NETBSD_TYPE_HFS	15
> -#define	GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE	16
> -#define	GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS	17
> -#define	GRUB_PC_PARTITION_NETBSD_TYPE_NTFS	18
> -#define	GRUB_PC_PARTITION_NETBSD_TYPE_RAID	19
> -#define	GRUB_PC_PARTITION_NETBSD_TYPE_CCD	20
> -#define	GRUB_PC_PARTITION_NETBSD_TYPE_JFS2	21
> -#define	GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS	22
> -
> -/* OpenBSD-specific types.  */
> -#define	GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS	14
> -#define	GRUB_PC_PARTITION_OPENBSD_TYPE_HFS	15
> -#define	GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE	16
> -#define	GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS	17
> -#define	GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS	18
> -#define	GRUB_PC_PARTITION_OPENBSD_TYPE_RAID	19
> -
> -/* The BSD partition entry.  */
> -struct grub_pc_partition_bsd_entry
> -{
> -  grub_uint32_t size;
> -  grub_uint32_t offset;
> -  grub_uint32_t fragment_size;
> -  grub_uint8_t fs_type;
> -  grub_uint8_t fs_fragments;
> -  grub_uint16_t fs_cylinders;
> -} __attribute__ ((packed));
> -
> -/* The BSD disk label. Only define members useful for GRUB.  */
> -struct grub_pc_partition_disk_label
> -{
> -  grub_uint32_t magic;
> -  grub_uint8_t padding[128];
> -  grub_uint32_t magic2;
> -  grub_uint16_t checksum;
> -  grub_uint16_t num_partitions;
> -  grub_uint32_t boot_size;
> -  grub_uint32_t superblock_size;
> -  struct grub_pc_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES];
> -} __attribute__ ((packed));
> -
>  /* The partition entry.  */
>  struct grub_pc_partition_entry
>  {
> @@ -170,20 +101,14 @@ struct grub_pc_partition_mbr
>  \f
>  struct grub_pc_partition
>  {
> -    /* The DOS partition number.  */
> -  int dos_part;
> -
> -  /* The BSD partition number (a == 0).  */
> -  int bsd_part;
> -
>    /* The DOS partition type.  */
>    int dos_type;
>  
> -  /* The BSD partition type.  */
> -  int bsd_type;
> -
>    /* The offset of the extended partition.  */
>    unsigned long ext_offset;
> +
> +  /* The index of this partition in the partition table.  */
> +  int index;
>  };
>  
>  static inline int
> @@ -200,12 +125,4 @@ grub_pc_partition_is_extended (int type)
>  	  || type == GRUB_PC_PARTITION_TYPE_LINUX_EXTENDED);
>  }
>  
> -static inline int
> -grub_pc_partition_is_bsd (int type)
> -{
> -  return (type == GRUB_PC_PARTITION_TYPE_FREEBSD
> -	  || type == GRUB_PC_PARTITION_TYPE_OPENBSD
> -	  || type == GRUB_PC_PARTITION_TYPE_NETBSD);
> -}
> -
>  #endif /* ! GRUB_PC_PARTITION_HEADER */
> diff --git a/kern/disk.c b/kern/disk.c
> index e167fb6..6eb9e4b 100644
> --- a/kern/disk.c
> +++ b/kern/disk.c
> @@ -334,6 +334,7 @@ grub_disk_open (const char *name)
>  void
>  grub_disk_close (grub_disk_t disk)
>  {
> +  grub_partition_t part;
>    grub_dprintf ("disk", "Closing `%s'.\n", disk->name);
>  
>    if (disk->dev && disk->dev->close)
> @@ -342,7 +343,13 @@ grub_disk_close (grub_disk_t disk)
>    /* Reset the timer.  */
>    grub_last_time = grub_get_time_ms ();
>  
> -  grub_free (disk->partition);
> +  while (disk->partition)
> +    {
> +      part = disk->partition->parent;
> +      grub_free (disk->partition->data);
> +      grub_free (disk->partition);
> +      disk->partition = part;
> +    }
>    grub_free ((void *) disk->name);
>    grub_free (disk);
>  }
> @@ -353,18 +360,19 @@ grub_disk_close (grub_disk_t disk)
>     - Verify that the range is inside the partition.  */
>  static grub_err_t
>  grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
> -		       grub_off_t *offset, grub_size_t size)
> +			grub_off_t *offset, grub_size_t size)
>  {
> +  grub_partition_t part;
>    *sector += *offset >> GRUB_DISK_SECTOR_BITS;
>    *offset &= GRUB_DISK_SECTOR_SIZE - 1;
>  
> -  if (disk->partition)
> +  for (part = disk->partition; part; part = part->parent)
>      {
>        grub_disk_addr_t start;
>        grub_uint64_t len;
>  
> -      start = grub_partition_get_start (disk->partition);
> -      len = grub_partition_get_len (disk->partition);
> +      start = grub_partition_get_start (part);
> +      len = grub_partition_get_len (part);
>  
>        if (*sector >= len
>  	  || len - *sector < ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
> diff --git a/kern/partition.c b/kern/partition.c
> index 4d5c63a..4bcd8c7 100644
> --- a/kern/partition.c
> +++ b/kern/partition.c
> @@ -17,6 +17,7 @@
>   */
>  
>  #include <grub/misc.h>
> +#include <grub/mm.h>
>  #include <grub/partition.h>
>  #include <grub/disk.h>
>  
> @@ -54,17 +55,58 @@ grub_partition_map_iterate (int (*hook) (const grub_partition_map_t partmap))
>    return 0;
>  }
>  
> +static grub_partition_t
> +grub_partition_map_probe (const grub_partition_map_t partmap,
> +			  grub_disk_t disk, int partnum)
> +{
> +  grub_partition_t p = 0;
> +
> +  auto int find_func (grub_disk_t d, const grub_partition_t partition);
> +
> +  int find_func (grub_disk_t d __attribute__ ((unused)),
> +		 const grub_partition_t partition)
> +    {
> +      if (partnum == partition->number)
> +	{
> +	  p = (grub_partition_t) grub_malloc (sizeof (*p));
> +	  if (! p)
> +	    return 1;
> +
> +	  grub_memcpy (p, partition, sizeof (*p));
> +	  return 1;
> +	}
> +
> +      return 0;
> +    }
> +
> +  partmap->iterate (disk, find_func);
> +  if (grub_errno)
> +    goto fail;
> +
> +  return p;
> +
> + fail:
> +  grub_free (p);
> +  return 0;
> +}
> +
>  grub_partition_t
>  grub_partition_probe (struct grub_disk *disk, const char *str)
>  {
>    grub_partition_t part = 0;
> +  grub_partition_t curpart = 0;
> +  grub_partition_t tail;
> +  const char *ptr;
> +  int num;
>  
>    auto int part_map_probe (const grub_partition_map_t partmap);
>  
>    int part_map_probe (const grub_partition_map_t partmap)
>      {
> -      part = partmap->probe (disk, str);
> -      if (part)
> +      disk->partition = part;
> +      curpart = grub_partition_map_probe (partmap, disk, num);
> +      disk->partition = tail;
> +      if (curpart)
>  	return 1;
>  
>        if (grub_errno == GRUB_ERR_BAD_PART_TABLE)
> @@ -77,27 +119,54 @@ grub_partition_probe (struct grub_disk *disk, const char *str)
>        return 1;
>      }
>  
> -  /* Use the first partition map type found.  */
> -  grub_partition_map_iterate (part_map_probe);
> +  part = tail = disk->partition;
> +
> +  for (ptr = str; *ptr;)
> +    {
> +      /* BSD-like partition specification.  */
> +      if (*ptr >= 'a' && *ptr <= 'z')
> +	num = *(ptr++) - 'a';
> +      else
> +	num = grub_strtoul (ptr, (char **) &ptr, 0) - 1;
> +
> +      curpart = 0;
> +      /* Use the first partition map type found.  */
> +      grub_partition_map_iterate (part_map_probe);
> +
> +      if (! curpart)
> +	{
> +	  while (part)
> +	    {
> +	      curpart = part->parent;
> +	      grub_free (part);
> +	      part = curpart;
> +	    }
> +	  return 0;
> +	}
> +      curpart->parent = part;
> +      part = curpart;
> +      if (! ptr || *ptr != ',')
> +	break;
> +      ptr++;
> +    }
>  
>    return part;
>  }
>  
> -int
> -grub_partition_iterate (struct grub_disk *disk,
> -			int (*hook) (grub_disk_t disk,
> -				     const grub_partition_t partition))
> +static grub_partition_map_t
> +get_partmap (struct grub_disk *disk)
>  {
>    grub_partition_map_t partmap = 0;
> -  int ret = 0;
> -
> +  struct grub_partition part;
> +  int found = 0;
>    auto int part_map_iterate (const grub_partition_map_t p);
>    auto int part_map_iterate_hook (grub_disk_t d,
>  				  const grub_partition_t partition);
> -
>    int part_map_iterate_hook (grub_disk_t d __attribute__ ((unused)),
> -			     const grub_partition_t partition __attribute__ ((unused)))
> +			     const grub_partition_t partition)
>      {
> +      found = 1;
> +      part = *partition;
>        return 1;
>      }
>  
> @@ -106,22 +175,58 @@ grub_partition_iterate (struct grub_disk *disk,
>        grub_dprintf ("partition", "Detecting %s...\n", p->name);
>        p->iterate (disk, part_map_iterate_hook);
>  
> -      if (grub_errno != GRUB_ERR_NONE)
> +      if (grub_errno != GRUB_ERR_NONE || ! found)
>  	{
>  	  /* Continue to next partition map type.  */
>  	  grub_dprintf ("partition", "%s detection failed.\n", p->name);
>  	  grub_errno = GRUB_ERR_NONE;
>  	  return 0;
>  	}
> +      grub_free (part.data);
>  
>        grub_dprintf ("partition", "%s detection succeeded.\n", p->name);
>        partmap = p;
>        return 1;
>      }
> -
>    grub_partition_map_iterate (part_map_iterate);
> -  if (partmap)
> -    ret = partmap->iterate (disk, hook);
> +  return partmap;
> +}
> +
> +int
> +grub_partition_iterate (struct grub_disk *disk,
> +			int (*hook) (grub_disk_t disk,
> +				     const grub_partition_t partition))
> +{
> +  int ret = 0;
> +
> +  auto int part_iterate (grub_disk_t dsk, const grub_partition_t p);
> +
> +  int part_iterate (grub_disk_t dsk,
> +		    const grub_partition_t partition)
> +    {
> +      struct grub_partition p = *partition;
> +      grub_partition_map_t partmap = 0;
> +      p.parent = dsk->partition;
> +      dsk->partition = 0;
> +      if (hook (dsk, &p))
> +	  return 1;
> +      if (p.start != 0)
> +	{
> +	  dsk->partition = &p;
> +	  partmap = get_partmap (dsk);
> +	  if (partmap)
> +	    ret = partmap->iterate (dsk, part_iterate);
> +	}
> +      dsk->partition = p.parent;
> +      return ret;
> +    }
> +
> +  {
> +    grub_partition_map_t partmap = 0;
> +    partmap = get_partmap (disk);
> +    if (partmap)
> +      ret = partmap->iterate (disk, part_iterate);
> +  }
>  
>    return ret;
>  }
> @@ -129,5 +234,30 @@ grub_partition_iterate (struct grub_disk *disk,
>  char *
>  grub_partition_get_name (const grub_partition_t partition)
>  {
> -  return partition->partmap->get_name (partition);
> +  char *out = 0;
> +  /* Even on 64-bit machines this buffer is enough to hold longest number.  */
> +  char buf[25];
> +  int curlen = 0;
> +  grub_partition_t part;
> +  for (part = partition; part; part = part->parent)
> +    {
> +      int strl;
> +      grub_sprintf (buf, "%d", part->number + 1);
> +      strl = grub_strlen (buf);
> +      if (curlen)
> +	{
> +	  out = grub_realloc (out, curlen + strl + 2);
> +	  grub_memcpy (out + strl + 1, out, curlen);
> +	  out[curlen + 1 + strl] = 0;
> +	  grub_memcpy (out, buf, strl);
> +	  out[strl] = ',';
> +	  curlen = curlen + 1 + strl;
> +	}
> +      else
> +	{
> +	  curlen = strl;
> +	  out = grub_strdup (buf);
> +	}
> +    }
> +  return out;
>  }
> diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c
> index 468e6d0..d9135b2 100644
> --- a/loader/i386/bsd.c
> +++ b/loader/i386/bsd.c
> @@ -86,7 +86,6 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
>  		     grub_uint32_t * unit,
>  		     grub_uint32_t * slice, grub_uint32_t * part)
>  {
> -  char *p;
>    grub_device_t dev; 
>  
>    *biosdev = grub_get_root_biosnumber () & 0xff;
> @@ -96,21 +95,13 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
>    dev = grub_device_open (0);
>    if (dev && dev->disk && dev->disk->partition)
>      {
> -
> -      p = dev->disk->partition->partmap->get_name (dev->disk->partition);
> -      if (p)
> +      if (dev->disk->partition->parent)
>  	{
> -	  if ((p[0] >= '0') && (p[0] <= '9'))
> -	    {
> -	      *slice = grub_strtoul (p, &p, 0);
> -
> -	      if ((p) && (p[0] == ','))
> -		p++;
> -	    }
> -
> -	  if ((p[0] >= 'a') && (p[0] <= 'z'))
> -	    *part = p[0] - 'a';
> +	  *part = dev->disk->partition->number;
> +	  *slice = dev->disk->partition->parent->number + 1;
>  	}
> +      else
> +	*slice = dev->disk->partition->number + 1;
>      }
>    if (dev)
>      grub_device_close (dev);
> diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c
> index 8ce315e..8b8a1a9 100644
> --- a/loader/i386/multiboot.c
> +++ b/loader/i386/multiboot.c
> @@ -155,7 +155,6 @@ static int
>  grub_multiboot_get_bootdev (grub_uint32_t *bootdev)
>  {
>  #ifdef GRUB_MACHINE_PCBIOS
> -  char *p;
>    grub_uint32_t biosdev, slice = ~0, part = ~0;
>    grub_device_t dev;
>  
> @@ -164,21 +163,13 @@ grub_multiboot_get_bootdev (grub_uint32_t *bootdev)
>    dev = grub_device_open (0);
>    if (dev && dev->disk && dev->disk->partition)
>      {
> -
> -      p = dev->disk->partition->partmap->get_name (dev->disk->partition);
> -      if (p)
> +      if (dev->disk->partition->parent)
>  	{
> -	  if ((p[0] >= '0') && (p[0] <= '9'))
> -	    {
> -	      slice = grub_strtoul (p, &p, 0) - 1;
> -
> -	      if ((p) && (p[0] == ','))
> -		p++;
> -	    }
> -
> -	  if ((p[0] >= 'a') && (p[0] <= 'z'))
> -	    part = p[0] - 'a';
> +	  part = dev->disk->partition->number;
> +	  slice = dev->disk->partition->parent->number;
>  	}
> +      else
> +	slice = dev->disk->partition->number;
>      }
>    if (dev)
>      grub_device_close (dev);
> diff --git a/loader/i386/pc/chainloader.c b/loader/i386/pc/chainloader.c
> index caf1450..108884b 100644
> --- a/loader/i386/pc/chainloader.c
> +++ b/loader/i386/pc/chainloader.c
> @@ -31,6 +31,7 @@
>  #include <grub/machine/memory.h>
>  #include <grub/dl.h>
>  #include <grub/command.h>
> +#include <grub/pc_partition.h>
>  #include <grub/machine/biosnum.h>
>  
>  static grub_dl_t my_mod;
> @@ -94,10 +95,28 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
>    dev = grub_device_open (0);
>    if (dev && dev->disk && dev->disk->partition)
>      {
> -      grub_disk_read (dev->disk, dev->disk->partition->offset, 446, 64,
> -		      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
> -      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
> -			    + (dev->disk->partition->index << 4));
> +      grub_disk_t disk = dev->disk;
> +
> +      if (disk)
> +	{
> +	  grub_partition_t p = disk->partition;
> +
> +	  /* In i386-pc, the id is equal to the BIOS drive number.  */
> +	  drive = (int) disk->id;
> +
> +	  if (p && grub_strcmp (p->partmap->name, "pc_partition_map") == 0)
> +	    {
> +	      disk->partition = p->parent;
> +	      grub_disk_read (disk, p->offset, 446, 64,
> +			      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
> +	      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
> +				    + (((struct grub_pc_partition *) p->data)
> +				       ->index << 4));
> +	      disk->partition = p;
> +	    }
> +	}
> +
> +      grub_device_close (dev);
>      }
>  
>    if (dev)
> diff --git a/partmap/acorn.c b/partmap/acorn.c
> index 42fd61f..0abd961 100644
> --- a/partmap/acorn.c
> +++ b/partmap/acorn.c
> @@ -96,21 +96,17 @@ acorn_partition_map_iterate (grub_disk_t disk,
>  					  const grub_partition_t partition))
>  {
>    struct grub_partition part;
> -  struct grub_disk raw;
>    struct linux_part map[LINUX_MAP_ENTRIES];
>    int i;
> -  grub_disk_addr_t sector;
> +  grub_disk_addr_t sector = 0;
>    grub_err_t err;
>  
> -  /* Enforce raw disk access.  */
> -  raw = *disk;
> -  raw.partition = 0;
> -
> -  err = acorn_partition_map_find (&raw, map, &sector);
> +  err = acorn_partition_map_find (disk, map, &sector);
>    if (err)
>      return err;
>  
>    part.partmap = &grub_acorn_partition_map;
> +  part.data = 0;
>  
>    for (i = 0; i != LINUX_MAP_ENTRIES; ++i)
>      {
> @@ -121,7 +117,7 @@ acorn_partition_map_iterate (grub_disk_t disk,
>        part.start = sector + map[i].start;
>        part.len = map[i].size;
>        part.offset = 6;
> -      part.index = i;
> +      part.number = i;
>  
>        if (hook (disk, &part))
>  	return grub_errno;
> @@ -130,60 +126,6 @@ acorn_partition_map_iterate (grub_disk_t disk,
>    return GRUB_ERR_NONE;
>  }
>  
> -
> -static grub_partition_t
> -acorn_partition_map_probe (grub_disk_t disk, const char *str)
> -{
> -  struct linux_part map[LINUX_MAP_ENTRIES];
> -  struct grub_disk raw = *disk;
> -  unsigned long partnum = grub_strtoul (str, 0, 10) - 1;
> -  grub_disk_addr_t sector;
> -  grub_err_t err;
> -  grub_partition_t p;
> -
> -  /* Enforce raw disk access.  */
> -  raw.partition = 0;
> -
> -  /* Get the partition number.  */
> -  if (partnum > LINUX_MAP_ENTRIES)
> -    goto fail;
> -
> -  err = acorn_partition_map_find (&raw, map, &sector);
> -  if (err)
> -    return 0;
> -
> -  if (map[partnum].magic != LINUX_NATIVE_MAGIC
> -      && map[partnum].magic != LINUX_SWAP_MAGIC)
> -    goto fail;
> -
> -  p = grub_malloc (sizeof (struct grub_partition));
> -  if (! p)
> -    return 0;
> -
> -  p->start = sector + map[partnum].start;
> -  p->len = map[partnum].size;
> -  p->offset = 6;
> -  p->index = partnum;
> -  return p;
> -
> -fail:
> -  grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
> -  return 0;
> -}
> -
> -
> -static char *
> -acorn_partition_map_get_name (const grub_partition_t p)
> -{
> -  char *name;
> -
> -  name = grub_malloc (13);
> -  if (! name)
> -    return 0;
> -
> -  grub_sprintf (name, "%d", p->index + 1);
> -  return name;
> -}
>  \f
>  
>  /* Partition map type.  */
> @@ -191,8 +133,6 @@ static struct grub_partition_map grub_acorn_partition_map =
>  {
>    .name = "Linux/ADFS partition map",
>    .iterate = acorn_partition_map_iterate,
> -  .probe = acorn_partition_map_probe,
> -  .get_name = acorn_partition_map_get_name
>  };
>  
>  GRUB_MOD_INIT(acorn_partition_map)
> diff --git a/partmap/amiga.c b/partmap/amiga.c
> index ffb807f..b246ca4 100644
> --- a/partmap/amiga.c
> +++ b/partmap/amiga.c
> @@ -76,20 +76,15 @@ amiga_partition_map_iterate (grub_disk_t disk,
>  {
>    struct grub_partition part;
>    struct grub_amiga_rdsk rdsk;
> -  struct grub_disk raw;
>    int partno = 0;
>    int next = -1;
>    unsigned pos;
>  
> -  /* Enforce raw disk access.  */
> -  raw = *disk;
> -  raw.partition = 0;
> -
>    /* The RDSK block is one of the first 15 blocks.  */
>    for (pos = 0; pos < 15; pos++)
>      {
>        /* Read the RDSK block which is a descriptor for the entire disk.  */
> -      if (grub_disk_read (&raw, pos, 0, sizeof (rdsk), &rdsk))
> +      if (grub_disk_read (disk, pos, 0, sizeof (rdsk), &rdsk))
>  	return grub_errno;
>  
>        if (grub_strcmp ((char *) rdsk.magic, "RDSK") == 0)
> @@ -104,13 +99,15 @@ amiga_partition_map_iterate (grub_disk_t disk,
>      return grub_error (GRUB_ERR_BAD_PART_TABLE,
>  		       "Amiga partition map not found.");
>  
> +  part.data = 0;
> +
>    /* The end of the partition list is marked using "-1".  */
>    while (next != -1)
>      {
>        struct grub_amiga_partition apart;
>  
>        /* Read the RDSK block which is a descriptor for the entire disk.  */
> -      if (grub_disk_read (&raw, next, 0, sizeof (apart), &apart))
> +      if (grub_disk_read (disk, next, 0, sizeof (apart), &apart))
>  	return grub_errno;
>  
>        /* Calculate the first block and the size of the partition.  */
> @@ -123,7 +120,7 @@ amiga_partition_map_iterate (grub_disk_t disk,
>  		  * grub_be_to_cpu32 (apart.block_per_track));
>  
>        part.offset = (grub_off_t) next * 512;
> -      part.index = partno;
> +      part.number = partno;
>        part.partmap = &grub_amiga_partition_map;
>  
>        if (hook (disk, &part))
> @@ -136,72 +133,12 @@ amiga_partition_map_iterate (grub_disk_t disk,
>    return 0;
>  }
>  
> -
> -static grub_partition_t
> -amiga_partition_map_probe (grub_disk_t disk, const char *str)
> -{
> -  grub_partition_t p = 0;
> -  int partnum = 0;
> -  char *s = (char *) str;
> -
> -  auto int find_func (grub_disk_t d, const grub_partition_t partition);
> -
> -  int find_func (grub_disk_t d __attribute__ ((unused)),
> -		 const grub_partition_t partition)
> -    {
> -      if (partnum == partition->index)
> -	{
> -	  p = (grub_partition_t) grub_malloc (sizeof (*p));
> -	  if (! p)
> -	    return 1;
> -
> -	  grub_memcpy (p, partition, sizeof (*p));
> -	  return 1;
> -	}
> -
> -      return 0;
> -    }
> -
> -  /* Get the partition number.  */
> -  partnum = grub_strtoul (s, 0, 10) - 1;
> -  if (grub_errno)
> -    {
> -      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
> -      return 0;
> -    }
> -
> -  if (amiga_partition_map_iterate (disk, find_func))
> -    goto fail;
> -
> -  return p;
> -
> - fail:
> -  grub_free (p);
> -  return 0;
> -}
> -
> -
> -static char *
> -amiga_partition_map_get_name (const grub_partition_t p)
> -{
> -  char *name;
> -
> -  name = grub_malloc (13);
> -  if (! name)
> -    return 0;
> -
> -  grub_sprintf (name, "%d", p->index + 1);
> -  return name;
> -}
> -
>  \f
>  /* Partition map type.  */
>  static struct grub_partition_map grub_amiga_partition_map =
>    {
>      .name = "amiga_partition_map",
>      .iterate = amiga_partition_map_iterate,
> -    .probe = amiga_partition_map_probe,
> -    .get_name = amiga_partition_map_get_name
>    };
>  
>  GRUB_MOD_INIT(amiga_partition_map)
> diff --git a/partmap/apple.c b/partmap/apple.c
> index fce2f2c..1621086 100644
> --- a/partmap/apple.c
> +++ b/partmap/apple.c
> @@ -104,17 +104,12 @@ apple_partition_map_iterate (grub_disk_t disk,
>    struct grub_partition part;
>    struct grub_apple_header aheader;
>    struct grub_apple_part apart;
> -  struct grub_disk raw;
>    int partno = 0;
>    unsigned pos = GRUB_DISK_SECTOR_SIZE;
>  
> -  /* Enforce raw disk access.  */
> -  raw = *disk;
> -  raw.partition = 0;
> -
>    part.partmap = &grub_apple_partition_map;
>  
> -  if (grub_disk_read (&raw, 0, 0, sizeof (aheader), &aheader))
> +  if (grub_disk_read (disk, 0, 0, sizeof (aheader), &aheader))
>      return grub_errno;
>  
>    if (grub_be_to_cpu16 (aheader.magic) != GRUB_APPLE_HEADER_MAGIC)
> @@ -126,9 +121,11 @@ apple_partition_map_iterate (grub_disk_t disk,
>        goto fail;
>      }
>  
> +  part.data = 0;
> +
>    for (;;)
>      {
> -      if (grub_disk_read (&raw, pos / GRUB_DISK_SECTOR_SIZE,
> +      if (grub_disk_read (disk, pos / GRUB_DISK_SECTOR_SIZE,
>  			  pos % GRUB_DISK_SECTOR_SIZE,
>  			  sizeof (struct grub_apple_part),  &apart))
>  	return grub_errno;
> @@ -145,7 +142,7 @@ apple_partition_map_iterate (grub_disk_t disk,
>        part.start = grub_be_to_cpu32 (apart.first_phys_block);
>        part.len = grub_be_to_cpu32 (apart.blockcnt);
>        part.offset = pos;
> -      part.index = partno;
> +      part.number = partno;
>  
>        grub_dprintf ("partition",
>  		    "partition %d: name %s, type %s, start 0x%x, len 0x%x\n",
> @@ -172,72 +169,12 @@ apple_partition_map_iterate (grub_disk_t disk,
>  		     "Apple partition map not found.");
>  }
>  
> -
> -static grub_partition_t
> -apple_partition_map_probe (grub_disk_t disk, const char *str)
> -{
> -  grub_partition_t p = 0;
> -  int partnum = 0;
> -  char *s = (char *) str;
> -
> -  auto int find_func (grub_disk_t d, const grub_partition_t partition);
> -
> -  int find_func (grub_disk_t d __attribute__ ((unused)),
> -		 const grub_partition_t partition)
> -    {
> -      if (partnum == partition->index)
> -	{
> -	  p = (grub_partition_t) grub_malloc (sizeof (*p));
> -	  if (! p)
> -	    return 1;
> -
> -	  grub_memcpy (p, partition, sizeof (*p));
> -	  return 1;
> -	}
> -
> -      return 0;
> -    }
> -
> -  /* Get the partition number.  */
> -  partnum = grub_strtoul (s, 0, 10) - 1;
> -  if (grub_errno)
> -    {
> -      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
> -      return 0;
> -    }
> -
> -  if (apple_partition_map_iterate (disk, find_func))
> -    goto fail;
> -
> -  return p;
> -
> - fail:
> -  grub_free (p);
> -  return 0;
> -}
> -
> -
> -static char *
> -apple_partition_map_get_name (const grub_partition_t p)
> -{
> -  char *name;
> -
> -  name = grub_malloc (13);
> -  if (! name)
> -    return 0;
> -
> -  grub_sprintf (name, "%d", p->index + 1);
> -  return name;
> -}
> -
>  \f
>  /* Partition map type.  */
>  static struct grub_partition_map grub_apple_partition_map =
>    {
>      .name = "apple_partition_map",
>      .iterate = apple_partition_map_iterate,
> -    .probe = apple_partition_map_probe,
> -    .get_name = apple_partition_map_get_name
>    };
>  
>  GRUB_MOD_INIT(apple_partition_map)
> diff --git a/partmap/bsdlabel.c b/partmap/bsdlabel.c
> new file mode 100644
> index 0000000..68c199f
> --- /dev/null
> +++ b/partmap/bsdlabel.c
> @@ -0,0 +1,89 @@
> +/* bsdlabel.c - Read BSD style partition tables.  */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2002,2004,2005,2006,2007,2008,2009  Free Software Foundation, Inc.
> + *
> + *  GRUB 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 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <grub/partition.h>
> +#include <grub/bsdlabel.h>
> +#include <grub/disk.h>
> +#include <grub/mm.h>
> +#include <grub/misc.h>
> +#include <grub/dl.h>
> +
> +static struct grub_partition_map grub_bsdlabel_partition_map;
> +\f
> +
> +static grub_err_t
> +bsdlabel_partition_map_iterate (grub_disk_t disk,
> +			  int (*hook) (grub_disk_t disk,
> +				       const grub_partition_t partition))
> +{
> +  struct grub_pc_partition_disk_label label;
> +  struct grub_partition p;
> +  grub_partition_t part;
> +  grub_disk_addr_t delta = 0;
> +
> +  /* BSDLabel offsets are absolute even when it's embed inside partition.  */
> +  for (part = disk->partition; part; part = part->parent)
> +    delta += grub_partition_get_start (part);
> +
> +  /* Read the BSD label.  */
> +  if (grub_disk_read (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR,
> +		      0, sizeof (label), &label))
> +    goto finish;
> +
> +  /* Check if it is valid.  */
> +  if (label.magic != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
> +    return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
> +  for (p.number = 0;
> +       p.number < grub_cpu_to_le16 (label.num_partitions);
> +       p.number++)
> +    {
> +      struct grub_pc_partition_bsd_entry *be
> +	= label.entries + p.number;
> +
> +      p.start = grub_le_to_cpu32 (be->offset) - delta;
> +      p.len = grub_le_to_cpu32 (be->size);
> +      p.offset = GRUB_PC_PARTITION_BSD_LABEL_SECTOR;
> +      p.partmap = &grub_bsdlabel_partition_map;
> +      p.data = 0;
> +
> +      if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
> +	if (hook (disk, &p))
> +	  return 1;
> +    }
> + finish:
> +  return grub_errno;
> +}
> +
> +\f
> +/* Partition map type.  */
> +static struct grub_partition_map grub_bsdlabel_partition_map =
> +  {
> +    .name = "bsdlabel_partition_map",
> +    .iterate = bsdlabel_partition_map_iterate,
> +  };
> +
> +GRUB_MOD_INIT(bsdlabel_partition_map)
> +{
> +  grub_partition_map_register (&grub_bsdlabel_partition_map);
> +}
> +
> +GRUB_MOD_FINI(bsdlabel_partition_map)
> +{
> +  grub_partition_map_unregister (&grub_bsdlabel_partition_map);
> +}
> diff --git a/partmap/gpt.c b/partmap/gpt.c
> index d646d41..bfe6269 100644
> --- a/partmap/gpt.c
> +++ b/partmap/gpt.c
> @@ -44,18 +44,13 @@ gpt_partition_map_iterate (grub_disk_t disk,
>    struct grub_partition part;
>    struct grub_gpt_header gpt;
>    struct grub_gpt_partentry entry;
> -  struct grub_disk raw;
>    struct grub_pc_partition_mbr mbr;
>    grub_uint64_t entries;
>    unsigned int i;
>    int last_offset = 0;
>  
> -  /* Enforce raw disk access.  */
> -  raw = *disk;
> -  raw.partition = 0;
> -
>    /* Read the protective MBR.  */
> -  if (grub_disk_read (&raw, 0, 0, sizeof (mbr), &mbr))
> +  if (grub_disk_read (disk, 0, 0, sizeof (mbr), &mbr))
>      return grub_errno;
>  
>    /* Check if it is valid.  */
> @@ -67,7 +62,7 @@ gpt_partition_map_iterate (grub_disk_t disk,
>      return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
>  
>    /* Read the GPT header.  */
> -  if (grub_disk_read (&raw, 1, 0, sizeof (gpt), &gpt))
> +  if (grub_disk_read (disk, 1, 0, sizeof (gpt), &gpt))
>      return grub_errno;
>  
>    if (grub_memcmp (gpt.magic, grub_gpt_magic, sizeof (grub_gpt_magic)))
> @@ -78,7 +73,7 @@ gpt_partition_map_iterate (grub_disk_t disk,
>    entries = grub_le_to_cpu64 (gpt.partitions);
>    for (i = 0; i < grub_le_to_cpu32 (gpt.maxpart); i++)
>      {
> -      if (grub_disk_read (&raw, entries, last_offset,
> +      if (grub_disk_read (disk, entries, last_offset,
>  			  sizeof (entry), &entry))
>  	return grub_errno;
>  
> @@ -90,9 +85,9 @@ gpt_partition_map_iterate (grub_disk_t disk,
>  	  part.len = (grub_le_to_cpu64 (entry.end)
>  		      - grub_le_to_cpu64 (entry.start) + 1);
>  	  part.offset = entries;
> -	  part.index = i;
> +	  part.number = i;
>  	  part.partmap = &grub_gpt_partition_map;
> -	  part.data = &entry;
> +	  part.data = 0;
>  
>  	  grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", i,
>  			(unsigned long long) part.start,
> @@ -113,73 +108,12 @@ gpt_partition_map_iterate (grub_disk_t disk,
>    return 0;
>  }
>  
> -
> -static grub_partition_t
> -gpt_partition_map_probe (grub_disk_t disk, const char *str)
> -{
> -  grub_partition_t p = 0;
> -  int partnum = 0;
> -  char *s = (char *) str;
> -
> -  auto int find_func (grub_disk_t d, const grub_partition_t partition);
> -
> -  int find_func (grub_disk_t d __attribute__ ((unused)),
> -		 const grub_partition_t partition)
> -    {
> -      if (partnum == partition->index)
> -	{
> -	  p = (grub_partition_t) grub_malloc (sizeof (*p));
> -	  if (! p)
> -	    return 1;
> -
> -	  grub_memcpy (p, partition, sizeof (*p));
> -	  return 1;
> -	}
> -
> -      return 0;
> -    }
> -
> -  /* Get the partition number.  */
> -  partnum = grub_strtoul (s, 0, 10) - 1;
> -  if (grub_errno)
> -    {
> -      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
> -      return 0;
> -    }
> -
> -  gpt_partition_map_iterate (disk, find_func);
> -  if (grub_errno)
> -    goto fail;
> -
> -  return p;
> -
> - fail:
> -  grub_free (p);
> -  return 0;
> -}
> -
> -
> -static char *
> -gpt_partition_map_get_name (const grub_partition_t p)
> -{
> -  char *name;
> -
> -  name = grub_malloc (13);
> -  if (! name)
> -    return 0;
> -
> -  grub_sprintf (name, "%d", p->index + 1);
> -  return name;
> -}
> -
>  \f
>  /* Partition map type.  */
>  static struct grub_partition_map grub_gpt_partition_map =
>    {
>      .name = "gpt_partition_map",
>      .iterate = gpt_partition_map_iterate,
> -    .probe = gpt_partition_map_probe,
> -    .get_name = gpt_partition_map_get_name
>    };
>  
>  GRUB_MOD_INIT(gpt_partition_map)
> diff --git a/partmap/pc.c b/partmap/pc.c
> index 6f68ecf..b195087 100644
> --- a/partmap/pc.c
> +++ b/partmap/pc.c
> @@ -27,178 +27,82 @@
>  static struct grub_partition_map grub_pc_partition_map;
>  \f
>  
> -/* Parse the partition representation in STR and return a partition.  */
> -static grub_partition_t
> -grub_partition_parse (const char *str)
> -{
> -  grub_partition_t p;
> -  struct grub_pc_partition *pcdata;
> -
> -  char *s = (char *) str;
> -
> -  p = (grub_partition_t) grub_malloc (sizeof (*p));
> -  if (! p)
> -    return 0;
> -
> -  pcdata = (struct grub_pc_partition *) grub_malloc (sizeof (*pcdata));
> -  if (! pcdata)
> -    goto fail;
> -
> -  p->data = pcdata;
> -  p->partmap = &grub_pc_partition_map;
> -
> -  /* Initialize some of the fields with invalid values.  */
> -  pcdata->bsd_part = pcdata->dos_type = pcdata->bsd_type = p->index = -1;
> -
> -  /* Get the DOS partition number. The number is counted from one for
> -     the user interface, and from zero internally.  */
> -  pcdata->dos_part = grub_strtoul (s, &s, 0) - 1;
> -
> -  if (grub_errno)
> -    {
> -      /* Not found. Maybe only a BSD label is specified.  */
> -      pcdata->dos_part = -1;
> -      grub_errno = GRUB_ERR_NONE;
> -    }
> -  else if (*s == ',')
> -    s++;
> -
> -  if (*s)
> -    {
> -      if (*s >= 'a' && *s <= 'h')
> -	{
> -	  pcdata->bsd_part = *s - 'a';
> -	  s++;
> -	}
> -
> -      if (*s)
> -	goto fail;
> -    }
> -
> -  if (pcdata->dos_part == -1 && pcdata->bsd_part == -1)
> -    goto fail;
> -
> -  return p;
> -
> - fail:
> -  grub_free (p);
> -  grub_free (pcdata);
> -  grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
> -  return 0;
> -}
> -
>  static grub_err_t
>  pc_partition_map_iterate (grub_disk_t disk,
>  			  int (*hook) (grub_disk_t disk,
>  				       const grub_partition_t partition))
>  {
>    struct grub_partition p;
> -  struct grub_pc_partition pcdata;
> +  struct grub_pc_partition *pcdata;
>    struct grub_pc_partition_mbr mbr;
> -  struct grub_pc_partition_disk_label label;
> -  struct grub_disk raw;
> -
> -  /* Enforce raw disk access.  */
> -  raw = *disk;
> -  raw.partition = 0;
>  
> +  pcdata = grub_malloc (sizeof (*pcdata));
>    p.offset = 0;
> -  pcdata.ext_offset = 0;
> -  pcdata.dos_part = -1;
> -  p.data = &pcdata;
> +  pcdata->ext_offset = 0;
> +  p.data = pcdata;
> +  p.number = -1;
>    p.partmap = &grub_pc_partition_map;
>  
> +  /* Signature check is known to cause false positives
> +     because the same signature is used for bootsectors.  */
> +  if (disk->partition)
> +    {
> +      grub_free (pcdata);
> +      return grub_error (GRUB_ERR_BAD_PART_TABLE,
> +			 "pc partition can't be nested");
> +    }
> +
>    while (1)
>      {
>        int i;
>        struct grub_pc_partition_entry *e;
>  
>        /* Read the MBR.  */
> -      if (grub_disk_read (&raw, p.offset, 0, sizeof (mbr), &mbr))
> +      if (grub_disk_read (disk, p.offset, 0, sizeof (mbr), &mbr))
>  	goto finish;
>  
>        /* Check if it is valid.  */
>        if (mbr.signature != grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE))
> -	return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
> +	{
> +	  grub_free (pcdata);
> +	  return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
> +	}
>  
>        /* Analyze DOS partitions.  */
> -      for (p.index = 0; p.index < 4; p.index++)
> +      for (pcdata->index = 0; pcdata->index < 4; pcdata->index++)
>  	{
> -	  e = mbr.entries + p.index;
> +	  e = mbr.entries + pcdata->index;
>  
>  	  p.start = p.offset + grub_le_to_cpu32 (e->start);
>  	  p.len = grub_le_to_cpu32 (e->length);
> -	  pcdata.bsd_part = -1;
> -	  pcdata.dos_type = e->type;
> -	  pcdata.bsd_type = -1;
> +	  pcdata->dos_type = e->type;
>  
>  	  grub_dprintf ("partition",
>  			"partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n",
> -			p.index, e->flag, pcdata.dos_type,
> +			pcdata->index, e->flag, pcdata->dos_type,
>  			(unsigned long long) p.start,
>  			(unsigned long long) p.len);
>  
>  	  /* If this is a GPT partition, this MBR is just a dummy.  */
> -	  if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && p.index == 0)
> -	    return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr");
> +	  if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && pcdata->index == 0)
> +	    {
> +	      grub_free (pcdata);
> +	      return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr");
> +	    }
>  
>  	  /* If this partition is a normal one, call the hook.  */
>  	  if (! grub_pc_partition_is_empty (e->type)
>  	      && ! grub_pc_partition_is_extended (e->type))
>  	    {
> -	      pcdata.dos_part++;
> +	      p.number++;
>  
>  	      if (hook (disk, &p))
>  		return 1;
> -
> -	      /* Check if this is a BSD partition.  */
> -	      if (grub_pc_partition_is_bsd (e->type))
> -		{
> -		  /* Check if the BSD label is within the DOS partition.  */
> -		  if (p.len <= GRUB_PC_PARTITION_BSD_LABEL_SECTOR)
> -		    {
> -		      grub_dprintf ("partition", "no space for disk label\n");
> -		      continue;
> -		    }
> -		  /* Read the BSD label.  */
> -		  if (grub_disk_read (&raw,
> -				      (p.start
> -				       + GRUB_PC_PARTITION_BSD_LABEL_SECTOR),
> -				      0,
> -				      sizeof (label),
> -				      &label))
> -		    goto finish;
> -
> -		  /* Check if it is valid.  */
> -		  if (label.magic
> -		      != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
> -		    {
> -		      grub_dprintf ("partition",
> -				    "invalid disk label magic 0x%x on partition %d\n",
> -				    label.magic, p.index);
> -		      continue;
> -		    }
> -		  for (pcdata.bsd_part = 0;
> -		       pcdata.bsd_part < grub_cpu_to_le16 (label.num_partitions);
> -		       pcdata.bsd_part++)
> -		    {
> -		      struct grub_pc_partition_bsd_entry *be
> -			= label.entries + pcdata.bsd_part;
> -
> -		      p.start = grub_le_to_cpu32 (be->offset);
> -		      p.len = grub_le_to_cpu32 (be->size);
> -		      pcdata.bsd_type = be->fs_type;
> -
> -		      if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
> -			if (hook (disk, &p))
> -			  return 1;
> -		    }
> -		}
>  	    }
> -	  else if (pcdata.dos_part < 4)
> +	  else if (p.number < 4)
>  	    /* If this partition is a logical one, shouldn't increase the
>  	       partition number.  */
> -	    pcdata.dos_part++;
> +	    p.number++;
>  	}
>  
>        /* Find an extended partition.  */
> @@ -208,9 +112,9 @@ pc_partition_map_iterate (grub_disk_t disk,
>  
>  	  if (grub_pc_partition_is_extended (e->type))
>  	    {
> -	      p.offset = pcdata.ext_offset + grub_le_to_cpu32 (e->start);
> -	      if (! pcdata.ext_offset)
> -		pcdata.ext_offset = p.offset;
> +	      p.offset = pcdata->ext_offset + grub_le_to_cpu32 (e->start);
> +	      if (! pcdata->ext_offset)
> +		pcdata->ext_offset = p.offset;
>  
>  	      break;
>  	    }
> @@ -222,77 +126,8 @@ pc_partition_map_iterate (grub_disk_t disk,
>      }
>  
>   finish:
> -  return grub_errno;
> -}
> -
> -
> -static grub_partition_t
> -pc_partition_map_probe (grub_disk_t disk, const char *str)
> -{
> -  grub_partition_t p;
> -  struct grub_pc_partition *pcdata;
> -
> -  auto int find_func (grub_disk_t d, const grub_partition_t partition);
> -
> -  int find_func (grub_disk_t d __attribute__ ((unused)),
> -		 const grub_partition_t partition)
> -    {
> -      struct grub_pc_partition *partdata = partition->data;
> -
> -      if ((pcdata->dos_part == partdata->dos_part || pcdata->dos_part == -1)
> -	  && pcdata->bsd_part == partdata->bsd_part)
> -	{
> -	  grub_memcpy (p, partition, sizeof (*p));
> -	  p->data = pcdata;
> -	  grub_memcpy (pcdata, partdata, sizeof (*pcdata));
> -	  return 1;
> -	}
> -
> -      return 0;
> -    }
> -
> -  p = grub_partition_parse (str);
> -  if (! p)
> -    return 0;
> -
> -  pcdata = p->data;
> -  pc_partition_map_iterate (disk, find_func);
> -  if (grub_errno)
> -    goto fail;
> -
> -  if (p->index < 0)
> -    {
> -      grub_error (GRUB_ERR_BAD_DEVICE, "no such partition");
> -      goto fail;
> -    }
> -
> -  return p;
> -
> - fail:
> -  grub_free (p);
>    grub_free (pcdata);
> -  return 0;
> -}
> -
> -
> -static char *
> -pc_partition_map_get_name (const grub_partition_t p)
> -{
> -  char *name;
> -  struct grub_pc_partition *pcdata = p->data;
> -
> -  name = grub_malloc (13);
> -  if (! name)
> -    return 0;
> -
> -  if (pcdata->bsd_part < 0)
> -    grub_sprintf (name, "%d", pcdata->dos_part + 1);
> -  else if (pcdata->dos_part < 0)
> -    grub_sprintf (name, "%c", pcdata->bsd_part + 'a');
> -  else
> -    grub_sprintf (name, "%d,%c", pcdata->dos_part + 1, pcdata->bsd_part + 'a');
> -
> -  return name;
> +  return grub_errno;
>  }
>  
>  \f
> @@ -301,8 +136,6 @@ static struct grub_partition_map grub_pc_partition_map =
>    {
>      .name = "pc_partition_map",
>      .iterate = pc_partition_map_iterate,
> -    .probe = pc_partition_map_probe,
> -    .get_name = pc_partition_map_get_name
>    };
>  
>  GRUB_MOD_INIT(pc_partition_map)
> diff --git a/partmap/sun.c b/partmap/sun.c
> index 6094777..c6633a1 100644
> --- a/partmap/sun.c
> +++ b/partmap/sun.c
> @@ -88,13 +88,9 @@ sun_partition_map_iterate (grub_disk_t disk,
>  					const grub_partition_t partition))
>  {
>    grub_partition_t p;
> -  struct grub_disk raw;
>    struct grub_sun_block block;
>    int partnum;
>  
> -  raw = *disk;
> -  raw.partition = 0;
> -
>    p = (grub_partition_t) grub_malloc (sizeof (struct grub_partition));
>    if (! p)
>      return grub_errno;
> @@ -102,7 +98,7 @@ sun_partition_map_iterate (grub_disk_t disk,
>    p->offset = 0;
>    p->data = 0;
>    p->partmap = &grub_sun_partition_map;
> -  if (grub_disk_read (&raw, 0, 0, sizeof (struct grub_sun_block),
> +  if (grub_disk_read (disk, 0, 0, sizeof (struct grub_sun_block),
>  		      &block) == GRUB_ERR_NONE)
>      {
>        if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.magic))
> @@ -126,7 +122,7 @@ sun_partition_map_iterate (grub_disk_t disk,
>  		      * grub_be_to_cpu16 (block.ntrks)
>  		      * grub_be_to_cpu16 (block.nsect));
>  	  p->len = grub_be_to_cpu32 (desc->num_sectors);
> -	  p->index = partnum;
> +	  p->number = partnum;
>  	  if (p->len)
>  	    {
>  	      if (hook (disk, p))
> @@ -140,68 +136,11 @@ sun_partition_map_iterate (grub_disk_t disk,
>    return grub_errno;
>  }
>  
> -static grub_partition_t
> -sun_partition_map_probe (grub_disk_t disk, const char *str)
> -{
> -  grub_partition_t p = 0;
> -  int partnum = 0;
> -  char *s = (char *) str;
> -
> -  auto int find_func (grub_disk_t d, const grub_partition_t partition);
> -
> -  int find_func (grub_disk_t d __attribute__ ((unused)),
> -		 const grub_partition_t partition)
> -    {
> -      if (partnum == partition->index)
> -        {
> -          p = (grub_partition_t) grub_malloc (sizeof (*p));
> -          if (p)
> -            grub_memcpy (p, partition, sizeof (*p));
> -
> -          return 1;
> -        }
> -
> -      return 0;
> -    }
> -
> -  grub_errno = GRUB_ERR_NONE;
> -  partnum = grub_strtoul (s, 0, 10) - 1;
> -  if (grub_errno == GRUB_ERR_NONE)
> -    {
> -      if (sun_partition_map_iterate (disk, find_func))
> -        {
> -          grub_free (p);
> -          p = 0;
> -        }
> -    }
> -  else
> -    {
> -      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
> -      p = 0;
> -    }
> -
> -  return p;
> -}
> -
> -static char *
> -sun_partition_map_get_name (const grub_partition_t p)
> -{
> -  char *name;
> -
> -  name = grub_malloc (13);
> -  if (name)
> -    grub_sprintf (name, "%d", p->index + 1);
> -
> -  return name;
> -}
> -
>  /* Partition map type.  */
>  static struct grub_partition_map grub_sun_partition_map =
>    {
>      .name = "sun_partition_map",
>      .iterate = sun_partition_map_iterate,
> -    .probe = sun_partition_map_probe,
> -    .get_name = sun_partition_map_get_name
>    };
>  
>  GRUB_MOD_INIT(sun_partition_map)
> diff --git a/parttool/pcpart.c b/parttool/pcpart.c
> index 6876d0d..c0c53e6 100644
> --- a/parttool/pcpart.c
> +++ b/parttool/pcpart.c
> @@ -47,9 +47,9 @@ static grub_err_t grub_pcpart_boot (const grub_device_t dev,
>    if (dev->disk->partition->offset)
>      return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a primary partition");
>  
> -  index = dev->disk->partition->index;
> +  index = ((struct grub_pc_partition *) dev->disk->partition->data)->index;
>    part = dev->disk->partition;
> -  dev->disk->partition = 0;
> +  dev->disk->partition = part->parent;
>  
>    /* Read the MBR.  */
>    if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr))
> @@ -94,9 +94,9 @@ static grub_err_t grub_pcpart_type (const grub_device_t dev,
>    grub_partition_t part;
>    struct grub_pc_partition_mbr mbr;
>  
> -  index = dev->disk->partition->index;
> +  index = ((struct grub_pc_partition *) dev->disk->partition->data)->index;
>    part = dev->disk->partition;
> -  dev->disk->partition = 0;
> +  dev->disk->partition = part->parent;
>  
>    /* Read the parttable.  */
>    if (grub_disk_read (dev->disk, part->offset, 0,
> diff --git a/util/hostdisk.c b/util/hostdisk.c
> index d84e7f3..994e256 100644
> --- a/util/hostdisk.c
> +++ b/util/hostdisk.c
> @@ -321,10 +321,15 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
>    {
>      int is_partition = 0;
>      char dev[PATH_MAX];
> +    grub_partition_t part;
> +    grub_disk_addr_t part_start = 0;
> +
> +    for (part = disk->partition; part; part = part->parent)
> +      part_start += grub_partition_get_start (part);
>  
>      strcpy (dev, map[disk->id].device);
>      if (disk->partition && strncmp (map[disk->id].device, "/dev/", 5) == 0)
> -      is_partition = linux_find_partition (dev, disk->partition->start);
> +      is_partition = linux_find_partition (dev, part_start);
>  
>      /* Open the partition.  */
>      grub_dprintf ("hostdisk", "opening the device `%s' in open_device()", dev);
> @@ -339,7 +344,7 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
>      ioctl (fd, BLKFLSBUF, 0);
>  
>      if (is_partition)
> -      sector -= disk->partition->start;
> +      sector -= part_start;
>    }
>  #else /* ! __linux__ */
>  #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
> @@ -919,39 +924,27 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
>      int find_partition (grub_disk_t disk __attribute__ ((unused)),
>  			const grub_partition_t partition)
>        {
> - 	struct grub_pc_partition *pcdata = NULL;
> -
> -	if (strcmp (partition->partmap->name, "pc_partition_map") == 0)
> -	  pcdata = partition->data;
> +	grub_partition_t part;
> +	grub_disk_addr_t part_start = 0;
> +	grub_util_info ("Partition %d starts from %lu",
> +			partition->number, partition->start);
>  
> -	if (pcdata)
> -	  {
> -	    if (pcdata->bsd_part < 0)
> -	      grub_util_info ("DOS partition %d starts from %lu",
> -			      pcdata->dos_part, partition->start);
> -	    else
> -	      grub_util_info ("BSD partition %d,%c starts from %lu",
> -			      pcdata->dos_part, pcdata->bsd_part + 'a',
> -			      partition->start);
> -	  }
> -	else
> -	  {
> -	      grub_util_info ("Partition %d starts from %lu",
> -			      partition->index, partition->start);
> -	  }
> +	for (part = partition; part; part = part->parent)
> +	  part_start += grub_partition_get_start (part);
>  
> -	if (hdg.start == partition->start)
> +	if (hdg.start == part_start)
>  	  {
> -	    if (pcdata)
> +	    if (partition->parent)
>  	      {
> -		dos_part = pcdata->dos_part;
> -		bsd_part = pcdata->bsd_part;
> +		dos_part = partition->parent->number;
> +		bsd_part = partition->number;
>  	      }
>  	    else
>  	      {
> -		dos_part = partition->index;
> +		dos_part = partition->number;
>  		bsd_part = -1;
>  	      }
> +
>  	    return 1;
>  	  }
>  
> diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c
> index 5a51964..aa30fa3 100644
> --- a/util/i386/pc/grub-setup.c
> +++ b/util/i386/pc/grub-setup.c
> @@ -128,7 +128,6 @@ setup (const char *dir,
>  
>        /* For its end offset, include as many dummy partitions as we can.  */
>        if (! grub_pc_partition_is_empty (pcdata->dos_type)
> -	  && ! grub_pc_partition_is_bsd (pcdata->dos_type)
>  	  && embed_region.end > p->start)
>  	embed_region.end = p->start;
>  
> @@ -278,22 +277,19 @@ setup (const char *dir,
>        /* Embed information about the installed location.  */
>        if (root_dev->disk->partition)
>  	{
> -	  if (strcmp (root_dev->disk->partition->partmap->name,
> -		      "pc_partition_map") == 0)
> +	  if (root_dev->disk->partition->parent)
>  	    {
> -	      struct grub_pc_partition *pcdata =
> -		root_dev->disk->partition->data;
> -	      dos_part = pcdata->dos_part;
> -	      bsd_part = pcdata->bsd_part;
> +	      if (root_dev->disk->partition->parent->parent)
> +		grub_util_error ("Installing on doubly nested partitiond is "
> +				 "not supported");
> +	      dos_part = root_dev->disk->partition->parent->number;
> +	      bsd_part = root_dev->disk->partition->number;
>  	    }
> -	  else if (strcmp (root_dev->disk->partition->partmap->name,
> -			   "gpt_partition_map") == 0)
> +	  else
>  	    {
> -	      dos_part = root_dev->disk->partition->index;
> +	      dos_part = root_dev->disk->partition->number;
>  	      bsd_part = -1;
>  	    }
> -	  else
> -	    grub_util_error ("No PC style partitions found");
>  	}
>        else
>  	dos_part = bsd_part = -1;
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel




^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-07-31  7:58   ` Marco Gerards
@ 2009-07-31  9:39     ` Vladimir 'phcoder' Serbinenko
  2009-07-31 19:48       ` Vladimir 'phcoder' Serbinenko
  0 siblings, 1 reply; 36+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-07-31  9:39 UTC (permalink / raw)
  To: The development of GRUB 2

On Fri, Jul 31, 2009 at 9:58 AM, Marco Gerards<mgerards@xs4all.nl> wrote:
> "Vladimir 'phcoder' Serbinenko" <phcoder@gmail.com> writes:
>
>> Rediff
>>
>> On Thu, Jun 11, 2009 at 5:51 PM, Vladimir 'phcoder'
>> Serbinenko<phcoder@gmail.com> wrote:
>>> Hello. Here is a first version of nested partition support. Beware
>>> it's EXPERIMENTAL and may be dagerous. Try at your own risk. With this
>>> patch you lose however the ability to specify bsd partition without
>>> specifying slice. Use search.
>
> Can you please explain what you mean by that you have to specify the
> slice and you have to use search?
Currently to access the BSD partition (hd0,1,a) user can type (hd0,a)
omitting '1' if he has no other BSD partitions. This may be convinient
but is somewhat ad-hoc and needs code in core to support this. With
using search I mean that if the number '1' isn't known user has to use
"search"
>
> What makes this experimental and dangerous?  Can you send in a patch
> that isn't?
Only that I touch core size and when I submitted it, it was only few
days old. Now I use it for over a month and haven't hit any problem
>
> Here a only a few comments on this patch.  In order to properly review
> it, can you explain what the design of the patch is and how it
> essentially works?  It is important to discuss that as well.  Can you
> also describe which problems the patch solves and introduces?
The typical case of the problem it solves is Solaris. When installed
on x86 its partition is subpartitioned. Because of that current grub
can't access its filesystem even if it's UFS or even when ZFS module
is loaded. sun_pc subpartitioning style will be a subject of separate
patch.
Something similar is used for BSD but it's done in an ad-hoc manner in
pc.mod which takes core size uselessly when user has e.g. /boot on lvm
on pc-style. With this patch bsdlabel.mod is a separate module
This patch mainly modifies the translation from sector relative to
partition start to the sector relative to start of disk. Inside every
partition it tries to find a possible subpartition.
Name parsing which was previously a part of every module has been
unified and consolidated in the core.

Could you perhaps quote only parts of patch which you comment
otherwise I have to scroll a lot. Thanks
> Please start with a capital letter and end with a `.'.  I noticed that
> you have committed other patches with this problem in the changelog
> entry.  If you commit something else and if you have the time, I would
> be happy if you could fix that too :-)
Already changed. This patch was sitting for too long
>> +     * partmap/acorn.c (acorn_partition_map_iterate): don't force raw access
>> +     Use number instead of index
>
> What do you mean by "don't force raw access use number instead of
> index"?
It was 2 sentences. Sorry for missing comma and quotes around field
names ('number' and 'index'). Actually I saw that eliminating 'index'
field isn't such a good idea after all. I'll make a patch which
doesn't eliminate it. If we keep 'index' we can remove 'data' field
which causes unstraightforward handling of allocated memory. Keeping
'index' and eliminating 'data' decreases core size for 50 bytes. The
only cost is that not size critical modules may need to re-read
parition info using 'offset' and 'index'
>> -  if (file->device->disk->partition)
>> -    part_start = grub_partition_get_start (file->device->disk->partition);
>> +  part_start = 0;
>> +  for (part = file->device->disk->partition; part; part = part->parent)
>> +    part_start += grub_partition_get_start (part);
>
> Why do you need this change?  Can you explain what this does?

It's because grub_partition_get_start resolves only one level of
partitioning and there may be more than one.

>> diff --git a/include/grub/bsdlabel.h b/include/grub/bsdlabel.h
>> new file mode 100644
>> index 0000000..ba75897
>> --- /dev/null
>> +++ b/include/grub/bsdlabel.h
>> @@ -0,0 +1,91 @@
>> +/*
>> + *  GRUB  --  GRand Unified Bootloader
>> + *  Copyright (C) 1999,2000,2001,2002,2004,2007  Free Software Foundation, Inc.
>
> 2009?

bsdlabel.h is mainly a copy paste from pc_partition.h and I didn't
feel that copyright claim on this move would be justified

>
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>



-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-07-31  9:39     ` Vladimir 'phcoder' Serbinenko
@ 2009-07-31 19:48       ` Vladimir 'phcoder' Serbinenko
  2009-07-31 20:25         ` Vladimir 'phcoder' Serbinenko
  2009-08-02 22:17         ` Robert Millan
  0 siblings, 2 replies; 36+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-07-31 19:48 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 1757 bytes --]

>> What makes this experimental and dangerous?  Can you send in a patch
>> that isn't?
> Only that I touch core size
*core functionality
> and when I submitted it, it was only few
> days old. Now I use it for over a month and haven't hit any problem
> The typical case of the problem it solves is Solaris. When installed
> on x86 its partition is subpartitioned. Because of that current grub
> can't access its filesystem even if it's UFS or even when ZFS module
> is loaded. sun_pc subpartitioning style will be a subject of separate
> patch.

The proble it doesn't solve is when 2 partition labels pretend to
describe the same region. Solaris during install dd'es MBR to its
partition that it subdivides in further paritions. This way the
parition seems to have 2 valid subpartitioning tables. I think the
most sane way to handle this is to introduce partition labels
priority. Fortunately thanks to Bean we have priority-list handling
function so it should increase the size of core for a lot. Numbers
will be available when I test it.
>>> -  if (file->device->disk->partition)
>>> -    part_start = grub_partition_get_start (file->device->disk->partition);
>>> +  part_start = 0;
>>> +  for (part = file->device->disk->partition; part; part = part->parent)
>>> +    part_start += grub_partition_get_start (part);
>>
>> Why do you need this change?  Can you explain what this does?
>
> It's because grub_partition_get_start resolves only one level of
> partitioning and there may be more than one.
>
I changed grub_partition_get_start to resolve all levels and used
->start when I need to resolve just one


-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git

[-- Attachment #2: nestpart.diff --]
[-- Type: text/plain, Size: 60906 bytes --]

diff --git a/ChangeLog b/ChangeLog
index 63daa3a..574227f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,76 @@
+2009-06-08  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	Nested partitions
+
+	* commands/blocklist.c (grub_cmd_blocklist): Don't check whether
+	'partition' is NULL, grub_partition_get_start already does that.
+	* commands/loadenv.c (check_blocklists): Likewise.
+	(write_blocklists): Likewise.
+	* conf/common.rmk (grub_probe_SOURCES): Add partmap/bsdlabel.c.
+	(grub_fstest_SOURCES): Likewise.
+	(pkglib_MODULES): Add bsdlabel.mod.
+	(bsdlabel_mod_SOURCES): New variable.
+	(bsdlabel_mod_CFLAGS): Likewise.
+	(bsdlabel_mod_LDFLAGS): Likewise.
+	* conf/i386-coreboot.rmk (grub_emu_SOURCES): Add partmap/bsdlabel.c.
+	* conf/i386-pc.rmk (grub_setup_SOURCES): Likewise.
+	(grub_emu_SOURCES): Likewise.
+	* conf/powerpc-ieee1275.rmk (grub_emu_SOURCES): Likewise.
+	* conf/sparc64-ieee1275.rmk (grub_emu_SOURCES): Likewise.
+	* include/grub/bsdlabel.h: New file.
+	* include/grub/partition.h (grub_partition_map): Remove 'probe' and
+	'get_name'.
+	(grub_partition): Add 'parent' and 'number'.
+	(grub_partition_get_start): Handle nested partitions.
+	* include/grub/pc_partition.h: Remove bsd-related entries.
+	(grub_pc_partition): Remove.
+	* kern/disk.c (grub_disk_close): Free partition data.
+	(grub_disk_adjust_range): Handle nested partitions.
+	* kern/partition.c (grub_partition_map_probe): New function.
+	(grub_partition_probe): Parse name to number, handle subpartitions.
+	(get_partmap): New function.
+	(grub_partition_iterate): Handle subpartitions.
+	(grub_partition_get_name): Likewise.
+	* loader/i386/pc/bsd.c (grub_bsd_get_device): Likewise.
+	* loader/i386/multiboot.c (grub_multiboot_get_bootdev): Likewise.
+	* loader/i386/pc/chainloader.c (grub_chainloader_cmd): Likewise.
+	* partmap/acorn.c (acorn_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	(acorn_partition_map_probe): Remove.
+	(acorn_partition_map_get_name): Likewise.
+	* partmap/amiga.c (amiga_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Set 'index' to 0 since there can be only one partition entry per sector.
+	(amiga_partition_map_probe): Remove.
+	(amiga_partition_map_get_name): Likewise.
+	* partmap/apple.c (apple_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Set 'offset' and 'index' to real positions of partitions.
+	(apple_partition_map_probe): Remove.
+	(apple_partition_map_get_name): Likewise.
+	* partmap/bsdlabel.c: New file.
+	* partmap/gpt.c (gpt_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Allocate 'data' so it can be correctly freed.
+	Set 'index' to offset inside sector.
+	(gpt_partition_map_probe): Remove.
+	(gpt_partition_map_get_name): Likewise.
+	* partmap/pc.c (grub_partition_parse): Remove.
+	(pc_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Make 'ext_offset' a local variable.
+	(pc_partition_map_probe): Remove.
+	(pc_partition_map_get_name): Remove.
+	* partmap/sun.c (sun_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	(sun_partition_map_probe): Remove.
+	(sun_partition_map_get_name): Likewise.
+	* parttool/pcpart.c (grub_pcpart_boot): Handle nested partitions.
+	(grub_pcpart_type): Likewise.
+	* util/hostdisk.c (open_device): Handle new numbering scheme.
+	(grub_util_biosdisk_get_grub_dev): Handle nested partitions.
+	* util/i386/pc/grub-setup.c (setup): Handle new numbering scheme.
+
 2009-07-31  Vladimir Serbinenko  <phcoder@gmail.com>
 
 	* commands/hexdump.c (grub_cmd_hexdump): Use grub_disk_read instead
diff --git a/commands/blocklist.c b/commands/blocklist.c
index b457b7c..6cc7d69 100644
--- a/commands/blocklist.c
+++ b/commands/blocklist.c
@@ -89,8 +89,7 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)),
     return grub_error (GRUB_ERR_BAD_DEVICE,
 		       "this command is available only for disk devices.");
 
-  if (file->device->disk->partition)
-    part_start = grub_partition_get_start (file->device->disk->partition);
+  part_start = grub_partition_get_start (file->device->disk->partition);
 
   file->read_hook = read_blocklist;
 
diff --git a/commands/loadenv.c b/commands/loadenv.c
index 22665f9..51cffd3 100644
--- a/commands/loadenv.c
+++ b/commands/loadenv.c
@@ -236,10 +236,8 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
   /* One more sanity check. Re-read all sectors by blocklists, and compare
      those with the data read via a file.  */
   disk = file->device->disk;
-  if (disk->partition)
-    part_start = grub_partition_get_start (disk->partition);
-  else
-    part_start = 0;
+
+  part_start = grub_partition_get_start (disk->partition);
 
   buf = grub_envblk_buffer (envblk);
   for (p = blocklists, index = 0; p; p = p->next, index += p->length)
@@ -272,10 +270,7 @@ write_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
 
   buf = grub_envblk_buffer (envblk);
   disk = file->device->disk;
-  if (disk->partition)
-    part_start = grub_partition_get_start (disk->partition);
-  else
-    part_start = 0;
+  part_start = grub_partition_get_start (disk->partition);
 
   index = 0;
   for (p = blocklists; p; p = p->next, index += p->length)
diff --git a/conf/common.rmk b/conf/common.rmk
index 032517f..dbbf38f 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -19,7 +19,8 @@ grub_probe_SOURCES = util/grub-probe.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c		\
 	\
-	partmap/pc.c partmap/apple.c partmap/sun.c partmap/gpt.c\
+	partmap/pc.c partmap/bsdlabel.c partmap/apple.c \
+	partmap/sun.c partmap/gpt.c\
 	kern/fs.c kern/env.c fs/fshelp.c			\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c grub_probe_init.c
 
@@ -40,8 +41,8 @@ grub_fstest_SOURCES = util/grub-fstest.c util/hostfs.c util/misc.c 	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c			\
 	fs/ufs.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c			\
 	\
-	kern/partition.c partmap/pc.c partmap/apple.c partmap/sun.c	\
-	partmap/gpt.c							\
+	kern/partition.c partmap/pc.c partmap/bsdlabel.c partmap/apple.c\
+	partmap/sun.c partmap/gpt.c					\
 	kern/fs.c kern/env.c fs/fshelp.c disk/raid.c			\
 	disk/raid5_recover.c disk/raid6_recover.c 			\
 	disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c 		\
@@ -280,7 +281,8 @@ befs_mod_CFLAGS = $(COMMON_CFLAGS)
 befs_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # Partition maps.
-pkglib_MODULES += amiga.mod apple.mod pc.mod sun.mod acorn.mod gpt.mod
+pkglib_MODULES += amiga.mod apple.mod pc.mod sun.mod acorn.mod gpt.mod \
+		  bsdlabel.mod
 
 # For amiga.mod
 amiga_mod_SOURCES = partmap/amiga.c
@@ -297,6 +299,11 @@ pc_mod_SOURCES = partmap/pc.c
 pc_mod_CFLAGS = $(COMMON_CFLAGS)
 pc_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For pc.mod
+bsdlabel_mod_SOURCES = partmap/bsdlabel.c
+bsdlabel_mod_CFLAGS = $(COMMON_CFLAGS)
+bsdlabel_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For sun.mod
 sun_mod_SOURCES = partmap/sun.c
 sun_mod_CFLAGS = $(COMMON_CFLAGS)
diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk
index 7ba5737..252f6e1 100644
--- a/conf/i386-coreboot.rmk
+++ b/conf/i386-coreboot.rmk
@@ -134,8 +134,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c       \
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c          \
-	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/bsdlabel.c \
+	partmap/sun.c partmap/acorn.c partmap/gpt.c			\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk
index 0321979..cd31408 100644
--- a/conf/i386-ieee1275.rmk
+++ b/conf/i386-ieee1275.rmk
@@ -88,8 +88,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c		\
-	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/bsdlabel.c \
+	partmap/sun.c partmap/acorn.c partmap/gpt.c			\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index 798aee2..c213bfd 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -106,7 +106,7 @@ grub_setup_SOURCES = util/i386/pc/grub-setup.c util/hostdisk.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c			\
 	\
-	partmap/pc.c partmap/gpt.c				\
+	partmap/pc.c partmap/bsdlabel.c partmap/gpt.c		\
 	\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
 	util/raid.c util/lvm.c					\
@@ -142,8 +142,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/menu_text.c						\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c		\
-	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/bsdlabel.c partmap/pc.c \
+	partmap/sun.c partmap/acorn.c partmap/gpt.c			\
 	\
 	fs/affs.c fs/cpio.c  fs/fat.c fs/ext2.c fs/hfs.c		\
 	fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c		\
diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk
index af29d23..5a1e837 100644
--- a/conf/powerpc-ieee1275.rmk
+++ b/conf/powerpc-ieee1275.rmk
@@ -69,8 +69,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c 	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c				\
-	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
-	partmap/acorn.c							\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/bsdlabel.c \
+	partmap/sun.c partmap/acorn.c					\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk
index aabccee..7d7e6d2 100644
--- a/conf/sparc64-ieee1275.rmk
+++ b/conf/sparc64-ieee1275.rmk
@@ -80,8 +80,8 @@ grub_setup_SOURCES = util/sparc64/ieee1275/grub-setup.c util/hostdisk.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c			\
 	\
-	partmap/amiga.c	partmap/apple.c partmap/pc.c		\
-	partmap/sun.c partmap/acorn.c				\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c 		\
+	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c	\
 	\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
 	util/raid.c util/lvm.c					\
diff --git a/include/grub/bsdlabel.h b/include/grub/bsdlabel.h
new file mode 100644
index 0000000..ba75897
--- /dev/null
+++ b/include/grub/bsdlabel.h
@@ -0,0 +1,91 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2004,2007  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_BSDLABEL_PARTITION_HEADER
+#define GRUB_BSDLABEL_PARTITION_HEADER	1
+
+/* Constants for BSD disk label.  */
+#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR	1
+#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC	0x82564557
+#define GRUB_PC_PARTITION_BSD_MAX_ENTRIES	8
+
+/* BSD partition types.  */
+#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED	0
+#define GRUB_PC_PARTITION_BSD_TYPE_SWAP		1
+#define GRUB_PC_PARTITION_BSD_TYPE_V6		2
+#define GRUB_PC_PARTITION_BSD_TYPE_V7		3
+#define GRUB_PC_PARTITION_BSD_TYPE_SYSV		4
+#define GRUB_PC_PARTITION_BSD_TYPE_V71K		5
+#define GRUB_PC_PARTITION_BSD_TYPE_V8		6
+#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS	7
+#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS	8
+#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS	9
+#define GRUB_PC_PARTITION_BSD_TYPE_OTHER	10
+#define GRUB_PC_PARTITION_BSD_TYPE_HPFS		11
+#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660	12
+#define GRUB_PC_PARTITION_BSD_TYPE_BOOT		13
+
+/* FreeBSD-specific types.  */
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM	14
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID	15
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2	21
+
+/* NetBSD-specific types.  */
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_ADOS	14
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_HFS	15
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE	16
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS	17
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_NTFS	18
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_RAID	19
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_CCD	20
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_JFS2	21
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS	22
+
+/* OpenBSD-specific types.  */
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS	14
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_HFS	15
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE	16
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS	17
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS	18
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_RAID	19
+
+/* The BSD partition entry.  */
+struct grub_pc_partition_bsd_entry
+{
+  grub_uint32_t size;
+  grub_uint32_t offset;
+  grub_uint32_t fragment_size;
+  grub_uint8_t fs_type;
+  grub_uint8_t fs_fragments;
+  grub_uint16_t fs_cylinders;
+} __attribute__ ((packed));
+
+/* The BSD disk label. Only define members useful for GRUB.  */
+struct grub_pc_partition_disk_label
+{
+  grub_uint32_t magic;
+  grub_uint8_t padding[128];
+  grub_uint32_t magic2;
+  grub_uint16_t checksum;
+  grub_uint16_t num_partitions;
+  grub_uint32_t boot_size;
+  grub_uint32_t superblock_size;
+  struct grub_pc_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES];
+} __attribute__ ((packed));
+
+#endif /* ! GRUB_PC_PARTITION_HEADER */
diff --git a/include/grub/partition.h b/include/grub/partition.h
index 37c5f24..1c4ba31 100644
--- a/include/grub/partition.h
+++ b/include/grub/partition.h
@@ -36,13 +36,6 @@ struct grub_partition_map
 			 int (*hook) (struct grub_disk *disk,
 				      const grub_partition_t partition));
 
-  /* Return the partition named STR on the disk DISK.  */
-  grub_partition_t (*probe) (struct grub_disk *disk,
-			     const char *str);
-
-  /* Return the name of the partition PARTITION.  */
-  char *(*get_name) (const grub_partition_t partition);
-
   /* The next partition map type.  */
   struct grub_partition_map *next;
 };
@@ -51,6 +44,9 @@ typedef struct grub_partition_map *grub_partition_map_t;
 /* Partition description.  */
 struct grub_partition
 {
+  /* The partition number.  */
+  int number;
+
   /* The start sector.  */
   grub_disk_addr_t start;
 
@@ -66,6 +62,9 @@ struct grub_partition
   /* Partition map type specific data.  */
   void *data;
 
+  /* Parent partition map.  */
+  struct grub_partition *parent;
+
   /* The type partition map.  */
   grub_partition_map_t partmap;
 };
@@ -101,7 +100,13 @@ void grub_apple_partition_map_fini (void);
 static inline grub_disk_addr_t
 grub_partition_get_start (const grub_partition_t p)
 {
-  return p->start;
+  grub_partition_t part;
+  grub_uint64_t part_start = 0;
+
+  for (part = p; part; part = part->parent)
+    part_start += part->start;
+
+  return part_start;
 }
 
 static inline grub_uint64_t
diff --git a/include/grub/pc_partition.h b/include/grub/pc_partition.h
index 67c312e..0b081ed 100644
--- a/include/grub/pc_partition.h
+++ b/include/grub/pc_partition.h
@@ -53,75 +53,6 @@
 #define GRUB_PC_PARTITION_TYPE_GPT_DISK		0xee
 #define GRUB_PC_PARTITION_TYPE_LINUX_RAID	0xfd
 
-/* Constants for BSD disk label.  */
-#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR	1
-#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC	0x82564557
-#define GRUB_PC_PARTITION_BSD_MAX_ENTRIES	8
-
-/* BSD partition types.  */
-#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED	0
-#define GRUB_PC_PARTITION_BSD_TYPE_SWAP		1
-#define GRUB_PC_PARTITION_BSD_TYPE_V6		2
-#define GRUB_PC_PARTITION_BSD_TYPE_V7		3
-#define GRUB_PC_PARTITION_BSD_TYPE_SYSV		4
-#define GRUB_PC_PARTITION_BSD_TYPE_V71K		5
-#define GRUB_PC_PARTITION_BSD_TYPE_V8		6
-#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS	7
-#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS	8
-#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS	9
-#define GRUB_PC_PARTITION_BSD_TYPE_OTHER	10
-#define GRUB_PC_PARTITION_BSD_TYPE_HPFS		11
-#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660	12
-#define GRUB_PC_PARTITION_BSD_TYPE_BOOT		13
-
-/* FreeBSD-specific types.  */
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM	14
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID	15
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2	21
-
-/* NetBSD-specific types.  */
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_ADOS	14
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_HFS	15
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE	16
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS	17
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_NTFS	18
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_RAID	19
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_CCD	20
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_JFS2	21
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS	22
-
-/* OpenBSD-specific types.  */
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS	14
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_HFS	15
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE	16
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS	17
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS	18
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_RAID	19
-
-/* The BSD partition entry.  */
-struct grub_pc_partition_bsd_entry
-{
-  grub_uint32_t size;
-  grub_uint32_t offset;
-  grub_uint32_t fragment_size;
-  grub_uint8_t fs_type;
-  grub_uint8_t fs_fragments;
-  grub_uint16_t fs_cylinders;
-} __attribute__ ((packed));
-
-/* The BSD disk label. Only define members useful for GRUB.  */
-struct grub_pc_partition_disk_label
-{
-  grub_uint32_t magic;
-  grub_uint8_t padding[128];
-  grub_uint32_t magic2;
-  grub_uint16_t checksum;
-  grub_uint16_t num_partitions;
-  grub_uint32_t boot_size;
-  grub_uint32_t superblock_size;
-  struct grub_pc_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES];
-} __attribute__ ((packed));
-
 /* The partition entry.  */
 struct grub_pc_partition_entry
 {
@@ -168,23 +99,6 @@ struct grub_pc_partition_mbr
 } __attribute__ ((packed));
 
 \f
-struct grub_pc_partition
-{
-    /* The DOS partition number.  */
-  int dos_part;
-
-  /* The BSD partition number (a == 0).  */
-  int bsd_part;
-
-  /* The DOS partition type.  */
-  int dos_type;
-
-  /* The BSD partition type.  */
-  int bsd_type;
-
-  /* The offset of the extended partition.  */
-  unsigned long ext_offset;
-};
 
 static inline int
 grub_pc_partition_is_empty (int type)
@@ -200,12 +114,4 @@ grub_pc_partition_is_extended (int type)
 	  || type == GRUB_PC_PARTITION_TYPE_LINUX_EXTENDED);
 }
 
-static inline int
-grub_pc_partition_is_bsd (int type)
-{
-  return (type == GRUB_PC_PARTITION_TYPE_FREEBSD
-	  || type == GRUB_PC_PARTITION_TYPE_OPENBSD
-	  || type == GRUB_PC_PARTITION_TYPE_NETBSD);
-}
-
 #endif /* ! GRUB_PC_PARTITION_HEADER */
diff --git a/kern/disk.c b/kern/disk.c
index e463626..657ac8d 100644
--- a/kern/disk.c
+++ b/kern/disk.c
@@ -330,6 +330,7 @@ grub_disk_open (const char *name)
 void
 grub_disk_close (grub_disk_t disk)
 {
+  grub_partition_t part;
   grub_dprintf ("disk", "Closing `%s'.\n", disk->name);
 
   if (disk->dev && disk->dev->close)
@@ -338,7 +339,13 @@ grub_disk_close (grub_disk_t disk)
   /* Reset the timer.  */
   grub_last_time = grub_get_time_ms ();
 
-  grub_free (disk->partition);
+  while (disk->partition)
+    {
+      part = disk->partition->parent;
+      grub_free (disk->partition->data);
+      grub_free (disk->partition);
+      disk->partition = part;
+    }
   grub_free ((void *) disk->name);
   grub_free (disk);
 }
@@ -349,18 +356,19 @@ grub_disk_close (grub_disk_t disk)
    - Verify that the range is inside the partition.  */
 static grub_err_t
 grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
-		       grub_off_t *offset, grub_size_t size)
+			grub_off_t *offset, grub_size_t size)
 {
+  grub_partition_t part;
   *sector += *offset >> GRUB_DISK_SECTOR_BITS;
   *offset &= GRUB_DISK_SECTOR_SIZE - 1;
 
-  if (disk->partition)
+  for (part = disk->partition; part; part = part->parent)
     {
       grub_disk_addr_t start;
       grub_uint64_t len;
 
-      start = grub_partition_get_start (disk->partition);
-      len = grub_partition_get_len (disk->partition);
+      start = part->start;
+      len = part->len;
 
       if (*sector >= len
 	  || len - *sector < ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
diff --git a/kern/partition.c b/kern/partition.c
index 4d5c63a..4bcd8c7 100644
--- a/kern/partition.c
+++ b/kern/partition.c
@@ -17,6 +17,7 @@
  */
 
 #include <grub/misc.h>
+#include <grub/mm.h>
 #include <grub/partition.h>
 #include <grub/disk.h>
 
@@ -54,17 +55,58 @@ grub_partition_map_iterate (int (*hook) (const grub_partition_map_t partmap))
   return 0;
 }
 
+static grub_partition_t
+grub_partition_map_probe (const grub_partition_map_t partmap,
+			  grub_disk_t disk, int partnum)
+{
+  grub_partition_t p = 0;
+
+  auto int find_func (grub_disk_t d, const grub_partition_t partition);
+
+  int find_func (grub_disk_t d __attribute__ ((unused)),
+		 const grub_partition_t partition)
+    {
+      if (partnum == partition->number)
+	{
+	  p = (grub_partition_t) grub_malloc (sizeof (*p));
+	  if (! p)
+	    return 1;
+
+	  grub_memcpy (p, partition, sizeof (*p));
+	  return 1;
+	}
+
+      return 0;
+    }
+
+  partmap->iterate (disk, find_func);
+  if (grub_errno)
+    goto fail;
+
+  return p;
+
+ fail:
+  grub_free (p);
+  return 0;
+}
+
 grub_partition_t
 grub_partition_probe (struct grub_disk *disk, const char *str)
 {
   grub_partition_t part = 0;
+  grub_partition_t curpart = 0;
+  grub_partition_t tail;
+  const char *ptr;
+  int num;
 
   auto int part_map_probe (const grub_partition_map_t partmap);
 
   int part_map_probe (const grub_partition_map_t partmap)
     {
-      part = partmap->probe (disk, str);
-      if (part)
+      disk->partition = part;
+      curpart = grub_partition_map_probe (partmap, disk, num);
+      disk->partition = tail;
+      if (curpart)
 	return 1;
 
       if (grub_errno == GRUB_ERR_BAD_PART_TABLE)
@@ -77,27 +119,54 @@ grub_partition_probe (struct grub_disk *disk, const char *str)
       return 1;
     }
 
-  /* Use the first partition map type found.  */
-  grub_partition_map_iterate (part_map_probe);
+  part = tail = disk->partition;
+
+  for (ptr = str; *ptr;)
+    {
+      /* BSD-like partition specification.  */
+      if (*ptr >= 'a' && *ptr <= 'z')
+	num = *(ptr++) - 'a';
+      else
+	num = grub_strtoul (ptr, (char **) &ptr, 0) - 1;
+
+      curpart = 0;
+      /* Use the first partition map type found.  */
+      grub_partition_map_iterate (part_map_probe);
+
+      if (! curpart)
+	{
+	  while (part)
+	    {
+	      curpart = part->parent;
+	      grub_free (part);
+	      part = curpart;
+	    }
+	  return 0;
+	}
+      curpart->parent = part;
+      part = curpart;
+      if (! ptr || *ptr != ',')
+	break;
+      ptr++;
+    }
 
   return part;
 }
 
-int
-grub_partition_iterate (struct grub_disk *disk,
-			int (*hook) (grub_disk_t disk,
-				     const grub_partition_t partition))
+static grub_partition_map_t
+get_partmap (struct grub_disk *disk)
 {
   grub_partition_map_t partmap = 0;
-  int ret = 0;
-
+  struct grub_partition part;
+  int found = 0;
   auto int part_map_iterate (const grub_partition_map_t p);
   auto int part_map_iterate_hook (grub_disk_t d,
 				  const grub_partition_t partition);
-
   int part_map_iterate_hook (grub_disk_t d __attribute__ ((unused)),
-			     const grub_partition_t partition __attribute__ ((unused)))
+			     const grub_partition_t partition)
     {
+      found = 1;
+      part = *partition;
       return 1;
     }
 
@@ -106,22 +175,58 @@ grub_partition_iterate (struct grub_disk *disk,
       grub_dprintf ("partition", "Detecting %s...\n", p->name);
       p->iterate (disk, part_map_iterate_hook);
 
-      if (grub_errno != GRUB_ERR_NONE)
+      if (grub_errno != GRUB_ERR_NONE || ! found)
 	{
 	  /* Continue to next partition map type.  */
 	  grub_dprintf ("partition", "%s detection failed.\n", p->name);
 	  grub_errno = GRUB_ERR_NONE;
 	  return 0;
 	}
+      grub_free (part.data);
 
       grub_dprintf ("partition", "%s detection succeeded.\n", p->name);
       partmap = p;
       return 1;
     }
-
   grub_partition_map_iterate (part_map_iterate);
-  if (partmap)
-    ret = partmap->iterate (disk, hook);
+  return partmap;
+}
+
+int
+grub_partition_iterate (struct grub_disk *disk,
+			int (*hook) (grub_disk_t disk,
+				     const grub_partition_t partition))
+{
+  int ret = 0;
+
+  auto int part_iterate (grub_disk_t dsk, const grub_partition_t p);
+
+  int part_iterate (grub_disk_t dsk,
+		    const grub_partition_t partition)
+    {
+      struct grub_partition p = *partition;
+      grub_partition_map_t partmap = 0;
+      p.parent = dsk->partition;
+      dsk->partition = 0;
+      if (hook (dsk, &p))
+	  return 1;
+      if (p.start != 0)
+	{
+	  dsk->partition = &p;
+	  partmap = get_partmap (dsk);
+	  if (partmap)
+	    ret = partmap->iterate (dsk, part_iterate);
+	}
+      dsk->partition = p.parent;
+      return ret;
+    }
+
+  {
+    grub_partition_map_t partmap = 0;
+    partmap = get_partmap (disk);
+    if (partmap)
+      ret = partmap->iterate (disk, part_iterate);
+  }
 
   return ret;
 }
@@ -129,5 +234,30 @@ grub_partition_iterate (struct grub_disk *disk,
 char *
 grub_partition_get_name (const grub_partition_t partition)
 {
-  return partition->partmap->get_name (partition);
+  char *out = 0;
+  /* Even on 64-bit machines this buffer is enough to hold longest number.  */
+  char buf[25];
+  int curlen = 0;
+  grub_partition_t part;
+  for (part = partition; part; part = part->parent)
+    {
+      int strl;
+      grub_sprintf (buf, "%d", part->number + 1);
+      strl = grub_strlen (buf);
+      if (curlen)
+	{
+	  out = grub_realloc (out, curlen + strl + 2);
+	  grub_memcpy (out + strl + 1, out, curlen);
+	  out[curlen + 1 + strl] = 0;
+	  grub_memcpy (out, buf, strl);
+	  out[strl] = ',';
+	  curlen = curlen + 1 + strl;
+	}
+      else
+	{
+	  curlen = strl;
+	  out = grub_strdup (buf);
+	}
+    }
+  return out;
 }
diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c
index 468e6d0..d9135b2 100644
--- a/loader/i386/bsd.c
+++ b/loader/i386/bsd.c
@@ -86,7 +86,6 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
 		     grub_uint32_t * unit,
 		     grub_uint32_t * slice, grub_uint32_t * part)
 {
-  char *p;
   grub_device_t dev; 
 
   *biosdev = grub_get_root_biosnumber () & 0xff;
@@ -96,21 +95,13 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-
-      p = dev->disk->partition->partmap->get_name (dev->disk->partition);
-      if (p)
+      if (dev->disk->partition->parent)
 	{
-	  if ((p[0] >= '0') && (p[0] <= '9'))
-	    {
-	      *slice = grub_strtoul (p, &p, 0);
-
-	      if ((p) && (p[0] == ','))
-		p++;
-	    }
-
-	  if ((p[0] >= 'a') && (p[0] <= 'z'))
-	    *part = p[0] - 'a';
+	  *part = dev->disk->partition->number;
+	  *slice = dev->disk->partition->parent->number + 1;
 	}
+      else
+	*slice = dev->disk->partition->number + 1;
     }
   if (dev)
     grub_device_close (dev);
diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c
index 87ffcae..cbb07bb 100644
--- a/loader/i386/multiboot.c
+++ b/loader/i386/multiboot.c
@@ -155,7 +155,6 @@ static int
 grub_multiboot_get_bootdev (grub_uint32_t *bootdev)
 {
 #ifdef GRUB_MACHINE_PCBIOS
-  char *p;
   grub_uint32_t biosdev, slice = ~0, part = ~0;
   grub_device_t dev;
 
@@ -164,21 +163,13 @@ grub_multiboot_get_bootdev (grub_uint32_t *bootdev)
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-
-      p = dev->disk->partition->partmap->get_name (dev->disk->partition);
-      if (p)
+      if (dev->disk->partition->parent)
 	{
-	  if ((p[0] >= '0') && (p[0] <= '9'))
-	    {
-	      slice = grub_strtoul (p, &p, 0) - 1;
-
-	      if ((p) && (p[0] == ','))
-		p++;
-	    }
-
-	  if ((p[0] >= 'a') && (p[0] <= 'z'))
-	    part = p[0] - 'a';
+	  part = dev->disk->partition->number;
+	  slice = dev->disk->partition->parent->number;
 	}
+      else
+	slice = dev->disk->partition->number;
     }
   if (dev)
     grub_device_close (dev);
diff --git a/loader/i386/pc/chainloader.c b/loader/i386/pc/chainloader.c
index caf1450..925163e 100644
--- a/loader/i386/pc/chainloader.c
+++ b/loader/i386/pc/chainloader.c
@@ -31,6 +31,7 @@
 #include <grub/machine/memory.h>
 #include <grub/dl.h>
 #include <grub/command.h>
+#include <grub/pc_partition.h>
 #include <grub/machine/biosnum.h>
 
 static grub_dl_t my_mod;
@@ -94,10 +95,25 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-      grub_disk_read (dev->disk, dev->disk->partition->offset, 446, 64,
-		      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
-      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
-			    + (dev->disk->partition->index << 4));
+      grub_disk_t disk = dev->disk;
+
+      if (disk)
+	{
+	  grub_partition_t p = disk->partition;
+
+	  /* In i386-pc, the id is equal to the BIOS drive number.  */
+	  drive = (int) disk->id;
+
+	  if (p && grub_strcmp (p->partmap->name, "pc_partition_map") == 0)
+	    {
+	      disk->partition = p->parent;
+	      grub_disk_read (disk, p->offset, 446, 64,
+			      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
+	      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
+				    + (p->index << 4));
+	      disk->partition = p;
+	    }
+	}
     }
 
   if (dev)
diff --git a/partmap/acorn.c b/partmap/acorn.c
index 42fd61f..8443554 100644
--- a/partmap/acorn.c
+++ b/partmap/acorn.c
@@ -96,21 +96,17 @@ acorn_partition_map_iterate (grub_disk_t disk,
 					  const grub_partition_t partition))
 {
   struct grub_partition part;
-  struct grub_disk raw;
   struct linux_part map[LINUX_MAP_ENTRIES];
   int i;
-  grub_disk_addr_t sector;
+  grub_disk_addr_t sector = 0;
   grub_err_t err;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
-  err = acorn_partition_map_find (&raw, map, &sector);
+  err = acorn_partition_map_find (disk, map, &sector);
   if (err)
     return err;
 
   part.partmap = &grub_acorn_partition_map;
+  part.data = 0;
 
   for (i = 0; i != LINUX_MAP_ENTRIES; ++i)
     {
@@ -121,7 +117,7 @@ acorn_partition_map_iterate (grub_disk_t disk,
       part.start = sector + map[i].start;
       part.len = map[i].size;
       part.offset = 6;
-      part.index = i;
+      part.number = part.index = i;
 
       if (hook (disk, &part))
 	return grub_errno;
@@ -130,60 +126,6 @@ acorn_partition_map_iterate (grub_disk_t disk,
   return GRUB_ERR_NONE;
 }
 
-
-static grub_partition_t
-acorn_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  struct linux_part map[LINUX_MAP_ENTRIES];
-  struct grub_disk raw = *disk;
-  unsigned long partnum = grub_strtoul (str, 0, 10) - 1;
-  grub_disk_addr_t sector;
-  grub_err_t err;
-  grub_partition_t p;
-
-  /* Enforce raw disk access.  */
-  raw.partition = 0;
-
-  /* Get the partition number.  */
-  if (partnum > LINUX_MAP_ENTRIES)
-    goto fail;
-
-  err = acorn_partition_map_find (&raw, map, &sector);
-  if (err)
-    return 0;
-
-  if (map[partnum].magic != LINUX_NATIVE_MAGIC
-      && map[partnum].magic != LINUX_SWAP_MAGIC)
-    goto fail;
-
-  p = grub_malloc (sizeof (struct grub_partition));
-  if (! p)
-    return 0;
-
-  p->start = sector + map[partnum].start;
-  p->len = map[partnum].size;
-  p->offset = 6;
-  p->index = partnum;
-  return p;
-
-fail:
-  grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-  return 0;
-}
-
-
-static char *
-acorn_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
 \f
 
 /* Partition map type.  */
@@ -191,8 +133,6 @@ static struct grub_partition_map grub_acorn_partition_map =
 {
   .name = "Linux/ADFS partition map",
   .iterate = acorn_partition_map_iterate,
-  .probe = acorn_partition_map_probe,
-  .get_name = acorn_partition_map_get_name
 };
 
 GRUB_MOD_INIT(acorn_partition_map)
diff --git a/partmap/amiga.c b/partmap/amiga.c
index ffb807f..90cf525 100644
--- a/partmap/amiga.c
+++ b/partmap/amiga.c
@@ -76,20 +76,15 @@ amiga_partition_map_iterate (grub_disk_t disk,
 {
   struct grub_partition part;
   struct grub_amiga_rdsk rdsk;
-  struct grub_disk raw;
   int partno = 0;
   int next = -1;
   unsigned pos;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   /* The RDSK block is one of the first 15 blocks.  */
   for (pos = 0; pos < 15; pos++)
     {
       /* Read the RDSK block which is a descriptor for the entire disk.  */
-      if (grub_disk_read (&raw, pos, 0, sizeof (rdsk), &rdsk))
+      if (grub_disk_read (disk, pos, 0, sizeof (rdsk), &rdsk))
 	return grub_errno;
 
       if (grub_strcmp ((char *) rdsk.magic, "RDSK") == 0)
@@ -104,13 +99,15 @@ amiga_partition_map_iterate (grub_disk_t disk,
     return grub_error (GRUB_ERR_BAD_PART_TABLE,
 		       "Amiga partition map not found.");
 
+  part.data = 0;
+
   /* The end of the partition list is marked using "-1".  */
   while (next != -1)
     {
       struct grub_amiga_partition apart;
 
       /* Read the RDSK block which is a descriptor for the entire disk.  */
-      if (grub_disk_read (&raw, next, 0, sizeof (apart), &apart))
+      if (grub_disk_read (disk, next, 0, sizeof (apart), &apart))
 	return grub_errno;
 
       /* Calculate the first block and the size of the partition.  */
@@ -123,7 +120,8 @@ amiga_partition_map_iterate (grub_disk_t disk,
 		  * grub_be_to_cpu32 (apart.block_per_track));
 
       part.offset = (grub_off_t) next * 512;
-      part.index = partno;
+      part.number = partno;
+      part.index = 0;
       part.partmap = &grub_amiga_partition_map;
 
       if (hook (disk, &part))
@@ -136,72 +134,12 @@ amiga_partition_map_iterate (grub_disk_t disk,
   return 0;
 }
 
-
-static grub_partition_t
-amiga_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  if (amiga_partition_map_iterate (disk, find_func))
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-amiga_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_amiga_partition_map =
   {
     .name = "amiga_partition_map",
     .iterate = amiga_partition_map_iterate,
-    .probe = amiga_partition_map_probe,
-    .get_name = amiga_partition_map_get_name
   };
 
 GRUB_MOD_INIT(amiga_partition_map)
diff --git a/partmap/apple.c b/partmap/apple.c
index fce2f2c..9929190 100644
--- a/partmap/apple.c
+++ b/partmap/apple.c
@@ -104,17 +104,12 @@ apple_partition_map_iterate (grub_disk_t disk,
   struct grub_partition part;
   struct grub_apple_header aheader;
   struct grub_apple_part apart;
-  struct grub_disk raw;
   int partno = 0;
   unsigned pos = GRUB_DISK_SECTOR_SIZE;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   part.partmap = &grub_apple_partition_map;
 
-  if (grub_disk_read (&raw, 0, 0, sizeof (aheader), &aheader))
+  if (grub_disk_read (disk, 0, 0, sizeof (aheader), &aheader))
     return grub_errno;
 
   if (grub_be_to_cpu16 (aheader.magic) != GRUB_APPLE_HEADER_MAGIC)
@@ -126,12 +121,16 @@ apple_partition_map_iterate (grub_disk_t disk,
       goto fail;
     }
 
+  part.data = 0;
+
   for (;;)
     {
-      if (grub_disk_read (&raw, pos / GRUB_DISK_SECTOR_SIZE,
-			  pos % GRUB_DISK_SECTOR_SIZE,
-			  sizeof (struct grub_apple_part),  &apart))
-	return grub_errno;
+       part.offset = pos / GRUB_DISK_SECTOR_SIZE;
+       part.index = pos % GRUB_DISK_SECTOR_SIZE;
+
+       if (grub_disk_read (disk, part.offset, part.index,
+			   sizeof (struct grub_apple_part),  &apart))
+	 return grub_errno;
 
       if (grub_be_to_cpu16 (apart.magic) != GRUB_APPLE_PART_MAGIC)
 	{
@@ -144,8 +143,7 @@ apple_partition_map_iterate (grub_disk_t disk,
 
       part.start = grub_be_to_cpu32 (apart.first_phys_block);
       part.len = grub_be_to_cpu32 (apart.blockcnt);
-      part.offset = pos;
-      part.index = partno;
+      part.number = partno;
 
       grub_dprintf ("partition",
 		    "partition %d: name %s, type %s, start 0x%x, len 0x%x\n",
@@ -172,72 +170,12 @@ apple_partition_map_iterate (grub_disk_t disk,
 		     "Apple partition map not found.");
 }
 
-
-static grub_partition_t
-apple_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  if (apple_partition_map_iterate (disk, find_func))
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-apple_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_apple_partition_map =
   {
     .name = "apple_partition_map",
     .iterate = apple_partition_map_iterate,
-    .probe = apple_partition_map_probe,
-    .get_name = apple_partition_map_get_name
   };
 
 GRUB_MOD_INIT(apple_partition_map)
diff --git a/partmap/bsdlabel.c b/partmap/bsdlabel.c
new file mode 100644
index 0000000..f376dce
--- /dev/null
+++ b/partmap/bsdlabel.c
@@ -0,0 +1,87 @@
+/* bsdlabel.c - Read BSD style partition tables.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2004,2005,2006,2007,2008,2009  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/partition.h>
+#include <grub/bsdlabel.h>
+#include <grub/disk.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/dl.h>
+
+static struct grub_partition_map grub_bsdlabel_partition_map;
+\f
+
+static grub_err_t
+bsdlabel_partition_map_iterate (grub_disk_t disk,
+			  int (*hook) (grub_disk_t disk,
+				       const grub_partition_t partition))
+{
+  struct grub_pc_partition_disk_label label;
+  struct grub_partition p;
+  grub_disk_addr_t delta = 0;
+
+  /* BSDLabel offsets are absolute even when it's embed inside partition.  */
+  delta = grub_partition_get_start (disk->partition);
+
+  /* Read the BSD label.  */
+  if (grub_disk_read (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR,
+		      0, sizeof (label), &label))
+    goto finish;
+
+  /* Check if it is valid.  */
+  if (label.magic != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
+    return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
+  for (p.number = 0;
+       p.number < grub_cpu_to_le16 (label.num_partitions);
+       p.number++)
+    {
+      struct grub_pc_partition_bsd_entry *be
+	= label.entries + p.number;
+
+      p.start = grub_le_to_cpu32 (be->offset) - delta;
+      p.len = grub_le_to_cpu32 (be->size);
+      p.offset = GRUB_PC_PARTITION_BSD_LABEL_SECTOR;
+      p.partmap = &grub_bsdlabel_partition_map;
+      p.index = p.number;
+
+      if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
+	if (hook (disk, &p))
+	  return 1;
+    }
+ finish:
+  return grub_errno;
+}
+
+\f
+/* Partition map type.  */
+static struct grub_partition_map grub_bsdlabel_partition_map =
+  {
+    .name = "bsdlabel_partition_map",
+    .iterate = bsdlabel_partition_map_iterate,
+  };
+
+GRUB_MOD_INIT(bsdlabel_partition_map)
+{
+  grub_partition_map_register (&grub_bsdlabel_partition_map);
+}
+
+GRUB_MOD_FINI(bsdlabel_partition_map)
+{
+  grub_partition_map_unregister (&grub_bsdlabel_partition_map);
+}
diff --git a/partmap/gpt.c b/partmap/gpt.c
index d646d41..041d6be 100644
--- a/partmap/gpt.c
+++ b/partmap/gpt.c
@@ -44,18 +44,13 @@ gpt_partition_map_iterate (grub_disk_t disk,
   struct grub_partition part;
   struct grub_gpt_header gpt;
   struct grub_gpt_partentry entry;
-  struct grub_disk raw;
   struct grub_pc_partition_mbr mbr;
   grub_uint64_t entries;
   unsigned int i;
   int last_offset = 0;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   /* Read the protective MBR.  */
-  if (grub_disk_read (&raw, 0, 0, sizeof (mbr), &mbr))
+  if (grub_disk_read (disk, 0, 0, sizeof (mbr), &mbr))
     return grub_errno;
 
   /* Check if it is valid.  */
@@ -67,7 +62,7 @@ gpt_partition_map_iterate (grub_disk_t disk,
     return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
 
   /* Read the GPT header.  */
-  if (grub_disk_read (&raw, 1, 0, sizeof (gpt), &gpt))
+  if (grub_disk_read (disk, 1, 0, sizeof (gpt), &gpt))
     return grub_errno;
 
   if (grub_memcmp (gpt.magic, grub_gpt_magic, sizeof (grub_gpt_magic)))
@@ -76,11 +71,15 @@ gpt_partition_map_iterate (grub_disk_t disk,
   grub_dprintf ("gpt", "Read a valid GPT header\n");
 
   entries = grub_le_to_cpu64 (gpt.partitions);
+  part.data = grub_malloc (sizeof (entry));
   for (i = 0; i < grub_le_to_cpu32 (gpt.maxpart); i++)
     {
-      if (grub_disk_read (&raw, entries, last_offset,
+      if (grub_disk_read (disk, entries, last_offset,
 			  sizeof (entry), &entry))
-	return grub_errno;
+	{
+	  grub_free (part.data);
+	  return grub_errno;
+	}
 
       if (grub_memcmp (&grub_gpt_partition_type_empty, &entry.type,
 		       sizeof (grub_gpt_partition_type_empty)))
@@ -90,9 +89,10 @@ gpt_partition_map_iterate (grub_disk_t disk,
 	  part.len = (grub_le_to_cpu64 (entry.end)
 		      - grub_le_to_cpu64 (entry.start) + 1);
 	  part.offset = entries;
-	  part.index = i;
+	  part.number = i;
+	  part.index = last_offset;
 	  part.partmap = &grub_gpt_partition_map;
-	  part.data = &entry;
+	  grub_memcpy (part.data, &entry, sizeof (entry));
 
 	  grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", i,
 			(unsigned long long) part.start,
@@ -109,77 +109,17 @@ gpt_partition_map_iterate (grub_disk_t disk,
 	  entries++;
 	}
     }
+  grub_free (part.data);
 
   return 0;
 }
 
-
-static grub_partition_t
-gpt_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  gpt_partition_map_iterate (disk, find_func);
-  if (grub_errno)
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-gpt_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_gpt_partition_map =
   {
     .name = "gpt_partition_map",
     .iterate = gpt_partition_map_iterate,
-    .probe = gpt_partition_map_probe,
-    .get_name = gpt_partition_map_get_name
   };
 
 GRUB_MOD_INIT(gpt_partition_map)
diff --git a/partmap/pc.c b/partmap/pc.c
index 6a2efd2..cb56c9b 100644
--- a/partmap/pc.c
+++ b/partmap/pc.c
@@ -27,85 +27,19 @@
 static struct grub_partition_map grub_pc_partition_map;
 \f
 
-/* Parse the partition representation in STR and return a partition.  */
-static grub_partition_t
-grub_partition_parse (const char *str)
-{
-  grub_partition_t p;
-  struct grub_pc_partition *pcdata;
-
-  char *s = (char *) str;
-
-  p = (grub_partition_t) grub_malloc (sizeof (*p));
-  if (! p)
-    return 0;
-
-  pcdata = (struct grub_pc_partition *) grub_malloc (sizeof (*pcdata));
-  if (! pcdata)
-    goto fail;
-
-  p->data = pcdata;
-  p->partmap = &grub_pc_partition_map;
-
-  /* Initialize some of the fields with invalid values.  */
-  pcdata->bsd_part = pcdata->dos_type = pcdata->bsd_type = p->index = -1;
-
-  /* Get the DOS partition number. The number is counted from one for
-     the user interface, and from zero internally.  */
-  pcdata->dos_part = grub_strtoul (s, &s, 0) - 1;
-
-  if (grub_errno)
-    {
-      /* Not found. Maybe only a BSD label is specified.  */
-      pcdata->dos_part = -1;
-      grub_errno = GRUB_ERR_NONE;
-    }
-  else if (*s == ',')
-    s++;
-
-  if (*s)
-    {
-      if (*s >= 'a' && *s <= 'h')
-	{
-	  pcdata->bsd_part = *s - 'a';
-	  s++;
-	}
-
-      if (*s)
-	goto fail;
-    }
-
-  if (pcdata->dos_part == -1 && pcdata->bsd_part == -1)
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  grub_free (pcdata);
-  grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-  return 0;
-}
-
 static grub_err_t
 pc_partition_map_iterate (grub_disk_t disk,
 			  int (*hook) (grub_disk_t disk,
 				       const grub_partition_t partition))
 {
   struct grub_partition p;
-  struct grub_pc_partition pcdata;
   struct grub_pc_partition_mbr mbr;
-  struct grub_pc_partition_disk_label label;
-  struct grub_disk raw;
-
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
+  grub_disk_addr_t ext_offset;
 
   p.offset = 0;
-  pcdata.ext_offset = 0;
-  pcdata.dos_part = -1;
-  p.data = &pcdata;
+  ext_offset = 0;
+  p.data = 0;
+  p.number = -1;
   p.partmap = &grub_pc_partition_map;
 
   while (1)
@@ -114,7 +48,7 @@ pc_partition_map_iterate (grub_disk_t disk,
       struct grub_pc_partition_entry *e;
 
       /* Read the MBR.  */
-      if (grub_disk_read (&raw, p.offset, 0, sizeof (mbr), &mbr))
+      if (grub_disk_read (disk, p.offset, 0, sizeof (mbr), &mbr))
 	goto finish;
 
       /* Check if it is valid.  */
@@ -132,13 +66,10 @@ pc_partition_map_iterate (grub_disk_t disk,
 
 	  p.start = p.offset + grub_le_to_cpu32 (e->start);
 	  p.len = grub_le_to_cpu32 (e->length);
-	  pcdata.bsd_part = -1;
-	  pcdata.dos_type = e->type;
-	  pcdata.bsd_type = -1;
 
 	  grub_dprintf ("partition",
 			"partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n",
-			p.index, e->flag, pcdata.dos_type,
+			p.index, e->flag, e->type,
 			(unsigned long long) p.start,
 			(unsigned long long) p.len);
 
@@ -150,59 +81,15 @@ pc_partition_map_iterate (grub_disk_t disk,
 	  if (! grub_pc_partition_is_empty (e->type)
 	      && ! grub_pc_partition_is_extended (e->type))
 	    {
-	      pcdata.dos_part++;
+	      p.number++;
 
 	      if (hook (disk, &p))
 		return 1;
-
-	      /* Check if this is a BSD partition.  */
-	      if (grub_pc_partition_is_bsd (e->type))
-		{
-		  /* Check if the BSD label is within the DOS partition.  */
-		  if (p.len <= GRUB_PC_PARTITION_BSD_LABEL_SECTOR)
-		    {
-		      grub_dprintf ("partition", "no space for disk label\n");
-		      continue;
-		    }
-		  /* Read the BSD label.  */
-		  if (grub_disk_read (&raw,
-				      (p.start
-				       + GRUB_PC_PARTITION_BSD_LABEL_SECTOR),
-				      0,
-				      sizeof (label),
-				      &label))
-		    goto finish;
-
-		  /* Check if it is valid.  */
-		  if (label.magic
-		      != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
-		    {
-		      grub_dprintf ("partition",
-				    "invalid disk label magic 0x%x on partition %d\n",
-				    label.magic, p.index);
-		      continue;
-		    }
-		  for (pcdata.bsd_part = 0;
-		       pcdata.bsd_part < grub_cpu_to_le16 (label.num_partitions);
-		       pcdata.bsd_part++)
-		    {
-		      struct grub_pc_partition_bsd_entry *be
-			= label.entries + pcdata.bsd_part;
-
-		      p.start = grub_le_to_cpu32 (be->offset);
-		      p.len = grub_le_to_cpu32 (be->size);
-		      pcdata.bsd_type = be->fs_type;
-
-		      if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
-			if (hook (disk, &p))
-			  return 1;
-		    }
-		}
 	    }
-	  else if (pcdata.dos_part < 4)
+	  else if (p.number < 4)
 	    /* If this partition is a logical one, shouldn't increase the
 	       partition number.  */
-	    pcdata.dos_part++;
+	    p.number++;
 	}
 
       /* Find an extended partition.  */
@@ -212,9 +99,9 @@ pc_partition_map_iterate (grub_disk_t disk,
 
 	  if (grub_pc_partition_is_extended (e->type))
 	    {
-	      p.offset = pcdata.ext_offset + grub_le_to_cpu32 (e->start);
-	      if (! pcdata.ext_offset)
-		pcdata.ext_offset = p.offset;
+	      p.offset = ext_offset + grub_le_to_cpu32 (e->start);
+	      if (! ext_offset)
+		ext_offset = p.offset;
 
 	      break;
 	    }
@@ -229,84 +116,12 @@ pc_partition_map_iterate (grub_disk_t disk,
   return grub_errno;
 }
 
-
-static grub_partition_t
-pc_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p;
-  struct grub_pc_partition *pcdata;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      struct grub_pc_partition *partdata = partition->data;
-
-      if ((pcdata->dos_part == partdata->dos_part || pcdata->dos_part == -1)
-	  && pcdata->bsd_part == partdata->bsd_part)
-	{
-	  grub_memcpy (p, partition, sizeof (*p));
-	  p->data = pcdata;
-	  grub_memcpy (pcdata, partdata, sizeof (*pcdata));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  p = grub_partition_parse (str);
-  if (! p)
-    return 0;
-
-  pcdata = p->data;
-  pc_partition_map_iterate (disk, find_func);
-  if (grub_errno)
-    goto fail;
-
-  if (p->index < 0)
-    {
-      grub_error (GRUB_ERR_BAD_DEVICE, "no such partition");
-      goto fail;
-    }
-
-  return p;
-
- fail:
-  grub_free (p);
-  grub_free (pcdata);
-  return 0;
-}
-
-
-static char *
-pc_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-  struct grub_pc_partition *pcdata = p->data;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  if (pcdata->bsd_part < 0)
-    grub_sprintf (name, "%d", pcdata->dos_part + 1);
-  else if (pcdata->dos_part < 0)
-    grub_sprintf (name, "%c", pcdata->bsd_part + 'a');
-  else
-    grub_sprintf (name, "%d,%c", pcdata->dos_part + 1, pcdata->bsd_part + 'a');
-
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_pc_partition_map =
   {
     .name = "pc_partition_map",
     .iterate = pc_partition_map_iterate,
-    .probe = pc_partition_map_probe,
-    .get_name = pc_partition_map_get_name
   };
 
 GRUB_MOD_INIT(pc_partition_map)
diff --git a/partmap/sun.c b/partmap/sun.c
index ce6d588..63ba6ae 100644
--- a/partmap/sun.c
+++ b/partmap/sun.c
@@ -88,19 +88,15 @@ sun_partition_map_iterate (grub_disk_t disk,
 					const grub_partition_t partition))
 {
   grub_partition_t p;
-  struct grub_disk raw;
   struct grub_sun_block block;
   int partnum;
 
-  raw = *disk;
-  raw.partition = 0;
-
   p = (grub_partition_t) grub_zalloc (sizeof (struct grub_partition));
   if (! p)
     return grub_errno;
 
   p->partmap = &grub_sun_partition_map;
-  if (grub_disk_read (&raw, 0, 0, sizeof (struct grub_sun_block),
+  if (grub_disk_read (disk, 0, 0, sizeof (struct grub_sun_block),
 		      &block) == GRUB_ERR_NONE)
     {
       if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.magic))
@@ -124,7 +120,7 @@ sun_partition_map_iterate (grub_disk_t disk,
 		      * grub_be_to_cpu16 (block.ntrks)
 		      * grub_be_to_cpu16 (block.nsect));
 	  p->len = grub_be_to_cpu32 (desc->num_sectors);
-	  p->index = partnum;
+	  p->number = p->index = partnum;
 	  if (p->len)
 	    {
 	      if (hook (disk, p))
@@ -138,68 +134,11 @@ sun_partition_map_iterate (grub_disk_t disk,
   return grub_errno;
 }
 
-static grub_partition_t
-sun_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-        {
-          p = (grub_partition_t) grub_malloc (sizeof (*p));
-          if (p)
-            grub_memcpy (p, partition, sizeof (*p));
-
-          return 1;
-        }
-
-      return 0;
-    }
-
-  grub_errno = GRUB_ERR_NONE;
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno == GRUB_ERR_NONE)
-    {
-      if (sun_partition_map_iterate (disk, find_func))
-        {
-          grub_free (p);
-          p = 0;
-        }
-    }
-  else
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      p = 0;
-    }
-
-  return p;
-}
-
-static char *
-sun_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (name)
-    grub_sprintf (name, "%d", p->index + 1);
-
-  return name;
-}
-
 /* Partition map type.  */
 static struct grub_partition_map grub_sun_partition_map =
   {
     .name = "sun_partition_map",
     .iterate = sun_partition_map_iterate,
-    .probe = sun_partition_map_probe,
-    .get_name = sun_partition_map_get_name
   };
 
 GRUB_MOD_INIT(sun_partition_map)
diff --git a/parttool/pcpart.c b/parttool/pcpart.c
index 6876d0d..da4d921 100644
--- a/parttool/pcpart.c
+++ b/parttool/pcpart.c
@@ -49,7 +49,7 @@ static grub_err_t grub_pcpart_boot (const grub_device_t dev,
 
   index = dev->disk->partition->index;
   part = dev->disk->partition;
-  dev->disk->partition = 0;
+  dev->disk->partition = part->parent;
 
   /* Read the MBR.  */
   if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr))
@@ -96,7 +96,7 @@ static grub_err_t grub_pcpart_type (const grub_device_t dev,
 
   index = dev->disk->partition->index;
   part = dev->disk->partition;
-  dev->disk->partition = 0;
+  dev->disk->partition = part->parent;
 
   /* Read the parttable.  */
   if (grub_disk_read (dev->disk, part->offset, 0,
diff --git a/util/hostdisk.c b/util/hostdisk.c
index fdf3514..ca57893 100644
--- a/util/hostdisk.c
+++ b/util/hostdisk.c
@@ -333,10 +333,13 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
   {
     int is_partition = 0;
     char dev[PATH_MAX];
+    grub_disk_addr_t part_start = 0;
+
+    part_start = grub_partition_get_start (disk->partition);
 
     strcpy (dev, map[disk->id].device);
     if (disk->partition && strncmp (map[disk->id].device, "/dev/", 5) == 0)
-      is_partition = linux_find_partition (dev, disk->partition->start);
+      is_partition = linux_find_partition (dev, part_start);
 
     /* Open the partition.  */
     grub_dprintf ("hostdisk", "opening the device `%s' in open_device()", dev);
@@ -351,7 +354,7 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
     ioctl (fd, BLKFLSBUF, 0);
 
     if (is_partition)
-      sector -= disk->partition->start;
+      sector -= part_start;
   }
 #else /* ! __linux__ */
 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -947,39 +950,25 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
     int find_partition (grub_disk_t disk __attribute__ ((unused)),
 			const grub_partition_t partition)
       {
- 	struct grub_pc_partition *pcdata = NULL;
-
-	if (strcmp (partition->partmap->name, "pc_partition_map") == 0)
-	  pcdata = partition->data;
+	grub_disk_addr_t part_start = 0;
+	grub_util_info ("Partition %d starts from %lu",
+			partition->number, partition->start);
 
-	if (pcdata)
-	  {
-	    if (pcdata->bsd_part < 0)
-	      grub_util_info ("DOS partition %d starts from %lu",
-			      pcdata->dos_part, partition->start);
-	    else
-	      grub_util_info ("BSD partition %d,%c starts from %lu",
-			      pcdata->dos_part, pcdata->bsd_part + 'a',
-			      partition->start);
-	  }
-	else
-	  {
-	      grub_util_info ("Partition %d starts from %lu",
-			      partition->index, partition->start);
-	  }
+	part_start = grub_partition_get_start (partition);
 
-	if (hdg.start == partition->start)
+	if (hdg.start == part_start)
 	  {
-	    if (pcdata)
+	    if (partition->parent)
 	      {
-		dos_part = pcdata->dos_part;
-		bsd_part = pcdata->bsd_part;
+		dos_part = partition->parent->number;
+		bsd_part = partition->number;
 	      }
 	    else
 	      {
-		dos_part = partition->index;
+		dos_part = partition->number;
 		bsd_part = -1;
 	      }
+
 	    return 1;
 	  }
 
diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c
index 92c69ef..e737233 100644
--- a/util/i386/pc/grub-setup.c
+++ b/util/i386/pc/grub-setup.c
@@ -121,15 +121,10 @@ setup (const char *dir,
   int NESTED_FUNC_ATTR find_usable_region_msdos (grub_disk_t disk __attribute__ ((unused)),
 						 const grub_partition_t p)
     {
-      struct grub_pc_partition *pcdata = p->data;
-
       /* There's always an embed region, and it starts right after the MBR.  */
       embed_region.start = 1;
 
-      /* For its end offset, include as many dummy partitions as we can.  */
-      if (! grub_pc_partition_is_empty (pcdata->dos_type)
-	  && ! grub_pc_partition_is_bsd (pcdata->dos_type)
-	  && embed_region.end > p->start)
+      if (embed_region.end > p->start)
 	embed_region.end = p->start;
 
       return 0;
@@ -278,22 +273,19 @@ setup (const char *dir,
       /* Embed information about the installed location.  */
       if (root_dev->disk->partition)
 	{
-	  if (strcmp (root_dev->disk->partition->partmap->name,
-		      "pc_partition_map") == 0)
+	  if (root_dev->disk->partition->parent)
 	    {
-	      struct grub_pc_partition *pcdata =
-		root_dev->disk->partition->data;
-	      dos_part = pcdata->dos_part;
-	      bsd_part = pcdata->bsd_part;
+	      if (root_dev->disk->partition->parent->parent)
+		grub_util_error ("Installing on doubly nested partitiond is "
+				 "not supported");
+	      dos_part = root_dev->disk->partition->parent->number;
+	      bsd_part = root_dev->disk->partition->number;
 	    }
-	  else if (strcmp (root_dev->disk->partition->partmap->name,
-			   "gpt_partition_map") == 0)
+	  else
 	    {
-	      dos_part = root_dev->disk->partition->index;
+	      dos_part = root_dev->disk->partition->number;
 	      bsd_part = -1;
 	    }
-	  else
-	    grub_util_error ("No PC style partitions found");
 	}
       else
 	dos_part = bsd_part = -1;

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-07-31 19:48       ` Vladimir 'phcoder' Serbinenko
@ 2009-07-31 20:25         ` Vladimir 'phcoder' Serbinenko
  2009-08-02 22:17         ` Robert Millan
  1 sibling, 0 replies; 36+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-07-31 20:25 UTC (permalink / raw)
  To: The development of GRUB 2

On Fri, Jul 31, 2009 at 9:48 PM, Vladimir 'phcoder'
Serbinenko<phcoder@gmail.com> wrote:
>>> What makes this experimental and dangerous?  Can you send in a patch
>>> that isn't?
>> Only that I touch core size
> *core functionality
>> and when I submitted it, it was only few
>> days old. Now I use it for over a month and haven't hit any problem
>> The typical case of the problem it solves is Solaris. When installed
>> on x86 its partition is subpartitioned. Because of that current grub
>> can't access its filesystem even if it's UFS or even when ZFS module
>> is loaded. sun_pc subpartitioning style will be a subject of separate
>> patch.
>
> The proble it doesn't solve is when 2 partition labels pretend to
> describe the same region. Solaris during install dd'es MBR to its
> partition that it subdivides in further paritions. This way the
> parition seems to have 2 valid subpartitioning tables. I think the
> most sane way to handle this is to introduce partition labels
> priority. Fortunately thanks to Bean we have priority-list handling
> function so it should increase the size of core for a lot. Numbers
> will be available when I test it.

Mainstream core with pc+fat+biosdisk: 26179 bytes
Core with nested parition support  with pc+fat+biosdisk: 26027 bytes
Core with nested parition support  with pc+bsdlabel+fat+biosdisk: 26392 bytes
As you can see core size decreases if no bsdlabel support is needed
but increases otherwise. Fortunately BSDs are unlikely to be on Reiser
or LVM (although may be on ZFS)
After additionally removing 'data' field w/o bsdlabel: 26000
After additionally removing 'data' field w/ bsdlabel: 26352
After additionally adding priority support w/o bsdlabel: 26006
After additionally adding priority support w/o bsdlabel: 26367

After additionally not inlining grub_partition_get_start w/o bsdlabel: 26022
After additionally not inlining grub_partition_get_start w/ bsdlabel: 26363
So I prefer to let grub_partition_get_start inlined


-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-07-16 20:52 ` Vladimir 'phcoder' Serbinenko
  2009-07-31  7:58   ` Marco Gerards
@ 2009-08-02 22:02   ` Robert Millan
  2009-08-02 22:09     ` Vladimir 'phcoder' Serbinenko
  1 sibling, 1 reply; 36+ messages in thread
From: Robert Millan @ 2009-08-02 22:02 UTC (permalink / raw)
  To: The development of GRUB 2

On Thu, Jul 16, 2009 at 10:52:37PM +0200, Vladimir 'phcoder' Serbinenko wrote:
> @@ -94,10 +95,28 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
>    dev = grub_device_open (0);
>    if (dev && dev->disk && dev->disk->partition)
>      {
> -      grub_disk_read (dev->disk, dev->disk->partition->offset, 446, 64,
> -		      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
> -      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
> -			    + (dev->disk->partition->index << 4));
> +      grub_disk_t disk = dev->disk;
> +
> +      if (disk)
> +	{
> +	  grub_partition_t p = disk->partition;
> +
> +	  /* In i386-pc, the id is equal to the BIOS drive number.  */
> +	  drive = (int) disk->id;
> +
> +	  if (p && grub_strcmp (p->partmap->name, "pc_partition_map") == 0)
> +	    {
> +	      disk->partition = p->parent;
> +	      grub_disk_read (disk, p->offset, 446, 64,
> +			      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
> +	      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
> +				    + (((struct grub_pc_partition *) p->data)
> +				       ->index << 4));
> +	      disk->partition = p;
> +	    }
> +	}
> +
> +      grub_device_close (dev);

I don't think we should allow chainload at all in partitions other than msdos
ones.  There's no existing use of this for other labels "in the wild", and we
shouldn't encourage it to appear IMO.

If we have partitions and the "pc_partition_map" match fails, I would just
abort.

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-02 22:02   ` Robert Millan
@ 2009-08-02 22:09     ` Vladimir 'phcoder' Serbinenko
  2009-08-02 22:25       ` Robert Millan
  0 siblings, 1 reply; 36+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-08-02 22:09 UTC (permalink / raw)
  To: The development of GRUB 2

>> +      grub_device_close (dev);
>
> I don't think we should allow chainload at all in partitions other than msdos
> ones.  There's no existing use of this for other labels "in the wild", and we
> shouldn't encourage it to appear IMO.
Actually it's something which happens with GPT. Suppose you have an OS
on your GPT which has no multiboot support. In this case you use
gptsync to create a fake msdos partition map and boot your OS. But
probably in this case this code should create a fake partition entry
at %es:%di too. Creating a fake entry may also be beneficial for
extended partitions and may make some targets which usually doesn't
support booting from extended partition to boot however
>
> If we have partitions and the "pc_partition_map" match fails, I would just
> abort.
>
> --
> Robert Millan
>
>  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
>  how) you may access your data; but nobody's threatening your freedom: we
>  still allow you to remove your data and not access it at all."
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>



-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-07-31 19:48       ` Vladimir 'phcoder' Serbinenko
  2009-07-31 20:25         ` Vladimir 'phcoder' Serbinenko
@ 2009-08-02 22:17         ` Robert Millan
  2009-08-02 22:36           ` Vladimir 'phcoder' Serbinenko
  1 sibling, 1 reply; 36+ messages in thread
From: Robert Millan @ 2009-08-02 22:17 UTC (permalink / raw)
  To: The development of GRUB 2

On Fri, Jul 31, 2009 at 09:48:21PM +0200, Vladimir 'phcoder' Serbinenko wrote:
> 
> The proble it doesn't solve is when 2 partition labels pretend to
> describe the same region. Solaris during install dd'es MBR to its
> partition that it subdivides in further paritions. This way the
> parition seems to have 2 valid subpartitioning tables. I think the
> most sane way to handle this is to introduce partition labels
> priority.

Priority lists sound like an overkill solution.  In practice, how many
times are we going to recurse at most?  Does the same number apply to
all partmap type combinations, or just some of them?

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-02 22:09     ` Vladimir 'phcoder' Serbinenko
@ 2009-08-02 22:25       ` Robert Millan
  2009-08-02 22:44         ` Vladimir 'phcoder' Serbinenko
  0 siblings, 1 reply; 36+ messages in thread
From: Robert Millan @ 2009-08-02 22:25 UTC (permalink / raw)
  To: The development of GRUB 2

On Mon, Aug 03, 2009 at 12:09:32AM +0200, Vladimir 'phcoder' Serbinenko wrote:
> >> +      grub_device_close (dev);
> >
> > I don't think we should allow chainload at all in partitions other than msdos
> > ones.  There's no existing use of this for other labels "in the wild", and we
> > shouldn't encourage it to appear IMO.
> Actually it's something which happens with GPT. Suppose you have an OS
> on your GPT which has no multiboot support. In this case you use
> gptsync to create a fake msdos partition map and boot your OS.

So gpt could be the other exception because it is backward compatible with
msdos labels (to some extent).

But please let's not make a general rule out of this.  The chainloader is
an implementation of the DOS MBR<->PBR boot protocol, which has been mimicked
by others but is still only available on msdos labels.  If someone tries it
on another partition label type, she should see an error.

Btw, does this bugfix depend on the rest of nested partition changes?

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-02 22:17         ` Robert Millan
@ 2009-08-02 22:36           ` Vladimir 'phcoder' Serbinenko
  0 siblings, 0 replies; 36+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-08-02 22:36 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 2553 bytes --]

On Mon, Aug 3, 2009 at 12:17 AM, Robert Millan<rmh@aybabtu.com> wrote:
> On Fri, Jul 31, 2009 at 09:48:21PM +0200, Vladimir 'phcoder' Serbinenko wrote:
>>
>> The proble it doesn't solve is when 2 partition labels pretend to
>> describe the same region. Solaris during install dd'es MBR to its
>> partition that it subdivides in further paritions. This way the
>> parition seems to have 2 valid subpartitioning tables. I think the
>> most sane way to handle this is to introduce partition labels
>> priority.
>
> Priority lists sound like an overkill solution.
I'm not sure that you see the problem. Let's say we have a disk
containing sun_pc label. sun_pc uses only sector number 1. So in
sector 0 you can put a standard msdos. So the same area is described
by 2 labels and grub has decide which to choose. If it was a purely
theoretical situation I wouldn't care. Unfortunately it's the
situation one encounters with opensolaris installer or if a bootsector
contains a lookalike of msdos partition (64 bytes zeros plus a
bootsector signature is a valid msdos label).
You can look at the patch if you want (I wasn't going to submit it yet
actually). It adds only 14 bytes to core size (first version added 6
but had a bug fixing which added another 8 bytes)
> In practice, how many
> times are we going to recurse at most?
In practise we probably won't have more than 2 levels of partitions.
But code for just 2 levels and for unlimited number of levels is of
the same complexity. So I prefer to avoid artitficial limit. But AFAIK
no OS is able to load from a 3-nested partition except perhaps using
tricks like loopbacks.
I'm aware of 4 situations when nested partitions are used
BSDlabel inside msdos for *BSD
sun_pc (patch ready but not submitted yet) inside msdos for OpenSolaris.
msdos inside msdos for minix
msdos inside GPT is described in GPT specification but I never saw it to be used
I vaguely heard of sun partitions inside apple partitions and AROS
mixing amiga and msdos

>
> --
> Robert Millan
>
>  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
>  how) you may access your data; but nobody's threatening your freedom: we
>  still allow you to remove your data and not access it at all."
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>



-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git

[-- Attachment #2: partprio.diff --]
[-- Type: text/plain, Size: 5779 bytes --]

diff --git a/conf/common.rmk b/conf/common.rmk
index dbbf38f..0c4873d 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -13,6 +13,7 @@ grub_probe_SOURCES = util/grub-probe.c	\
 	util/hostdisk.c	util/misc.c util/getroot.c		\
 	kern/device.c kern/disk.c kern/err.c kern/misc.c	\
 	kern/parser.c kern/partition.c kern/file.c		\
+	kern/list.c \
 	\
 	fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c		\
 	fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c	\
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index c213bfd..cfdc50f 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -100,6 +100,7 @@ grub_setup_SOURCES = util/i386/pc/grub-setup.c util/hostdisk.c	\
 	util/misc.c util/getroot.c kern/device.c kern/disk.c	\
 	kern/err.c kern/misc.c kern/parser.c kern/partition.c	\
 	kern/file.c kern/fs.c kern/env.c fs/fshelp.c		\
+	kern/list.c \
 	\
 	fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c		\
 	fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c	\
diff --git a/include/grub/partition.h b/include/grub/partition.h
index 6c0939b..6e50661 100644
--- a/include/grub/partition.h
+++ b/include/grub/partition.h
@@ -28,16 +28,19 @@ typedef struct grub_partition *grub_partition_t;
 /* Partition map type.  */
 struct grub_partition_map
 {
+  /* The next partition map type.  */
+  struct grub_partition_map *next;
+
   /* The name of the partition map type.  */
   const char *name;
 
+  /* Priority of this partition map.  */
+  int prio;
+
   /* Call HOOK with each partition, until HOOK returns non-zero.  */
   grub_err_t (*iterate) (struct grub_disk *disk,
 			 int (*hook) (struct grub_disk *disk,
 				      const grub_partition_t partition));
-
-  /* The next partition map type.  */
-  struct grub_partition_map *next;
 };
 typedef struct grub_partition_map *grub_partition_map_t;
 
diff --git a/kern/partition.c b/kern/partition.c
index aa7161f..415765a 100644
--- a/kern/partition.c
+++ b/kern/partition.c
@@ -20,39 +20,35 @@
 #include <grub/mm.h>
 #include <grub/partition.h>
 #include <grub/disk.h>
+#include <grub/list.h>
 
 static grub_partition_map_t grub_partition_map_list;
 
+static int test (grub_partition_map_t new_item, grub_partition_map_t item)
+{
+  return new_item->prio > item->prio;
+}
+
 void
 grub_partition_map_register (grub_partition_map_t partmap)
 {
-  partmap->next = grub_partition_map_list;
-  grub_partition_map_list = partmap;
+  grub_list_insert (GRUB_AS_LIST_P (&grub_partition_map_list),
+		    GRUB_AS_LIST (partmap),
+		    (grub_list_test_t) test);
 }
 
 void
 grub_partition_map_unregister (grub_partition_map_t partmap)
 {
-  grub_partition_map_t *p, q;
-
-  for (p = &grub_partition_map_list, q = *p; q; p = &(q->next), q = q->next)
-    if (q == partmap)
-      {
-        *p = q->next;
-	break;
-      }
+  grub_list_remove (GRUB_AS_LIST_P (&grub_partition_map_list),
+		    GRUB_AS_LIST (partmap));
 }
 
 int
 grub_partition_map_iterate (int (*hook) (const grub_partition_map_t partmap))
 {
-  grub_partition_map_t p;
-
-  for (p = grub_partition_map_list; p; p = p->next)
-    if (hook (p))
-      return 1;
-
-  return 0;
+  return grub_list_iterate (GRUB_AS_LIST (grub_partition_map_list),
+			    (grub_list_hook_t) hook);
 }
 
 static grub_partition_t
diff --git a/partmap/acorn.c b/partmap/acorn.c
index 0318beb..9d4bdce 100644
--- a/partmap/acorn.c
+++ b/partmap/acorn.c
@@ -131,6 +131,7 @@ acorn_partition_map_iterate (grub_disk_t disk,
 static struct grub_partition_map grub_acorn_partition_map =
 {
   .name = "Linux/ADFS partition map",
+  .prio = 10,
   .iterate = acorn_partition_map_iterate,
 };
 
diff --git a/partmap/amiga.c b/partmap/amiga.c
index 4f5c9dd..2cee986 100644
--- a/partmap/amiga.c
+++ b/partmap/amiga.c
@@ -136,6 +136,7 @@ amiga_partition_map_iterate (grub_disk_t disk,
 /* Partition map type.  */
 static struct grub_partition_map grub_amiga_partition_map =
   {
+    .prio = 10,
     .name = "amiga_partition_map",
     .iterate = amiga_partition_map_iterate,
   };
diff --git a/partmap/apple.c b/partmap/apple.c
index 09259a1..3a67b78 100644
--- a/partmap/apple.c
+++ b/partmap/apple.c
@@ -172,6 +172,7 @@ apple_partition_map_iterate (grub_disk_t disk,
 /* Partition map type.  */
 static struct grub_partition_map grub_apple_partition_map =
   {
+    .prio = 5,
     .name = "apple_partition_map",
     .iterate = apple_partition_map_iterate,
   };
diff --git a/partmap/bsdlabel.c b/partmap/bsdlabel.c
index f376dce..d007105 100644
--- a/partmap/bsdlabel.c
+++ b/partmap/bsdlabel.c
@@ -73,6 +73,7 @@ bsdlabel_partition_map_iterate (grub_disk_t disk,
 static struct grub_partition_map grub_bsdlabel_partition_map =
   {
     .name = "bsdlabel_partition_map",
+    .prio = 5,
     .iterate = bsdlabel_partition_map_iterate,
   };
 
diff --git a/partmap/gpt.c b/partmap/gpt.c
index e258297..d51c8b3 100644
--- a/partmap/gpt.c
+++ b/partmap/gpt.c
@@ -112,6 +112,7 @@ gpt_partition_map_iterate (grub_disk_t disk,
 /* Partition map type.  */
 static struct grub_partition_map grub_gpt_partition_map =
   {
+    .prio = 10,
     .name = "gpt_partition_map",
     .iterate = gpt_partition_map_iterate,
   };
diff --git a/partmap/pc.c b/partmap/pc.c
index fd9dc09..d9d3e6a 100644
--- a/partmap/pc.c
+++ b/partmap/pc.c
@@ -120,6 +120,7 @@ pc_partition_map_iterate (grub_disk_t disk,
 static struct grub_partition_map grub_pc_partition_map =
   {
     .name = "pc_partition_map",
+    .prio = 1,
     .iterate = pc_partition_map_iterate,
   };
 
diff --git a/partmap/sun.c b/partmap/sun.c
index 63ba6ae..2c6ee44 100644
--- a/partmap/sun.c
+++ b/partmap/sun.c
@@ -138,6 +138,7 @@ sun_partition_map_iterate (grub_disk_t disk,
 static struct grub_partition_map grub_sun_partition_map =
   {
     .name = "sun_partition_map",
+    .prio = 10,
     .iterate = sun_partition_map_iterate,
   };
 

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-02 22:25       ` Robert Millan
@ 2009-08-02 22:44         ` Vladimir 'phcoder' Serbinenko
  2009-08-04 20:15           ` Robert Millan
  0 siblings, 1 reply; 36+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-08-02 22:44 UTC (permalink / raw)
  To: The development of GRUB 2

On Mon, Aug 3, 2009 at 12:25 AM, Robert Millan<rmh@aybabtu.com> wrote:
> On Mon, Aug 03, 2009 at 12:09:32AM +0200, Vladimir 'phcoder' Serbinenko wrote:
>> >> +      grub_device_close (dev);
>> >
>> > I don't think we should allow chainload at all in partitions other than msdos
>> > ones.  There's no existing use of this for other labels "in the wild", and we
>> > shouldn't encourage it to appear IMO.
>> Actually it's something which happens with GPT. Suppose you have an OS
>> on your GPT which has no multiboot support. In this case you use
>> gptsync to create a fake msdos partition map and boot your OS.
>
> So gpt could be the other exception because it is backward compatible with
> msdos labels (to some extent).
>
> But please let's not make a general rule out of this.  The chainloader is
> an implementation of the DOS MBR<->PBR boot protocol, which has been mimicked
> by others but is still only available on msdos labels.  If someone tries it
> on another partition label type, she should see an error.
>
> Btw, does this bugfix depend on the rest of nested partition changes?
>
Actually only superficially
> +           disk->partition = p->parent;
this line would be = 0; without nestpart patch. If you want I can
commit it separately.

The following line is bogus:
> +       /* In i386-pc, the id is equal to the BIOS drive number.  */
> +       drive = (int) disk->id;
It shouldn't have been here at all - it was written before
introduction of biosnum. I won't resend the patch because of this but
I corrected it in my local git
> --
> Robert Millan
>
>  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
>  how) you may access your data; but nobody's threatening your freedom: we
>  still allow you to remove your data and not access it at all."
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>



-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-02 22:44         ` Vladimir 'phcoder' Serbinenko
@ 2009-08-04 20:15           ` Robert Millan
  2009-08-17 13:00             ` Vladimir 'phcoder' Serbinenko
  0 siblings, 1 reply; 36+ messages in thread
From: Robert Millan @ 2009-08-04 20:15 UTC (permalink / raw)
  To: The development of GRUB 2

On Mon, Aug 03, 2009 at 12:44:37AM +0200, Vladimir 'phcoder' Serbinenko wrote:
> >
> > Btw, does this bugfix depend on the rest of nested partition changes?
> >
> Actually only superficially
> > +           disk->partition = p->parent;
> this line would be = 0; without nestpart patch. If you want I can
> commit it separately.
> 
> The following line is bogus:
> > +       /* In i386-pc, the id is equal to the BIOS drive number.  */
> > +       drive = (int) disk->id;
> It shouldn't have been here at all - it was written before
> introduction of biosnum. I won't resend the patch because of this but
> I corrected it in my local git

Please take into account the issue with pc_partition_map.  Your current
patch checks for it in a place where operation with non-msdos labels would
still proceed.

I notice the grub_device_open(0) call is wrong too, but this has nothing to
do with your patch.

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-04 20:15           ` Robert Millan
@ 2009-08-17 13:00             ` Vladimir 'phcoder' Serbinenko
  2009-08-17 14:06               ` Robert Millan
  0 siblings, 1 reply; 36+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-08-17 13:00 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 1572 bytes --]

Rediff and few fixes

On Tue, Aug 4, 2009 at 10:15 PM, Robert Millan<rmh@aybabtu.com> wrote:
> On Mon, Aug 03, 2009 at 12:44:37AM +0200, Vladimir 'phcoder' Serbinenko wrote:
>> >
>> > Btw, does this bugfix depend on the rest of nested partition changes?
>> >
>> Actually only superficially
>> > +           disk->partition = p->parent;
>> this line would be = 0; without nestpart patch. If you want I can
>> commit it separately.
>>
>> The following line is bogus:
>> > +       /* In i386-pc, the id is equal to the BIOS drive number.  */
>> > +       drive = (int) disk->id;
>> It shouldn't have been here at all - it was written before
>> introduction of biosnum. I won't resend the patch because of this but
>> I corrected it in my local git
>
> Please take into account the issue with pc_partition_map.  Your current
> patch checks for it in a place where operation with non-msdos labels would
> still proceed.
>
> I notice the grub_device_open(0) call is wrong too, but this has nothing to
> do with your patch.
>
> --
> Robert Millan
>
>  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
>  how) you may access your data; but nobody's threatening your freedom: we
>  still allow you to remove your data and not access it at all."
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>



-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git

[-- Attachment #2: nestpart.diff --]
[-- Type: text/plain, Size: 61060 bytes --]

diff --git a/ChangeLog b/ChangeLog
index 3d34abf..55c72b6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,76 @@
+2009-06-08  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	Nested partitions
+
+	* commands/blocklist.c (grub_cmd_blocklist): Don't check whether
+	'partition' is NULL, grub_partition_get_start already does that.
+	* commands/loadenv.c (check_blocklists): Likewise.
+	(write_blocklists): Likewise.
+	* conf/common.rmk (grub_probe_SOURCES): Add partmap/bsdlabel.c.
+	(grub_fstest_SOURCES): Likewise.
+	(pkglib_MODULES): Add bsdlabel.mod.
+	(bsdlabel_mod_SOURCES): New variable.
+	(bsdlabel_mod_CFLAGS): Likewise.
+	(bsdlabel_mod_LDFLAGS): Likewise.
+	* conf/i386-coreboot.rmk (grub_emu_SOURCES): Add partmap/bsdlabel.c.
+	* conf/i386-pc.rmk (grub_setup_SOURCES): Likewise.
+	(grub_emu_SOURCES): Likewise.
+	* conf/powerpc-ieee1275.rmk (grub_emu_SOURCES): Likewise.
+	* conf/sparc64-ieee1275.rmk (grub_emu_SOURCES): Likewise.
+	* include/grub/bsdlabel.h: New file.
+	* include/grub/partition.h (grub_partition_map): Remove 'probe' and
+	'get_name'.
+	(grub_partition): Add 'parent' and 'number'.
+	(grub_partition_get_start): Handle nested partitions.
+	* include/grub/pc_partition.h: Remove bsd-related entries.
+	(grub_pc_partition): Remove.
+	* kern/disk.c (grub_disk_close): Free partition data.
+	(grub_disk_adjust_range): Handle nested partitions.
+	* kern/partition.c (grub_partition_map_probe): New function.
+	(grub_partition_probe): Parse name to number, handle subpartitions.
+	(get_partmap): New function.
+	(grub_partition_iterate): Handle subpartitions.
+	(grub_partition_get_name): Likewise.
+	* loader/i386/pc/bsd.c (grub_bsd_get_device): Likewise.
+	* loader/i386/multiboot.c (grub_multiboot_get_bootdev): Likewise.
+	* loader/i386/pc/chainloader.c (grub_chainloader_cmd): Likewise.
+	* partmap/acorn.c (acorn_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	(acorn_partition_map_probe): Remove.
+	(acorn_partition_map_get_name): Likewise.
+	* partmap/amiga.c (amiga_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Set 'index' to 0 since there can be only one partition entry per sector.
+	(amiga_partition_map_probe): Remove.
+	(amiga_partition_map_get_name): Likewise.
+	* partmap/apple.c (apple_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Set 'offset' and 'index' to real positions of partitions.
+	(apple_partition_map_probe): Remove.
+	(apple_partition_map_get_name): Likewise.
+	* partmap/bsdlabel.c: New file.
+	* partmap/gpt.c (gpt_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Allocate 'data' so it can be correctly freed.
+	Set 'index' to offset inside sector.
+	(gpt_partition_map_probe): Remove.
+	(gpt_partition_map_get_name): Likewise.
+	* partmap/pc.c (grub_partition_parse): Remove.
+	(pc_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Make 'ext_offset' a local variable.
+	(pc_partition_map_probe): Remove.
+	(pc_partition_map_get_name): Remove.
+	* partmap/sun.c (sun_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	(sun_partition_map_probe): Remove.
+	(sun_partition_map_get_name): Likewise.
+	* parttool/pcpart.c (grub_pcpart_boot): Handle nested partitions.
+	(grub_pcpart_type): Likewise.
+	* util/hostdisk.c (open_device): Handle new numbering scheme.
+	(grub_util_biosdisk_get_grub_dev): Handle nested partitions.
+	* util/i386/pc/grub-setup.c (setup): Handle new numbering scheme.
+
 2009-08-15  Vladimir Serbinenko  <phcoder@gmail.com>
 
 	* fs/affs.c (grub_affs_read_symlink): Change leftover grub_printf into
diff --git a/commands/blocklist.c b/commands/blocklist.c
index b457b7c..6cc7d69 100644
--- a/commands/blocklist.c
+++ b/commands/blocklist.c
@@ -89,8 +89,7 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)),
     return grub_error (GRUB_ERR_BAD_DEVICE,
 		       "this command is available only for disk devices.");
 
-  if (file->device->disk->partition)
-    part_start = grub_partition_get_start (file->device->disk->partition);
+  part_start = grub_partition_get_start (file->device->disk->partition);
 
   file->read_hook = read_blocklist;
 
diff --git a/commands/loadenv.c b/commands/loadenv.c
index 22665f9..51cffd3 100644
--- a/commands/loadenv.c
+++ b/commands/loadenv.c
@@ -236,10 +236,8 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
   /* One more sanity check. Re-read all sectors by blocklists, and compare
      those with the data read via a file.  */
   disk = file->device->disk;
-  if (disk->partition)
-    part_start = grub_partition_get_start (disk->partition);
-  else
-    part_start = 0;
+
+  part_start = grub_partition_get_start (disk->partition);
 
   buf = grub_envblk_buffer (envblk);
   for (p = blocklists, index = 0; p; p = p->next, index += p->length)
@@ -272,10 +270,7 @@ write_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
 
   buf = grub_envblk_buffer (envblk);
   disk = file->device->disk;
-  if (disk->partition)
-    part_start = grub_partition_get_start (disk->partition);
-  else
-    part_start = 0;
+  part_start = grub_partition_get_start (disk->partition);
 
   index = 0;
   for (p = blocklists; p; p = p->next, index += p->length)
diff --git a/conf/common.rmk b/conf/common.rmk
index b0d3785..84dcbbb 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -19,7 +19,8 @@ grub_probe_SOURCES = util/grub-probe.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c		\
 	\
-	partmap/pc.c partmap/apple.c partmap/sun.c partmap/gpt.c\
+	partmap/pc.c partmap/bsdlabel.c partmap/apple.c \
+	partmap/sun.c partmap/gpt.c\
 	kern/fs.c kern/env.c fs/fshelp.c			\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c grub_probe_init.c
 
@@ -40,8 +41,8 @@ grub_fstest_SOURCES = util/grub-fstest.c util/hostfs.c util/misc.c 	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c			\
 	fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c			\
 	\
-	kern/partition.c partmap/pc.c partmap/apple.c partmap/sun.c	\
-	partmap/gpt.c							\
+	kern/partition.c partmap/pc.c partmap/bsdlabel.c partmap/apple.c\
+	partmap/sun.c partmap/gpt.c					\
 	kern/fs.c kern/env.c fs/fshelp.c disk/raid.c			\
 	disk/raid5_recover.c disk/raid6_recover.c 			\
 	disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c 		\
@@ -285,7 +286,8 @@ befs_mod_CFLAGS = $(COMMON_CFLAGS)
 befs_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # Partition maps.
-pkglib_MODULES += amiga.mod apple.mod pc.mod sun.mod acorn.mod gpt.mod
+pkglib_MODULES += amiga.mod apple.mod pc.mod sun.mod acorn.mod gpt.mod \
+		  bsdlabel.mod
 
 # For amiga.mod
 amiga_mod_SOURCES = partmap/amiga.c
@@ -302,6 +304,11 @@ pc_mod_SOURCES = partmap/pc.c
 pc_mod_CFLAGS = $(COMMON_CFLAGS)
 pc_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For pc.mod
+bsdlabel_mod_SOURCES = partmap/bsdlabel.c
+bsdlabel_mod_CFLAGS = $(COMMON_CFLAGS)
+bsdlabel_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For sun.mod
 sun_mod_SOURCES = partmap/sun.c
 sun_mod_CFLAGS = $(COMMON_CFLAGS)
diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk
index ce2576b..fdd640f 100644
--- a/conf/i386-coreboot.rmk
+++ b/conf/i386-coreboot.rmk
@@ -134,8 +134,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c       \
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c          \
-	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/bsdlabel.c \
+	partmap/sun.c partmap/acorn.c partmap/gpt.c			\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk
index 65d1c6b..818a058 100644
--- a/conf/i386-ieee1275.rmk
+++ b/conf/i386-ieee1275.rmk
@@ -88,8 +88,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c		\
-	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/bsdlabel.c \
+	partmap/sun.c partmap/acorn.c partmap/gpt.c			\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index 0ef5e47..f1a3a43 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -104,7 +104,7 @@ grub_setup_SOURCES = util/i386/pc/grub-setup.c util/hostdisk.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c			\
 	\
-	partmap/pc.c partmap/gpt.c				\
+	partmap/pc.c partmap/bsdlabel.c partmap/gpt.c		\
 	\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
 	util/raid.c util/lvm.c					\
@@ -140,8 +140,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/menu_text.c						\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c		\
-	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/bsdlabel.c partmap/pc.c \
+	partmap/sun.c partmap/acorn.c partmap/gpt.c			\
 	\
 	fs/affs.c fs/cpio.c  fs/fat.c fs/ext2.c fs/hfs.c		\
 	fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c		\
diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk
index c30f61a..4649222 100644
--- a/conf/powerpc-ieee1275.rmk
+++ b/conf/powerpc-ieee1275.rmk
@@ -69,8 +69,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c 	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c				\
-	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
-	partmap/acorn.c							\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/bsdlabel.c \
+	partmap/sun.c partmap/acorn.c					\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk
index b26496d..27bf7b1 100644
--- a/conf/sparc64-ieee1275.rmk
+++ b/conf/sparc64-ieee1275.rmk
@@ -80,8 +80,8 @@ grub_setup_SOURCES = util/sparc64/ieee1275/grub-setup.c util/hostdisk.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c			\
 	\
-	partmap/amiga.c	partmap/apple.c partmap/pc.c		\
-	partmap/sun.c partmap/acorn.c				\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c 		\
+	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c	\
 	\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
 	util/raid.c util/lvm.c					\
diff --git a/include/grub/bsdlabel.h b/include/grub/bsdlabel.h
new file mode 100644
index 0000000..ba75897
--- /dev/null
+++ b/include/grub/bsdlabel.h
@@ -0,0 +1,91 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2004,2007  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_BSDLABEL_PARTITION_HEADER
+#define GRUB_BSDLABEL_PARTITION_HEADER	1
+
+/* Constants for BSD disk label.  */
+#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR	1
+#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC	0x82564557
+#define GRUB_PC_PARTITION_BSD_MAX_ENTRIES	8
+
+/* BSD partition types.  */
+#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED	0
+#define GRUB_PC_PARTITION_BSD_TYPE_SWAP		1
+#define GRUB_PC_PARTITION_BSD_TYPE_V6		2
+#define GRUB_PC_PARTITION_BSD_TYPE_V7		3
+#define GRUB_PC_PARTITION_BSD_TYPE_SYSV		4
+#define GRUB_PC_PARTITION_BSD_TYPE_V71K		5
+#define GRUB_PC_PARTITION_BSD_TYPE_V8		6
+#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS	7
+#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS	8
+#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS	9
+#define GRUB_PC_PARTITION_BSD_TYPE_OTHER	10
+#define GRUB_PC_PARTITION_BSD_TYPE_HPFS		11
+#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660	12
+#define GRUB_PC_PARTITION_BSD_TYPE_BOOT		13
+
+/* FreeBSD-specific types.  */
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM	14
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID	15
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2	21
+
+/* NetBSD-specific types.  */
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_ADOS	14
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_HFS	15
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE	16
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS	17
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_NTFS	18
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_RAID	19
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_CCD	20
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_JFS2	21
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS	22
+
+/* OpenBSD-specific types.  */
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS	14
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_HFS	15
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE	16
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS	17
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS	18
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_RAID	19
+
+/* The BSD partition entry.  */
+struct grub_pc_partition_bsd_entry
+{
+  grub_uint32_t size;
+  grub_uint32_t offset;
+  grub_uint32_t fragment_size;
+  grub_uint8_t fs_type;
+  grub_uint8_t fs_fragments;
+  grub_uint16_t fs_cylinders;
+} __attribute__ ((packed));
+
+/* The BSD disk label. Only define members useful for GRUB.  */
+struct grub_pc_partition_disk_label
+{
+  grub_uint32_t magic;
+  grub_uint8_t padding[128];
+  grub_uint32_t magic2;
+  grub_uint16_t checksum;
+  grub_uint16_t num_partitions;
+  grub_uint32_t boot_size;
+  grub_uint32_t superblock_size;
+  struct grub_pc_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES];
+} __attribute__ ((packed));
+
+#endif /* ! GRUB_PC_PARTITION_HEADER */
diff --git a/include/grub/partition.h b/include/grub/partition.h
index 37c5f24..1c4ba31 100644
--- a/include/grub/partition.h
+++ b/include/grub/partition.h
@@ -36,13 +36,6 @@ struct grub_partition_map
 			 int (*hook) (struct grub_disk *disk,
 				      const grub_partition_t partition));
 
-  /* Return the partition named STR on the disk DISK.  */
-  grub_partition_t (*probe) (struct grub_disk *disk,
-			     const char *str);
-
-  /* Return the name of the partition PARTITION.  */
-  char *(*get_name) (const grub_partition_t partition);
-
   /* The next partition map type.  */
   struct grub_partition_map *next;
 };
@@ -51,6 +44,9 @@ typedef struct grub_partition_map *grub_partition_map_t;
 /* Partition description.  */
 struct grub_partition
 {
+  /* The partition number.  */
+  int number;
+
   /* The start sector.  */
   grub_disk_addr_t start;
 
@@ -66,6 +62,9 @@ struct grub_partition
   /* Partition map type specific data.  */
   void *data;
 
+  /* Parent partition map.  */
+  struct grub_partition *parent;
+
   /* The type partition map.  */
   grub_partition_map_t partmap;
 };
@@ -101,7 +100,13 @@ void grub_apple_partition_map_fini (void);
 static inline grub_disk_addr_t
 grub_partition_get_start (const grub_partition_t p)
 {
-  return p->start;
+  grub_partition_t part;
+  grub_uint64_t part_start = 0;
+
+  for (part = p; part; part = part->parent)
+    part_start += part->start;
+
+  return part_start;
 }
 
 static inline grub_uint64_t
diff --git a/include/grub/pc_partition.h b/include/grub/pc_partition.h
index 67c312e..0b081ed 100644
--- a/include/grub/pc_partition.h
+++ b/include/grub/pc_partition.h
@@ -53,75 +53,6 @@
 #define GRUB_PC_PARTITION_TYPE_GPT_DISK		0xee
 #define GRUB_PC_PARTITION_TYPE_LINUX_RAID	0xfd
 
-/* Constants for BSD disk label.  */
-#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR	1
-#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC	0x82564557
-#define GRUB_PC_PARTITION_BSD_MAX_ENTRIES	8
-
-/* BSD partition types.  */
-#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED	0
-#define GRUB_PC_PARTITION_BSD_TYPE_SWAP		1
-#define GRUB_PC_PARTITION_BSD_TYPE_V6		2
-#define GRUB_PC_PARTITION_BSD_TYPE_V7		3
-#define GRUB_PC_PARTITION_BSD_TYPE_SYSV		4
-#define GRUB_PC_PARTITION_BSD_TYPE_V71K		5
-#define GRUB_PC_PARTITION_BSD_TYPE_V8		6
-#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS	7
-#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS	8
-#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS	9
-#define GRUB_PC_PARTITION_BSD_TYPE_OTHER	10
-#define GRUB_PC_PARTITION_BSD_TYPE_HPFS		11
-#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660	12
-#define GRUB_PC_PARTITION_BSD_TYPE_BOOT		13
-
-/* FreeBSD-specific types.  */
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM	14
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID	15
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2	21
-
-/* NetBSD-specific types.  */
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_ADOS	14
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_HFS	15
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE	16
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS	17
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_NTFS	18
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_RAID	19
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_CCD	20
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_JFS2	21
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS	22
-
-/* OpenBSD-specific types.  */
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS	14
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_HFS	15
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE	16
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS	17
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS	18
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_RAID	19
-
-/* The BSD partition entry.  */
-struct grub_pc_partition_bsd_entry
-{
-  grub_uint32_t size;
-  grub_uint32_t offset;
-  grub_uint32_t fragment_size;
-  grub_uint8_t fs_type;
-  grub_uint8_t fs_fragments;
-  grub_uint16_t fs_cylinders;
-} __attribute__ ((packed));
-
-/* The BSD disk label. Only define members useful for GRUB.  */
-struct grub_pc_partition_disk_label
-{
-  grub_uint32_t magic;
-  grub_uint8_t padding[128];
-  grub_uint32_t magic2;
-  grub_uint16_t checksum;
-  grub_uint16_t num_partitions;
-  grub_uint32_t boot_size;
-  grub_uint32_t superblock_size;
-  struct grub_pc_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES];
-} __attribute__ ((packed));
-
 /* The partition entry.  */
 struct grub_pc_partition_entry
 {
@@ -168,23 +99,6 @@ struct grub_pc_partition_mbr
 } __attribute__ ((packed));
 
 \f
-struct grub_pc_partition
-{
-    /* The DOS partition number.  */
-  int dos_part;
-
-  /* The BSD partition number (a == 0).  */
-  int bsd_part;
-
-  /* The DOS partition type.  */
-  int dos_type;
-
-  /* The BSD partition type.  */
-  int bsd_type;
-
-  /* The offset of the extended partition.  */
-  unsigned long ext_offset;
-};
 
 static inline int
 grub_pc_partition_is_empty (int type)
@@ -200,12 +114,4 @@ grub_pc_partition_is_extended (int type)
 	  || type == GRUB_PC_PARTITION_TYPE_LINUX_EXTENDED);
 }
 
-static inline int
-grub_pc_partition_is_bsd (int type)
-{
-  return (type == GRUB_PC_PARTITION_TYPE_FREEBSD
-	  || type == GRUB_PC_PARTITION_TYPE_OPENBSD
-	  || type == GRUB_PC_PARTITION_TYPE_NETBSD);
-}
-
 #endif /* ! GRUB_PC_PARTITION_HEADER */
diff --git a/kern/disk.c b/kern/disk.c
index e463626..657ac8d 100644
--- a/kern/disk.c
+++ b/kern/disk.c
@@ -330,6 +330,7 @@ grub_disk_open (const char *name)
 void
 grub_disk_close (grub_disk_t disk)
 {
+  grub_partition_t part;
   grub_dprintf ("disk", "Closing `%s'.\n", disk->name);
 
   if (disk->dev && disk->dev->close)
@@ -338,7 +339,13 @@ grub_disk_close (grub_disk_t disk)
   /* Reset the timer.  */
   grub_last_time = grub_get_time_ms ();
 
-  grub_free (disk->partition);
+  while (disk->partition)
+    {
+      part = disk->partition->parent;
+      grub_free (disk->partition->data);
+      grub_free (disk->partition);
+      disk->partition = part;
+    }
   grub_free ((void *) disk->name);
   grub_free (disk);
 }
@@ -349,18 +356,19 @@ grub_disk_close (grub_disk_t disk)
    - Verify that the range is inside the partition.  */
 static grub_err_t
 grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
-		       grub_off_t *offset, grub_size_t size)
+			grub_off_t *offset, grub_size_t size)
 {
+  grub_partition_t part;
   *sector += *offset >> GRUB_DISK_SECTOR_BITS;
   *offset &= GRUB_DISK_SECTOR_SIZE - 1;
 
-  if (disk->partition)
+  for (part = disk->partition; part; part = part->parent)
     {
       grub_disk_addr_t start;
       grub_uint64_t len;
 
-      start = grub_partition_get_start (disk->partition);
-      len = grub_partition_get_len (disk->partition);
+      start = part->start;
+      len = part->len;
 
       if (*sector >= len
 	  || len - *sector < ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
diff --git a/kern/partition.c b/kern/partition.c
index 4d5c63a..4bcd8c7 100644
--- a/kern/partition.c
+++ b/kern/partition.c
@@ -17,6 +17,7 @@
  */
 
 #include <grub/misc.h>
+#include <grub/mm.h>
 #include <grub/partition.h>
 #include <grub/disk.h>
 
@@ -54,17 +55,58 @@ grub_partition_map_iterate (int (*hook) (const grub_partition_map_t partmap))
   return 0;
 }
 
+static grub_partition_t
+grub_partition_map_probe (const grub_partition_map_t partmap,
+			  grub_disk_t disk, int partnum)
+{
+  grub_partition_t p = 0;
+
+  auto int find_func (grub_disk_t d, const grub_partition_t partition);
+
+  int find_func (grub_disk_t d __attribute__ ((unused)),
+		 const grub_partition_t partition)
+    {
+      if (partnum == partition->number)
+	{
+	  p = (grub_partition_t) grub_malloc (sizeof (*p));
+	  if (! p)
+	    return 1;
+
+	  grub_memcpy (p, partition, sizeof (*p));
+	  return 1;
+	}
+
+      return 0;
+    }
+
+  partmap->iterate (disk, find_func);
+  if (grub_errno)
+    goto fail;
+
+  return p;
+
+ fail:
+  grub_free (p);
+  return 0;
+}
+
 grub_partition_t
 grub_partition_probe (struct grub_disk *disk, const char *str)
 {
   grub_partition_t part = 0;
+  grub_partition_t curpart = 0;
+  grub_partition_t tail;
+  const char *ptr;
+  int num;
 
   auto int part_map_probe (const grub_partition_map_t partmap);
 
   int part_map_probe (const grub_partition_map_t partmap)
     {
-      part = partmap->probe (disk, str);
-      if (part)
+      disk->partition = part;
+      curpart = grub_partition_map_probe (partmap, disk, num);
+      disk->partition = tail;
+      if (curpart)
 	return 1;
 
       if (grub_errno == GRUB_ERR_BAD_PART_TABLE)
@@ -77,27 +119,54 @@ grub_partition_probe (struct grub_disk *disk, const char *str)
       return 1;
     }
 
-  /* Use the first partition map type found.  */
-  grub_partition_map_iterate (part_map_probe);
+  part = tail = disk->partition;
+
+  for (ptr = str; *ptr;)
+    {
+      /* BSD-like partition specification.  */
+      if (*ptr >= 'a' && *ptr <= 'z')
+	num = *(ptr++) - 'a';
+      else
+	num = grub_strtoul (ptr, (char **) &ptr, 0) - 1;
+
+      curpart = 0;
+      /* Use the first partition map type found.  */
+      grub_partition_map_iterate (part_map_probe);
+
+      if (! curpart)
+	{
+	  while (part)
+	    {
+	      curpart = part->parent;
+	      grub_free (part);
+	      part = curpart;
+	    }
+	  return 0;
+	}
+      curpart->parent = part;
+      part = curpart;
+      if (! ptr || *ptr != ',')
+	break;
+      ptr++;
+    }
 
   return part;
 }
 
-int
-grub_partition_iterate (struct grub_disk *disk,
-			int (*hook) (grub_disk_t disk,
-				     const grub_partition_t partition))
+static grub_partition_map_t
+get_partmap (struct grub_disk *disk)
 {
   grub_partition_map_t partmap = 0;
-  int ret = 0;
-
+  struct grub_partition part;
+  int found = 0;
   auto int part_map_iterate (const grub_partition_map_t p);
   auto int part_map_iterate_hook (grub_disk_t d,
 				  const grub_partition_t partition);
-
   int part_map_iterate_hook (grub_disk_t d __attribute__ ((unused)),
-			     const grub_partition_t partition __attribute__ ((unused)))
+			     const grub_partition_t partition)
     {
+      found = 1;
+      part = *partition;
       return 1;
     }
 
@@ -106,22 +175,58 @@ grub_partition_iterate (struct grub_disk *disk,
       grub_dprintf ("partition", "Detecting %s...\n", p->name);
       p->iterate (disk, part_map_iterate_hook);
 
-      if (grub_errno != GRUB_ERR_NONE)
+      if (grub_errno != GRUB_ERR_NONE || ! found)
 	{
 	  /* Continue to next partition map type.  */
 	  grub_dprintf ("partition", "%s detection failed.\n", p->name);
 	  grub_errno = GRUB_ERR_NONE;
 	  return 0;
 	}
+      grub_free (part.data);
 
       grub_dprintf ("partition", "%s detection succeeded.\n", p->name);
       partmap = p;
       return 1;
     }
-
   grub_partition_map_iterate (part_map_iterate);
-  if (partmap)
-    ret = partmap->iterate (disk, hook);
+  return partmap;
+}
+
+int
+grub_partition_iterate (struct grub_disk *disk,
+			int (*hook) (grub_disk_t disk,
+				     const grub_partition_t partition))
+{
+  int ret = 0;
+
+  auto int part_iterate (grub_disk_t dsk, const grub_partition_t p);
+
+  int part_iterate (grub_disk_t dsk,
+		    const grub_partition_t partition)
+    {
+      struct grub_partition p = *partition;
+      grub_partition_map_t partmap = 0;
+      p.parent = dsk->partition;
+      dsk->partition = 0;
+      if (hook (dsk, &p))
+	  return 1;
+      if (p.start != 0)
+	{
+	  dsk->partition = &p;
+	  partmap = get_partmap (dsk);
+	  if (partmap)
+	    ret = partmap->iterate (dsk, part_iterate);
+	}
+      dsk->partition = p.parent;
+      return ret;
+    }
+
+  {
+    grub_partition_map_t partmap = 0;
+    partmap = get_partmap (disk);
+    if (partmap)
+      ret = partmap->iterate (disk, part_iterate);
+  }
 
   return ret;
 }
@@ -129,5 +234,30 @@ grub_partition_iterate (struct grub_disk *disk,
 char *
 grub_partition_get_name (const grub_partition_t partition)
 {
-  return partition->partmap->get_name (partition);
+  char *out = 0;
+  /* Even on 64-bit machines this buffer is enough to hold longest number.  */
+  char buf[25];
+  int curlen = 0;
+  grub_partition_t part;
+  for (part = partition; part; part = part->parent)
+    {
+      int strl;
+      grub_sprintf (buf, "%d", part->number + 1);
+      strl = grub_strlen (buf);
+      if (curlen)
+	{
+	  out = grub_realloc (out, curlen + strl + 2);
+	  grub_memcpy (out + strl + 1, out, curlen);
+	  out[curlen + 1 + strl] = 0;
+	  grub_memcpy (out, buf, strl);
+	  out[strl] = ',';
+	  curlen = curlen + 1 + strl;
+	}
+      else
+	{
+	  curlen = strl;
+	  out = grub_strdup (buf);
+	}
+    }
+  return out;
 }
diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c
index 5badb79..7451dbf 100644
--- a/loader/i386/bsd.c
+++ b/loader/i386/bsd.c
@@ -86,7 +86,6 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
 		     grub_uint32_t * unit,
 		     grub_uint32_t * slice, grub_uint32_t * part)
 {
-  char *p;
   grub_device_t dev; 
 
   *biosdev = grub_get_root_biosnumber () & 0xff;
@@ -96,21 +95,13 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-
-      p = dev->disk->partition->partmap->get_name (dev->disk->partition);
-      if (p)
+      if (dev->disk->partition->parent)
 	{
-	  if ((p[0] >= '0') && (p[0] <= '9'))
-	    {
-	      *slice = grub_strtoul (p, &p, 0);
-
-	      if ((p) && (p[0] == ','))
-		p++;
-	    }
-
-	  if ((p[0] >= 'a') && (p[0] <= 'z'))
-	    *part = p[0] - 'a';
+	  *part = dev->disk->partition->number;
+	  *slice = dev->disk->partition->parent->number + 1;
 	}
+      else
+	*slice = dev->disk->partition->number + 1;
     }
   if (dev)
     grub_device_close (dev);
diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c
index 8c3139b..719a51d 100644
--- a/loader/i386/multiboot.c
+++ b/loader/i386/multiboot.c
@@ -155,7 +155,6 @@ static int
 grub_multiboot_get_bootdev (grub_uint32_t *bootdev)
 {
 #ifdef GRUB_MACHINE_PCBIOS
-  char *p;
   grub_uint32_t biosdev, slice = ~0, part = ~0;
   grub_device_t dev;
 
@@ -164,21 +163,13 @@ grub_multiboot_get_bootdev (grub_uint32_t *bootdev)
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-
-      p = dev->disk->partition->partmap->get_name (dev->disk->partition);
-      if (p)
+      if (dev->disk->partition->parent)
 	{
-	  if ((p[0] >= '0') && (p[0] <= '9'))
-	    {
-	      slice = grub_strtoul (p, &p, 0) - 1;
-
-	      if ((p) && (p[0] == ','))
-		p++;
-	    }
-
-	  if ((p[0] >= 'a') && (p[0] <= 'z'))
-	    part = p[0] - 'a';
+	  part = dev->disk->partition->number;
+	  slice = dev->disk->partition->parent->number;
 	}
+      else
+	slice = dev->disk->partition->number;
     }
   if (dev)
     grub_device_close (dev);
diff --git a/loader/i386/pc/chainloader.c b/loader/i386/pc/chainloader.c
index caf1450..79bc290 100644
--- a/loader/i386/pc/chainloader.c
+++ b/loader/i386/pc/chainloader.c
@@ -31,6 +31,7 @@
 #include <grub/machine/memory.h>
 #include <grub/dl.h>
 #include <grub/command.h>
+#include <grub/pc_partition.h>
 #include <grub/machine/biosnum.h>
 
 static grub_dl_t my_mod;
@@ -94,10 +95,22 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-      grub_disk_read (dev->disk, dev->disk->partition->offset, 446, 64,
-		      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
-      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
-			    + (dev->disk->partition->index << 4));
+      grub_disk_t disk = dev->disk;
+
+      if (disk)
+	{
+	  grub_partition_t p = disk->partition;
+
+	  if (p && grub_strcmp (p->partmap->name, "pc_partition_map") == 0)
+	    {
+	      disk->partition = p->parent;
+	      grub_disk_read (disk, p->offset, 446, 64,
+			      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
+	      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
+				    + (p->index << 4));
+	      disk->partition = p;
+	    }
+	}
     }
 
   if (dev)
diff --git a/partmap/acorn.c b/partmap/acorn.c
index 42fd61f..8443554 100644
--- a/partmap/acorn.c
+++ b/partmap/acorn.c
@@ -96,21 +96,17 @@ acorn_partition_map_iterate (grub_disk_t disk,
 					  const grub_partition_t partition))
 {
   struct grub_partition part;
-  struct grub_disk raw;
   struct linux_part map[LINUX_MAP_ENTRIES];
   int i;
-  grub_disk_addr_t sector;
+  grub_disk_addr_t sector = 0;
   grub_err_t err;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
-  err = acorn_partition_map_find (&raw, map, &sector);
+  err = acorn_partition_map_find (disk, map, &sector);
   if (err)
     return err;
 
   part.partmap = &grub_acorn_partition_map;
+  part.data = 0;
 
   for (i = 0; i != LINUX_MAP_ENTRIES; ++i)
     {
@@ -121,7 +117,7 @@ acorn_partition_map_iterate (grub_disk_t disk,
       part.start = sector + map[i].start;
       part.len = map[i].size;
       part.offset = 6;
-      part.index = i;
+      part.number = part.index = i;
 
       if (hook (disk, &part))
 	return grub_errno;
@@ -130,60 +126,6 @@ acorn_partition_map_iterate (grub_disk_t disk,
   return GRUB_ERR_NONE;
 }
 
-
-static grub_partition_t
-acorn_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  struct linux_part map[LINUX_MAP_ENTRIES];
-  struct grub_disk raw = *disk;
-  unsigned long partnum = grub_strtoul (str, 0, 10) - 1;
-  grub_disk_addr_t sector;
-  grub_err_t err;
-  grub_partition_t p;
-
-  /* Enforce raw disk access.  */
-  raw.partition = 0;
-
-  /* Get the partition number.  */
-  if (partnum > LINUX_MAP_ENTRIES)
-    goto fail;
-
-  err = acorn_partition_map_find (&raw, map, &sector);
-  if (err)
-    return 0;
-
-  if (map[partnum].magic != LINUX_NATIVE_MAGIC
-      && map[partnum].magic != LINUX_SWAP_MAGIC)
-    goto fail;
-
-  p = grub_malloc (sizeof (struct grub_partition));
-  if (! p)
-    return 0;
-
-  p->start = sector + map[partnum].start;
-  p->len = map[partnum].size;
-  p->offset = 6;
-  p->index = partnum;
-  return p;
-
-fail:
-  grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-  return 0;
-}
-
-
-static char *
-acorn_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
 \f
 
 /* Partition map type.  */
@@ -191,8 +133,6 @@ static struct grub_partition_map grub_acorn_partition_map =
 {
   .name = "Linux/ADFS partition map",
   .iterate = acorn_partition_map_iterate,
-  .probe = acorn_partition_map_probe,
-  .get_name = acorn_partition_map_get_name
 };
 
 GRUB_MOD_INIT(acorn_partition_map)
diff --git a/partmap/amiga.c b/partmap/amiga.c
index ffb807f..90cf525 100644
--- a/partmap/amiga.c
+++ b/partmap/amiga.c
@@ -76,20 +76,15 @@ amiga_partition_map_iterate (grub_disk_t disk,
 {
   struct grub_partition part;
   struct grub_amiga_rdsk rdsk;
-  struct grub_disk raw;
   int partno = 0;
   int next = -1;
   unsigned pos;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   /* The RDSK block is one of the first 15 blocks.  */
   for (pos = 0; pos < 15; pos++)
     {
       /* Read the RDSK block which is a descriptor for the entire disk.  */
-      if (grub_disk_read (&raw, pos, 0, sizeof (rdsk), &rdsk))
+      if (grub_disk_read (disk, pos, 0, sizeof (rdsk), &rdsk))
 	return grub_errno;
 
       if (grub_strcmp ((char *) rdsk.magic, "RDSK") == 0)
@@ -104,13 +99,15 @@ amiga_partition_map_iterate (grub_disk_t disk,
     return grub_error (GRUB_ERR_BAD_PART_TABLE,
 		       "Amiga partition map not found.");
 
+  part.data = 0;
+
   /* The end of the partition list is marked using "-1".  */
   while (next != -1)
     {
       struct grub_amiga_partition apart;
 
       /* Read the RDSK block which is a descriptor for the entire disk.  */
-      if (grub_disk_read (&raw, next, 0, sizeof (apart), &apart))
+      if (grub_disk_read (disk, next, 0, sizeof (apart), &apart))
 	return grub_errno;
 
       /* Calculate the first block and the size of the partition.  */
@@ -123,7 +120,8 @@ amiga_partition_map_iterate (grub_disk_t disk,
 		  * grub_be_to_cpu32 (apart.block_per_track));
 
       part.offset = (grub_off_t) next * 512;
-      part.index = partno;
+      part.number = partno;
+      part.index = 0;
       part.partmap = &grub_amiga_partition_map;
 
       if (hook (disk, &part))
@@ -136,72 +134,12 @@ amiga_partition_map_iterate (grub_disk_t disk,
   return 0;
 }
 
-
-static grub_partition_t
-amiga_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  if (amiga_partition_map_iterate (disk, find_func))
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-amiga_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_amiga_partition_map =
   {
     .name = "amiga_partition_map",
     .iterate = amiga_partition_map_iterate,
-    .probe = amiga_partition_map_probe,
-    .get_name = amiga_partition_map_get_name
   };
 
 GRUB_MOD_INIT(amiga_partition_map)
diff --git a/partmap/apple.c b/partmap/apple.c
index 04ccff1..e1b5bff 100644
--- a/partmap/apple.c
+++ b/partmap/apple.c
@@ -105,17 +105,12 @@ apple_partition_map_iterate (grub_disk_t disk,
   struct grub_partition part;
   struct grub_apple_header aheader;
   struct grub_apple_part apart;
-  struct grub_disk raw;
   int partno = 0, partnum = 0;
   unsigned pos;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   part.partmap = &grub_apple_partition_map;
 
-  if (grub_disk_read (&raw, 0, 0, sizeof (aheader), &aheader))
+  if (grub_disk_read (disk, 0, 0, sizeof (aheader), &aheader))
     return grub_errno;
 
   if (grub_be_to_cpu16 (aheader.magic) != GRUB_APPLE_HEADER_MAGIC)
@@ -127,14 +122,17 @@ apple_partition_map_iterate (grub_disk_t disk,
       goto fail;
     }
 
+  part.data = 0;
   pos = grub_be_to_cpu16 (aheader.blocksize);
 
   do
     {
-      if (grub_disk_read (&raw, pos / GRUB_DISK_SECTOR_SIZE,
-			  pos % GRUB_DISK_SECTOR_SIZE,
-			  sizeof (struct grub_apple_part),  &apart))
-	return grub_errno;
+       part.offset = pos / GRUB_DISK_SECTOR_SIZE;
+       part.index = pos % GRUB_DISK_SECTOR_SIZE;
+
+       if (grub_disk_read (disk, part.offset, part.index,
+			   sizeof (struct grub_apple_part),  &apart))
+	 return grub_errno;
 
       if (grub_be_to_cpu16 (apart.magic) != GRUB_APPLE_PART_MAGIC)
 	{
@@ -156,6 +154,7 @@ apple_partition_map_iterate (grub_disk_t disk,
 	/ GRUB_DISK_SECTOR_SIZE;
       part.offset = pos;
       part.index = partno;
+      part.number = partno;
 
       grub_dprintf ("partition",
 		    "partition %d: name %s, type %s, start 0x%x, len 0x%x\n",
@@ -179,72 +178,12 @@ apple_partition_map_iterate (grub_disk_t disk,
 		     "Apple partition map not found.");
 }
 
-
-static grub_partition_t
-apple_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  if (apple_partition_map_iterate (disk, find_func))
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-apple_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_apple_partition_map =
   {
     .name = "apple_partition_map",
     .iterate = apple_partition_map_iterate,
-    .probe = apple_partition_map_probe,
-    .get_name = apple_partition_map_get_name
   };
 
 GRUB_MOD_INIT(apple_partition_map)
diff --git a/partmap/bsdlabel.c b/partmap/bsdlabel.c
new file mode 100644
index 0000000..f376dce
--- /dev/null
+++ b/partmap/bsdlabel.c
@@ -0,0 +1,87 @@
+/* bsdlabel.c - Read BSD style partition tables.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2004,2005,2006,2007,2008,2009  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/partition.h>
+#include <grub/bsdlabel.h>
+#include <grub/disk.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/dl.h>
+
+static struct grub_partition_map grub_bsdlabel_partition_map;
+\f
+
+static grub_err_t
+bsdlabel_partition_map_iterate (grub_disk_t disk,
+			  int (*hook) (grub_disk_t disk,
+				       const grub_partition_t partition))
+{
+  struct grub_pc_partition_disk_label label;
+  struct grub_partition p;
+  grub_disk_addr_t delta = 0;
+
+  /* BSDLabel offsets are absolute even when it's embed inside partition.  */
+  delta = grub_partition_get_start (disk->partition);
+
+  /* Read the BSD label.  */
+  if (grub_disk_read (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR,
+		      0, sizeof (label), &label))
+    goto finish;
+
+  /* Check if it is valid.  */
+  if (label.magic != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
+    return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
+  for (p.number = 0;
+       p.number < grub_cpu_to_le16 (label.num_partitions);
+       p.number++)
+    {
+      struct grub_pc_partition_bsd_entry *be
+	= label.entries + p.number;
+
+      p.start = grub_le_to_cpu32 (be->offset) - delta;
+      p.len = grub_le_to_cpu32 (be->size);
+      p.offset = GRUB_PC_PARTITION_BSD_LABEL_SECTOR;
+      p.partmap = &grub_bsdlabel_partition_map;
+      p.index = p.number;
+
+      if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
+	if (hook (disk, &p))
+	  return 1;
+    }
+ finish:
+  return grub_errno;
+}
+
+\f
+/* Partition map type.  */
+static struct grub_partition_map grub_bsdlabel_partition_map =
+  {
+    .name = "bsdlabel_partition_map",
+    .iterate = bsdlabel_partition_map_iterate,
+  };
+
+GRUB_MOD_INIT(bsdlabel_partition_map)
+{
+  grub_partition_map_register (&grub_bsdlabel_partition_map);
+}
+
+GRUB_MOD_FINI(bsdlabel_partition_map)
+{
+  grub_partition_map_unregister (&grub_bsdlabel_partition_map);
+}
diff --git a/partmap/gpt.c b/partmap/gpt.c
index d646d41..041d6be 100644
--- a/partmap/gpt.c
+++ b/partmap/gpt.c
@@ -44,18 +44,13 @@ gpt_partition_map_iterate (grub_disk_t disk,
   struct grub_partition part;
   struct grub_gpt_header gpt;
   struct grub_gpt_partentry entry;
-  struct grub_disk raw;
   struct grub_pc_partition_mbr mbr;
   grub_uint64_t entries;
   unsigned int i;
   int last_offset = 0;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   /* Read the protective MBR.  */
-  if (grub_disk_read (&raw, 0, 0, sizeof (mbr), &mbr))
+  if (grub_disk_read (disk, 0, 0, sizeof (mbr), &mbr))
     return grub_errno;
 
   /* Check if it is valid.  */
@@ -67,7 +62,7 @@ gpt_partition_map_iterate (grub_disk_t disk,
     return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
 
   /* Read the GPT header.  */
-  if (grub_disk_read (&raw, 1, 0, sizeof (gpt), &gpt))
+  if (grub_disk_read (disk, 1, 0, sizeof (gpt), &gpt))
     return grub_errno;
 
   if (grub_memcmp (gpt.magic, grub_gpt_magic, sizeof (grub_gpt_magic)))
@@ -76,11 +71,15 @@ gpt_partition_map_iterate (grub_disk_t disk,
   grub_dprintf ("gpt", "Read a valid GPT header\n");
 
   entries = grub_le_to_cpu64 (gpt.partitions);
+  part.data = grub_malloc (sizeof (entry));
   for (i = 0; i < grub_le_to_cpu32 (gpt.maxpart); i++)
     {
-      if (grub_disk_read (&raw, entries, last_offset,
+      if (grub_disk_read (disk, entries, last_offset,
 			  sizeof (entry), &entry))
-	return grub_errno;
+	{
+	  grub_free (part.data);
+	  return grub_errno;
+	}
 
       if (grub_memcmp (&grub_gpt_partition_type_empty, &entry.type,
 		       sizeof (grub_gpt_partition_type_empty)))
@@ -90,9 +89,10 @@ gpt_partition_map_iterate (grub_disk_t disk,
 	  part.len = (grub_le_to_cpu64 (entry.end)
 		      - grub_le_to_cpu64 (entry.start) + 1);
 	  part.offset = entries;
-	  part.index = i;
+	  part.number = i;
+	  part.index = last_offset;
 	  part.partmap = &grub_gpt_partition_map;
-	  part.data = &entry;
+	  grub_memcpy (part.data, &entry, sizeof (entry));
 
 	  grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", i,
 			(unsigned long long) part.start,
@@ -109,77 +109,17 @@ gpt_partition_map_iterate (grub_disk_t disk,
 	  entries++;
 	}
     }
+  grub_free (part.data);
 
   return 0;
 }
 
-
-static grub_partition_t
-gpt_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  gpt_partition_map_iterate (disk, find_func);
-  if (grub_errno)
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-gpt_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_gpt_partition_map =
   {
     .name = "gpt_partition_map",
     .iterate = gpt_partition_map_iterate,
-    .probe = gpt_partition_map_probe,
-    .get_name = gpt_partition_map_get_name
   };
 
 GRUB_MOD_INIT(gpt_partition_map)
diff --git a/partmap/pc.c b/partmap/pc.c
index 6a2efd2..cb56c9b 100644
--- a/partmap/pc.c
+++ b/partmap/pc.c
@@ -27,85 +27,19 @@
 static struct grub_partition_map grub_pc_partition_map;
 \f
 
-/* Parse the partition representation in STR and return a partition.  */
-static grub_partition_t
-grub_partition_parse (const char *str)
-{
-  grub_partition_t p;
-  struct grub_pc_partition *pcdata;
-
-  char *s = (char *) str;
-
-  p = (grub_partition_t) grub_malloc (sizeof (*p));
-  if (! p)
-    return 0;
-
-  pcdata = (struct grub_pc_partition *) grub_malloc (sizeof (*pcdata));
-  if (! pcdata)
-    goto fail;
-
-  p->data = pcdata;
-  p->partmap = &grub_pc_partition_map;
-
-  /* Initialize some of the fields with invalid values.  */
-  pcdata->bsd_part = pcdata->dos_type = pcdata->bsd_type = p->index = -1;
-
-  /* Get the DOS partition number. The number is counted from one for
-     the user interface, and from zero internally.  */
-  pcdata->dos_part = grub_strtoul (s, &s, 0) - 1;
-
-  if (grub_errno)
-    {
-      /* Not found. Maybe only a BSD label is specified.  */
-      pcdata->dos_part = -1;
-      grub_errno = GRUB_ERR_NONE;
-    }
-  else if (*s == ',')
-    s++;
-
-  if (*s)
-    {
-      if (*s >= 'a' && *s <= 'h')
-	{
-	  pcdata->bsd_part = *s - 'a';
-	  s++;
-	}
-
-      if (*s)
-	goto fail;
-    }
-
-  if (pcdata->dos_part == -1 && pcdata->bsd_part == -1)
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  grub_free (pcdata);
-  grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-  return 0;
-}
-
 static grub_err_t
 pc_partition_map_iterate (grub_disk_t disk,
 			  int (*hook) (grub_disk_t disk,
 				       const grub_partition_t partition))
 {
   struct grub_partition p;
-  struct grub_pc_partition pcdata;
   struct grub_pc_partition_mbr mbr;
-  struct grub_pc_partition_disk_label label;
-  struct grub_disk raw;
-
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
+  grub_disk_addr_t ext_offset;
 
   p.offset = 0;
-  pcdata.ext_offset = 0;
-  pcdata.dos_part = -1;
-  p.data = &pcdata;
+  ext_offset = 0;
+  p.data = 0;
+  p.number = -1;
   p.partmap = &grub_pc_partition_map;
 
   while (1)
@@ -114,7 +48,7 @@ pc_partition_map_iterate (grub_disk_t disk,
       struct grub_pc_partition_entry *e;
 
       /* Read the MBR.  */
-      if (grub_disk_read (&raw, p.offset, 0, sizeof (mbr), &mbr))
+      if (grub_disk_read (disk, p.offset, 0, sizeof (mbr), &mbr))
 	goto finish;
 
       /* Check if it is valid.  */
@@ -132,13 +66,10 @@ pc_partition_map_iterate (grub_disk_t disk,
 
 	  p.start = p.offset + grub_le_to_cpu32 (e->start);
 	  p.len = grub_le_to_cpu32 (e->length);
-	  pcdata.bsd_part = -1;
-	  pcdata.dos_type = e->type;
-	  pcdata.bsd_type = -1;
 
 	  grub_dprintf ("partition",
 			"partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n",
-			p.index, e->flag, pcdata.dos_type,
+			p.index, e->flag, e->type,
 			(unsigned long long) p.start,
 			(unsigned long long) p.len);
 
@@ -150,59 +81,15 @@ pc_partition_map_iterate (grub_disk_t disk,
 	  if (! grub_pc_partition_is_empty (e->type)
 	      && ! grub_pc_partition_is_extended (e->type))
 	    {
-	      pcdata.dos_part++;
+	      p.number++;
 
 	      if (hook (disk, &p))
 		return 1;
-
-	      /* Check if this is a BSD partition.  */
-	      if (grub_pc_partition_is_bsd (e->type))
-		{
-		  /* Check if the BSD label is within the DOS partition.  */
-		  if (p.len <= GRUB_PC_PARTITION_BSD_LABEL_SECTOR)
-		    {
-		      grub_dprintf ("partition", "no space for disk label\n");
-		      continue;
-		    }
-		  /* Read the BSD label.  */
-		  if (grub_disk_read (&raw,
-				      (p.start
-				       + GRUB_PC_PARTITION_BSD_LABEL_SECTOR),
-				      0,
-				      sizeof (label),
-				      &label))
-		    goto finish;
-
-		  /* Check if it is valid.  */
-		  if (label.magic
-		      != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
-		    {
-		      grub_dprintf ("partition",
-				    "invalid disk label magic 0x%x on partition %d\n",
-				    label.magic, p.index);
-		      continue;
-		    }
-		  for (pcdata.bsd_part = 0;
-		       pcdata.bsd_part < grub_cpu_to_le16 (label.num_partitions);
-		       pcdata.bsd_part++)
-		    {
-		      struct grub_pc_partition_bsd_entry *be
-			= label.entries + pcdata.bsd_part;
-
-		      p.start = grub_le_to_cpu32 (be->offset);
-		      p.len = grub_le_to_cpu32 (be->size);
-		      pcdata.bsd_type = be->fs_type;
-
-		      if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
-			if (hook (disk, &p))
-			  return 1;
-		    }
-		}
 	    }
-	  else if (pcdata.dos_part < 4)
+	  else if (p.number < 4)
 	    /* If this partition is a logical one, shouldn't increase the
 	       partition number.  */
-	    pcdata.dos_part++;
+	    p.number++;
 	}
 
       /* Find an extended partition.  */
@@ -212,9 +99,9 @@ pc_partition_map_iterate (grub_disk_t disk,
 
 	  if (grub_pc_partition_is_extended (e->type))
 	    {
-	      p.offset = pcdata.ext_offset + grub_le_to_cpu32 (e->start);
-	      if (! pcdata.ext_offset)
-		pcdata.ext_offset = p.offset;
+	      p.offset = ext_offset + grub_le_to_cpu32 (e->start);
+	      if (! ext_offset)
+		ext_offset = p.offset;
 
 	      break;
 	    }
@@ -229,84 +116,12 @@ pc_partition_map_iterate (grub_disk_t disk,
   return grub_errno;
 }
 
-
-static grub_partition_t
-pc_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p;
-  struct grub_pc_partition *pcdata;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      struct grub_pc_partition *partdata = partition->data;
-
-      if ((pcdata->dos_part == partdata->dos_part || pcdata->dos_part == -1)
-	  && pcdata->bsd_part == partdata->bsd_part)
-	{
-	  grub_memcpy (p, partition, sizeof (*p));
-	  p->data = pcdata;
-	  grub_memcpy (pcdata, partdata, sizeof (*pcdata));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  p = grub_partition_parse (str);
-  if (! p)
-    return 0;
-
-  pcdata = p->data;
-  pc_partition_map_iterate (disk, find_func);
-  if (grub_errno)
-    goto fail;
-
-  if (p->index < 0)
-    {
-      grub_error (GRUB_ERR_BAD_DEVICE, "no such partition");
-      goto fail;
-    }
-
-  return p;
-
- fail:
-  grub_free (p);
-  grub_free (pcdata);
-  return 0;
-}
-
-
-static char *
-pc_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-  struct grub_pc_partition *pcdata = p->data;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  if (pcdata->bsd_part < 0)
-    grub_sprintf (name, "%d", pcdata->dos_part + 1);
-  else if (pcdata->dos_part < 0)
-    grub_sprintf (name, "%c", pcdata->bsd_part + 'a');
-  else
-    grub_sprintf (name, "%d,%c", pcdata->dos_part + 1, pcdata->bsd_part + 'a');
-
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_pc_partition_map =
   {
     .name = "pc_partition_map",
     .iterate = pc_partition_map_iterate,
-    .probe = pc_partition_map_probe,
-    .get_name = pc_partition_map_get_name
   };
 
 GRUB_MOD_INIT(pc_partition_map)
diff --git a/partmap/sun.c b/partmap/sun.c
index ce6d588..63ba6ae 100644
--- a/partmap/sun.c
+++ b/partmap/sun.c
@@ -88,19 +88,15 @@ sun_partition_map_iterate (grub_disk_t disk,
 					const grub_partition_t partition))
 {
   grub_partition_t p;
-  struct grub_disk raw;
   struct grub_sun_block block;
   int partnum;
 
-  raw = *disk;
-  raw.partition = 0;
-
   p = (grub_partition_t) grub_zalloc (sizeof (struct grub_partition));
   if (! p)
     return grub_errno;
 
   p->partmap = &grub_sun_partition_map;
-  if (grub_disk_read (&raw, 0, 0, sizeof (struct grub_sun_block),
+  if (grub_disk_read (disk, 0, 0, sizeof (struct grub_sun_block),
 		      &block) == GRUB_ERR_NONE)
     {
       if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.magic))
@@ -124,7 +120,7 @@ sun_partition_map_iterate (grub_disk_t disk,
 		      * grub_be_to_cpu16 (block.ntrks)
 		      * grub_be_to_cpu16 (block.nsect));
 	  p->len = grub_be_to_cpu32 (desc->num_sectors);
-	  p->index = partnum;
+	  p->number = p->index = partnum;
 	  if (p->len)
 	    {
 	      if (hook (disk, p))
@@ -138,68 +134,11 @@ sun_partition_map_iterate (grub_disk_t disk,
   return grub_errno;
 }
 
-static grub_partition_t
-sun_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-        {
-          p = (grub_partition_t) grub_malloc (sizeof (*p));
-          if (p)
-            grub_memcpy (p, partition, sizeof (*p));
-
-          return 1;
-        }
-
-      return 0;
-    }
-
-  grub_errno = GRUB_ERR_NONE;
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno == GRUB_ERR_NONE)
-    {
-      if (sun_partition_map_iterate (disk, find_func))
-        {
-          grub_free (p);
-          p = 0;
-        }
-    }
-  else
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      p = 0;
-    }
-
-  return p;
-}
-
-static char *
-sun_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (name)
-    grub_sprintf (name, "%d", p->index + 1);
-
-  return name;
-}
-
 /* Partition map type.  */
 static struct grub_partition_map grub_sun_partition_map =
   {
     .name = "sun_partition_map",
     .iterate = sun_partition_map_iterate,
-    .probe = sun_partition_map_probe,
-    .get_name = sun_partition_map_get_name
   };
 
 GRUB_MOD_INIT(sun_partition_map)
diff --git a/parttool/pcpart.c b/parttool/pcpart.c
index 6876d0d..da4d921 100644
--- a/parttool/pcpart.c
+++ b/parttool/pcpart.c
@@ -49,7 +49,7 @@ static grub_err_t grub_pcpart_boot (const grub_device_t dev,
 
   index = dev->disk->partition->index;
   part = dev->disk->partition;
-  dev->disk->partition = 0;
+  dev->disk->partition = part->parent;
 
   /* Read the MBR.  */
   if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr))
@@ -96,7 +96,7 @@ static grub_err_t grub_pcpart_type (const grub_device_t dev,
 
   index = dev->disk->partition->index;
   part = dev->disk->partition;
-  dev->disk->partition = 0;
+  dev->disk->partition = part->parent;
 
   /* Read the parttable.  */
   if (grub_disk_read (dev->disk, part->offset, 0,
diff --git a/util/hostdisk.c b/util/hostdisk.c
index fdf3514..ca57893 100644
--- a/util/hostdisk.c
+++ b/util/hostdisk.c
@@ -333,10 +333,13 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
   {
     int is_partition = 0;
     char dev[PATH_MAX];
+    grub_disk_addr_t part_start = 0;
+
+    part_start = grub_partition_get_start (disk->partition);
 
     strcpy (dev, map[disk->id].device);
     if (disk->partition && strncmp (map[disk->id].device, "/dev/", 5) == 0)
-      is_partition = linux_find_partition (dev, disk->partition->start);
+      is_partition = linux_find_partition (dev, part_start);
 
     /* Open the partition.  */
     grub_dprintf ("hostdisk", "opening the device `%s' in open_device()", dev);
@@ -351,7 +354,7 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
     ioctl (fd, BLKFLSBUF, 0);
 
     if (is_partition)
-      sector -= disk->partition->start;
+      sector -= part_start;
   }
 #else /* ! __linux__ */
 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -947,39 +950,25 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
     int find_partition (grub_disk_t disk __attribute__ ((unused)),
 			const grub_partition_t partition)
       {
- 	struct grub_pc_partition *pcdata = NULL;
-
-	if (strcmp (partition->partmap->name, "pc_partition_map") == 0)
-	  pcdata = partition->data;
+	grub_disk_addr_t part_start = 0;
+	grub_util_info ("Partition %d starts from %lu",
+			partition->number, partition->start);
 
-	if (pcdata)
-	  {
-	    if (pcdata->bsd_part < 0)
-	      grub_util_info ("DOS partition %d starts from %lu",
-			      pcdata->dos_part, partition->start);
-	    else
-	      grub_util_info ("BSD partition %d,%c starts from %lu",
-			      pcdata->dos_part, pcdata->bsd_part + 'a',
-			      partition->start);
-	  }
-	else
-	  {
-	      grub_util_info ("Partition %d starts from %lu",
-			      partition->index, partition->start);
-	  }
+	part_start = grub_partition_get_start (partition);
 
-	if (hdg.start == partition->start)
+	if (hdg.start == part_start)
 	  {
-	    if (pcdata)
+	    if (partition->parent)
 	      {
-		dos_part = pcdata->dos_part;
-		bsd_part = pcdata->bsd_part;
+		dos_part = partition->parent->number;
+		bsd_part = partition->number;
 	      }
 	    else
 	      {
-		dos_part = partition->index;
+		dos_part = partition->number;
 		bsd_part = -1;
 	      }
+
 	    return 1;
 	  }
 
diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c
index 92c69ef..6572bb3 100644
--- a/util/i386/pc/grub-setup.c
+++ b/util/i386/pc/grub-setup.c
@@ -121,15 +121,10 @@ setup (const char *dir,
   int NESTED_FUNC_ATTR find_usable_region_msdos (grub_disk_t disk __attribute__ ((unused)),
 						 const grub_partition_t p)
     {
-      struct grub_pc_partition *pcdata = p->data;
-
       /* There's always an embed region, and it starts right after the MBR.  */
       embed_region.start = 1;
 
-      /* For its end offset, include as many dummy partitions as we can.  */
-      if (! grub_pc_partition_is_empty (pcdata->dos_type)
-	  && ! grub_pc_partition_is_bsd (pcdata->dos_type)
-	  && embed_region.end > p->start)
+      if (embed_region.end > p->start)
 	embed_region.end = p->start;
 
       return 0;
@@ -278,22 +273,19 @@ setup (const char *dir,
       /* Embed information about the installed location.  */
       if (root_dev->disk->partition)
 	{
-	  if (strcmp (root_dev->disk->partition->partmap->name,
-		      "pc_partition_map") == 0)
+	  if (root_dev->disk->partition->parent)
 	    {
-	      struct grub_pc_partition *pcdata =
-		root_dev->disk->partition->data;
-	      dos_part = pcdata->dos_part;
-	      bsd_part = pcdata->bsd_part;
+	      if (root_dev->disk->partition->parent->parent)
+		grub_util_error ("Installing on doubly nested partitiond is "
+				 "not supported");
+	      dos_part = root_dev->disk->partition->parent->number;
+	      bsd_part = root_dev->disk->partition->number;
 	    }
-	  else if (strcmp (root_dev->disk->partition->partmap->name,
-			   "gpt_partition_map") == 0)
+	  else
 	    {
-	      dos_part = root_dev->disk->partition->index;
+	      dos_part = root_dev->disk->partition->number;
 	      bsd_part = -1;
 	    }
-	  else
-	    grub_util_error ("No PC style partitions found");
 	}
       else
 	dos_part = bsd_part = -1;
@@ -326,6 +318,8 @@ setup (const char *dir,
   int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk __attribute__ ((unused)),
 					 const grub_partition_t p)
     {
+      if (p->parent)
+	return 0;
       dest_partmap = p->partmap->name;
       return 1;
     }

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-17 13:00             ` Vladimir 'phcoder' Serbinenko
@ 2009-08-17 14:06               ` Robert Millan
  2009-08-17 14:34                 ` Vladimir 'phcoder' Serbinenko
  0 siblings, 1 reply; 36+ messages in thread
From: Robert Millan @ 2009-08-17 14:06 UTC (permalink / raw)
  To: The development of GRUB 2

On Mon, Aug 17, 2009 at 03:00:52PM +0200, Vladimir 'phcoder' Serbinenko wrote:
> Rediff and few fixes

Please note that after what we discussed on IRC, we need to find a solution
that wouldn't make boot time increase linearly with the number of filesystems
or partmaps GRUB supports.

I really think supporting every sort of combination is too extreme.  For
example who would want an msdos/msdos chain?  OpenSolaris creates one, but
it's a false positive.

The overall idea *is* nice.  Some combinations (e.g. msdos/bsd) are cleaner
this way, but supporting everything doesn't scale well.

Perhaps we can explicitly list which combinations make sense?  So when an
msdos label is found, its partitions are probed for bsd labels too, but not
for msdos labels again, etc.

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-17 14:06               ` Robert Millan
@ 2009-08-17 14:34                 ` Vladimir 'phcoder' Serbinenko
  2009-08-23 22:57                   ` Vladimir 'phcoder' Serbinenko
  0 siblings, 1 reply; 36+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-08-17 14:34 UTC (permalink / raw)
  To: The development of GRUB 2

On Mon, Aug 17, 2009 at 4:06 PM, Robert Millan<rmh@aybabtu.com> wrote:
> On Mon, Aug 17, 2009 at 03:00:52PM +0200, Vladimir 'phcoder' Serbinenko wrote:
>> Rediff and few fixes
>
> Please note that after what we discussed on IRC, we need to find a solution
> that wouldn't make boot time increase linearly with the number of filesystems
> or partmaps GRUB supports.
>
It probe time scales linearly no matter what we do. Fortunately with
disk cache few first sectors are read and checked for different
signatures which is fast. As for module autoload with search patch it
doesn't happen except in the failure to access requested device.
> I really think supporting every sort of combination is too extreme.  For
> example who would want an msdos/msdos chain?  OpenSolaris creates one, but
> it's a false positive.
>
minix does it and it's not a false positive.
> The overall idea *is* nice.  Some combinations (e.g. msdos/bsd) are cleaner
> this way, but supporting everything doesn't scale well.
AFAIK no partmap goes beyond first 16K for signature checking. Time
for signature checking can be neglected and 16K would be read for
filesystem probe too. Additionally e.g. (hd0,1) is probed for
subpartitions only if (hd0,1,X) is requested or we're scanning through
partitions. In last case we're likely to fsprobe partition anyway so
it doesn't create any overhead
>
> Perhaps we can explicitly list which combinations make sense?  So when an
> msdos label is found, its partitions are probed for bsd labels too, but not
> for msdos labels again, etc.
>
> --
> Robert Millan
>
>  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
>  how) you may access your data; but nobody's threatening your freedom: we
>  still allow you to remove your data and not access it at all."
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>



-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-17 14:34                 ` Vladimir 'phcoder' Serbinenko
@ 2009-08-23 22:57                   ` Vladimir 'phcoder' Serbinenko
  2009-08-24 13:39                     ` Vladimir 'phcoder' Serbinenko
  0 siblings, 1 reply; 36+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-08-23 22:57 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 2393 bytes --]

Rediff
On Mon, Aug 17, 2009 at 4:34 PM, Vladimir 'phcoder'
Serbinenko<phcoder@gmail.com> wrote:
> On Mon, Aug 17, 2009 at 4:06 PM, Robert Millan<rmh@aybabtu.com> wrote:
>> On Mon, Aug 17, 2009 at 03:00:52PM +0200, Vladimir 'phcoder' Serbinenko wrote:
>>> Rediff and few fixes
>>
>> Please note that after what we discussed on IRC, we need to find a solution
>> that wouldn't make boot time increase linearly with the number of filesystems
>> or partmaps GRUB supports.
>>
> It probe time scales linearly no matter what we do. Fortunately with
> disk cache few first sectors are read and checked for different
> signatures which is fast. As for module autoload with search patch it
> doesn't happen except in the failure to access requested device.
>> I really think supporting every sort of combination is too extreme.  For
>> example who would want an msdos/msdos chain?  OpenSolaris creates one, but
>> it's a false positive.
>>
> minix does it and it's not a false positive.
>> The overall idea *is* nice.  Some combinations (e.g. msdos/bsd) are cleaner
>> this way, but supporting everything doesn't scale well.
> AFAIK no partmap goes beyond first 16K for signature checking. Time
> for signature checking can be neglected and 16K would be read for
> filesystem probe too. Additionally e.g. (hd0,1) is probed for
> subpartitions only if (hd0,1,X) is requested or we're scanning through
> partitions. In last case we're likely to fsprobe partition anyway so
> it doesn't create any overhead
>>
>> Perhaps we can explicitly list which combinations make sense?  So when an
>> msdos label is found, its partitions are probed for bsd labels too, but not
>> for msdos labels again, etc.
>>
>> --
>> Robert Millan
>>
>>  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
>>  how) you may access your data; but nobody's threatening your freedom: we
>>  still allow you to remove your data and not access it at all."
>>
>>
>> _______________________________________________
>> Grub-devel mailing list
>> Grub-devel@gnu.org
>> http://lists.gnu.org/mailman/listinfo/grub-devel
>>
>
>
>
> --
> Regards
> Vladimir 'phcoder' Serbinenko
>
> Personal git repository: http://repo.or.cz/w/grub2/phcoder.git
>



-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git

[-- Attachment #2: nestpart.diff --]
[-- Type: text/plain, Size: 61234 bytes --]

diff --git a/Changelog.phcoder b/Changelog.phcoder
new file mode 100644
index 0000000..1154244
--- /dev/null
+++ b/Changelog.phcoder
@@ -0,0 +1,72 @@
+2009-06-08  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	Nested partitions
+
+	* commands/blocklist.c (grub_cmd_blocklist): Don't check whether
+	'partition' is NULL, grub_partition_get_start already does that.
+	* commands/loadenv.c (check_blocklists): Likewise.
+	(write_blocklists): Likewise.
+	* conf/common.rmk (grub_probe_SOURCES): Add partmap/bsdlabel.c.
+	(grub_fstest_SOURCES): Likewise.
+	(pkglib_MODULES): Add bsdlabel.mod.
+	(bsdlabel_mod_SOURCES): New variable.
+	(bsdlabel_mod_CFLAGS): Likewise.
+	(bsdlabel_mod_LDFLAGS): Likewise.
+	* conf/i386-coreboot.rmk (grub_emu_SOURCES): Add partmap/bsdlabel.c.
+	* conf/i386-pc.rmk (grub_setup_SOURCES): Likewise.
+	(grub_emu_SOURCES): Likewise.
+	* conf/powerpc-ieee1275.rmk (grub_emu_SOURCES): Likewise.
+	* conf/sparc64-ieee1275.rmk (grub_emu_SOURCES): Likewise.
+	* include/grub/bsdlabel.h: New file.
+	* include/grub/partition.h (grub_partition_map): Remove 'probe' and
+	'get_name'.
+	(grub_partition): Add 'parent' and 'number'.
+	(grub_partition_get_start): Handle nested partitions.
+	* include/grub/pc_partition.h: Remove bsd-related entries.
+	(grub_pc_partition): Remove.
+	* kern/disk.c (grub_disk_close): Free partition data.
+	(grub_disk_adjust_range): Handle nested partitions.
+	* kern/partition.c (grub_partition_map_probe): New function.
+	(grub_partition_probe): Parse name to number, handle subpartitions.
+	(get_partmap): New function.
+	(grub_partition_iterate): Handle subpartitions.
+	(grub_partition_get_name): Likewise.
+	* loader/i386/pc/bsd.c (grub_bsd_get_device): Likewise.
+	* loader/i386/multiboot.c (grub_multiboot_get_bootdev): Likewise.
+	* loader/i386/pc/chainloader.c (grub_chainloader_cmd): Likewise.
+	* partmap/acorn.c (acorn_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	(acorn_partition_map_probe): Remove.
+	(acorn_partition_map_get_name): Likewise.
+	* partmap/amiga.c (amiga_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Set 'index' to 0 since there can be only one partition entry per sector.
+	(amiga_partition_map_probe): Remove.
+	(amiga_partition_map_get_name): Likewise.
+	* partmap/apple.c (apple_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Set 'offset' and 'index' to real positions of partitions.
+	(apple_partition_map_probe): Remove.
+	(apple_partition_map_get_name): Likewise.
+	* partmap/bsdlabel.c: New file.
+	* partmap/gpt.c (gpt_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Allocate 'data' so it can be correctly freed.
+	Set 'index' to offset inside sector.
+	(gpt_partition_map_probe): Remove.
+	(gpt_partition_map_get_name): Likewise.
+	* partmap/pc.c (grub_partition_parse): Remove.
+	(pc_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Make 'ext_offset' a local variable.
+	(pc_partition_map_probe): Remove.
+	(pc_partition_map_get_name): Remove.
+	* partmap/sun.c (sun_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	(sun_partition_map_probe): Remove.
+	(sun_partition_map_get_name): Likewise.
+	* parttool/pcpart.c (grub_pcpart_boot): Handle nested partitions.
+	(grub_pcpart_type): Likewise.
+	* util/hostdisk.c (open_device): Handle new numbering scheme.
+	(grub_util_biosdisk_get_grub_dev): Handle nested partitions.
+	* util/i386/pc/grub-setup.c (setup): Handle new numbering scheme.
diff --git a/commands/blocklist.c b/commands/blocklist.c
index b457b7c..6cc7d69 100644
--- a/commands/blocklist.c
+++ b/commands/blocklist.c
@@ -89,8 +89,7 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)),
     return grub_error (GRUB_ERR_BAD_DEVICE,
 		       "this command is available only for disk devices.");
 
-  if (file->device->disk->partition)
-    part_start = grub_partition_get_start (file->device->disk->partition);
+  part_start = grub_partition_get_start (file->device->disk->partition);
 
   file->read_hook = read_blocklist;
 
diff --git a/commands/loadenv.c b/commands/loadenv.c
index 22665f9..51cffd3 100644
--- a/commands/loadenv.c
+++ b/commands/loadenv.c
@@ -236,10 +236,8 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
   /* One more sanity check. Re-read all sectors by blocklists, and compare
      those with the data read via a file.  */
   disk = file->device->disk;
-  if (disk->partition)
-    part_start = grub_partition_get_start (disk->partition);
-  else
-    part_start = 0;
+
+  part_start = grub_partition_get_start (disk->partition);
 
   buf = grub_envblk_buffer (envblk);
   for (p = blocklists, index = 0; p; p = p->next, index += p->length)
@@ -272,10 +270,7 @@ write_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
 
   buf = grub_envblk_buffer (envblk);
   disk = file->device->disk;
-  if (disk->partition)
-    part_start = grub_partition_get_start (disk->partition);
-  else
-    part_start = 0;
+  part_start = grub_partition_get_start (disk->partition);
 
   index = 0;
   for (p = blocklists; p; p = p->next, index += p->length)
diff --git a/conf/common.rmk b/conf/common.rmk
index c33e800..15ab189 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -19,7 +19,8 @@ grub_probe_SOURCES = util/grub-probe.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c		\
 	\
-	partmap/msdos.c partmap/apple.c partmap/sun.c partmap/gpt.c\
+	partmap/msdos.c partmap/bsdlabel.c partmap/apple.c \
+	partmap/sun.c partmap/gpt.c\
 	kern/fs.c kern/env.c fs/fshelp.c			\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c grub_probe_init.c
 
@@ -40,8 +41,8 @@ grub_fstest_SOURCES = util/grub-fstest.c util/hostfs.c util/misc.c 	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c			\
 	fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c			\
 	\
-	kern/partition.c partmap/msdos.c partmap/apple.c partmap/sun.c	\
-	partmap/gpt.c							\
+	kern/partition.c partmap/msdos.c partmap/bsdlabel.c		\
+	partmap/apple.c partmap/sun.c partmap/gpt.c			\
 	kern/fs.c kern/env.c fs/fshelp.c disk/raid.c			\
 	disk/raid5_recover.c disk/raid6_recover.c 			\
 	disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c 		\
@@ -316,6 +317,11 @@ part_gpt_mod_SOURCES = partmap/gpt.c
 part_gpt_mod_CFLAGS = $(COMMON_CFLAGS)
 part_gpt_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+pkglib_MODULES += part_bsd.mod
+part_bsd_mod_SOURCES = partmap/bsdlabel.c
+part_bsd_mod_CFLAGS = $(COMMON_CFLAGS)
+part_bsd_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # Special disk structures and generic drivers
 
 pkglib_MODULES += raid.mod raid5rec.mod raid6rec.mod mdraid.mod dm_nv.mod \
diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk
index de30041..64fe91e 100644
--- a/conf/i386-coreboot.rmk
+++ b/conf/i386-coreboot.rmk
@@ -134,8 +134,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c       \
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c          \
-	partmap/amiga.c	partmap/apple.c partmap/msdos.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/msdos.c			\
+	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c partmap/gpt.c	\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk
index 98aaf58..bebf905 100644
--- a/conf/i386-ieee1275.rmk
+++ b/conf/i386-ieee1275.rmk
@@ -88,8 +88,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c		\
-	partmap/amiga.c	partmap/apple.c partmap/msdos.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/msdos.c			\
+	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c partmap/gpt.c	\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index 13aaa26..7e55a70 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -104,7 +104,7 @@ grub_setup_SOURCES = util/i386/pc/grub-setup.c util/hostdisk.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c			\
 	\
-	partmap/msdos.c partmap/gpt.c				\
+	partmap/msdos.c partmap/bsdlabel.c partmap/gpt.c		\
 	\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
 	util/raid.c util/lvm.c					\
@@ -140,8 +140,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/menu_text.c						\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c		\
-	partmap/amiga.c	partmap/apple.c partmap/msdos.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/bsdlabel.c 		\
+	partmap/msdos.c partmap/sun.c partmap/acorn.c partmap/gpt.c	\
 	\
 	fs/affs.c fs/cpio.c  fs/fat.c fs/ext2.c fs/hfs.c		\
 	fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c		\
diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk
index c1c04e4..bf67daa 100644
--- a/conf/powerpc-ieee1275.rmk
+++ b/conf/powerpc-ieee1275.rmk
@@ -69,8 +69,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c 	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c				\
-	partmap/amiga.c	partmap/apple.c partmap/msdos.c partmap/sun.c	\
-	partmap/acorn.c							\
+	partmap/amiga.c	partmap/apple.c partmap/msdos.c 		\
+	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c		\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk
index c3ecba2..eeb03f8 100644
--- a/conf/sparc64-ieee1275.rmk
+++ b/conf/sparc64-ieee1275.rmk
@@ -80,8 +80,8 @@ grub_setup_SOURCES = util/sparc64/ieee1275/grub-setup.c util/hostdisk.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c			\
 	\
-	partmap/amiga.c	partmap/apple.c partmap/msdos.c		\
-	partmap/sun.c partmap/acorn.c				\
+	partmap/amiga.c	partmap/apple.c partmap/msdos.c 	\
+	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c	\
 	\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
 	util/raid.c util/lvm.c					\
diff --git a/include/grub/bsdlabel.h b/include/grub/bsdlabel.h
new file mode 100644
index 0000000..0139b42
--- /dev/null
+++ b/include/grub/bsdlabel.h
@@ -0,0 +1,89 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2004,2007  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_BSDLABEL_PARTITION_HEADER
+#define GRUB_BSDLABEL_PARTITION_HEADER	1
+
+/* Constants for BSD disk label.  */
+#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR	1
+#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC	0x82564557
+
+/* BSD partition types.  */
+#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED	0
+#define GRUB_PC_PARTITION_BSD_TYPE_SWAP		1
+#define GRUB_PC_PARTITION_BSD_TYPE_V6		2
+#define GRUB_PC_PARTITION_BSD_TYPE_V7		3
+#define GRUB_PC_PARTITION_BSD_TYPE_SYSV		4
+#define GRUB_PC_PARTITION_BSD_TYPE_V71K		5
+#define GRUB_PC_PARTITION_BSD_TYPE_V8		6
+#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS	7
+#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS	8
+#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS	9
+#define GRUB_PC_PARTITION_BSD_TYPE_OTHER	10
+#define GRUB_PC_PARTITION_BSD_TYPE_HPFS		11
+#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660	12
+#define GRUB_PC_PARTITION_BSD_TYPE_BOOT		13
+
+/* FreeBSD-specific types.  */
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM	14
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID	15
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2	21
+
+/* NetBSD-specific types.  */
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_ADOS	14
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_HFS	15
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE	16
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS	17
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_NTFS	18
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_RAID	19
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_CCD	20
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_JFS2	21
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS	22
+
+/* OpenBSD-specific types.  */
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS	14
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_HFS	15
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE	16
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS	17
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS	18
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_RAID	19
+
+/* The BSD partition entry.  */
+struct grub_pc_partition_bsd_entry
+{
+  grub_uint32_t size;
+  grub_uint32_t offset;
+  grub_uint32_t fragment_size;
+  grub_uint8_t fs_type;
+  grub_uint8_t fs_fragments;
+  grub_uint16_t fs_cylinders;
+} __attribute__ ((packed));
+
+/* The BSD disk label. Only define members useful for GRUB.  */
+struct grub_pc_partition_disk_label
+{
+  grub_uint32_t magic;
+  grub_uint8_t padding[128];
+  grub_uint32_t magic2;
+  grub_uint16_t checksum;
+  grub_uint16_t num_partitions;
+  grub_uint32_t boot_size;
+  grub_uint32_t superblock_size;
+} __attribute__ ((packed));
+
+#endif /* ! GRUB_PC_PARTITION_HEADER */
diff --git a/include/grub/msdos_partition.h b/include/grub/msdos_partition.h
index 273d8c9..650d784 100644
--- a/include/grub/msdos_partition.h
+++ b/include/grub/msdos_partition.h
@@ -53,75 +53,6 @@
 #define GRUB_PC_PARTITION_TYPE_GPT_DISK		0xee
 #define GRUB_PC_PARTITION_TYPE_LINUX_RAID	0xfd
 
-/* Constants for BSD disk label.  */
-#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR	1
-#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC	0x82564557
-#define GRUB_PC_PARTITION_BSD_MAX_ENTRIES	8
-
-/* BSD partition types.  */
-#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED	0
-#define GRUB_PC_PARTITION_BSD_TYPE_SWAP		1
-#define GRUB_PC_PARTITION_BSD_TYPE_V6		2
-#define GRUB_PC_PARTITION_BSD_TYPE_V7		3
-#define GRUB_PC_PARTITION_BSD_TYPE_SYSV		4
-#define GRUB_PC_PARTITION_BSD_TYPE_V71K		5
-#define GRUB_PC_PARTITION_BSD_TYPE_V8		6
-#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS	7
-#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS	8
-#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS	9
-#define GRUB_PC_PARTITION_BSD_TYPE_OTHER	10
-#define GRUB_PC_PARTITION_BSD_TYPE_HPFS		11
-#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660	12
-#define GRUB_PC_PARTITION_BSD_TYPE_BOOT		13
-
-/* FreeBSD-specific types.  */
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM	14
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID	15
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2	21
-
-/* NetBSD-specific types.  */
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_ADOS	14
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_HFS	15
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE	16
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS	17
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_NTFS	18
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_RAID	19
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_CCD	20
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_JFS2	21
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS	22
-
-/* OpenBSD-specific types.  */
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS	14
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_HFS	15
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE	16
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS	17
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS	18
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_RAID	19
-
-/* The BSD partition entry.  */
-struct grub_msdos_partition_bsd_entry
-{
-  grub_uint32_t size;
-  grub_uint32_t offset;
-  grub_uint32_t fragment_size;
-  grub_uint8_t fs_type;
-  grub_uint8_t fs_fragments;
-  grub_uint16_t fs_cylinders;
-} __attribute__ ((packed));
-
-/* The BSD disk label. Only define members useful for GRUB.  */
-struct grub_msdos_partition_disk_label
-{
-  grub_uint32_t magic;
-  grub_uint8_t padding[128];
-  grub_uint32_t magic2;
-  grub_uint16_t checksum;
-  grub_uint16_t num_partitions;
-  grub_uint32_t boot_size;
-  grub_uint32_t superblock_size;
-  struct grub_msdos_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES];
-} __attribute__ ((packed));
-
 /* The partition entry.  */
 struct grub_msdos_partition_entry
 {
@@ -168,23 +99,6 @@ struct grub_msdos_partition_mbr
 } __attribute__ ((packed));
 
 \f
-struct grub_msdos_partition
-{
-    /* The DOS partition number.  */
-  int dos_part;
-
-  /* The BSD partition number (a == 0).  */
-  int bsd_part;
-
-  /* The DOS partition type.  */
-  int dos_type;
-
-  /* The BSD partition type.  */
-  int bsd_type;
-
-  /* The offset of the extended partition.  */
-  unsigned long ext_offset;
-};
 
 static inline int
 grub_msdos_partition_is_empty (int type)
@@ -200,12 +114,4 @@ grub_msdos_partition_is_extended (int type)
 	  || type == GRUB_PC_PARTITION_TYPE_LINUX_EXTENDED);
 }
 
-static inline int
-grub_msdos_partition_is_bsd (int type)
-{
-  return (type == GRUB_PC_PARTITION_TYPE_FREEBSD
-	  || type == GRUB_PC_PARTITION_TYPE_OPENBSD
-	  || type == GRUB_PC_PARTITION_TYPE_NETBSD);
-}
-
 #endif /* ! GRUB_PC_PARTITION_HEADER */
diff --git a/include/grub/partition.h b/include/grub/partition.h
index d35658c..5e8c476 100644
--- a/include/grub/partition.h
+++ b/include/grub/partition.h
@@ -36,13 +36,6 @@ struct grub_partition_map
 			 int (*hook) (struct grub_disk *disk,
 				      const grub_partition_t partition));
 
-  /* Return the partition named STR on the disk DISK.  */
-  grub_partition_t (*probe) (struct grub_disk *disk,
-			     const char *str);
-
-  /* Return the name of the partition PARTITION.  */
-  char *(*get_name) (const grub_partition_t partition);
-
   /* The next partition map type.  */
   struct grub_partition_map *next;
 };
@@ -51,6 +44,9 @@ typedef struct grub_partition_map *grub_partition_map_t;
 /* Partition description.  */
 struct grub_partition
 {
+  /* The partition number.  */
+  int number;
+
   /* The start sector.  */
   grub_disk_addr_t start;
 
@@ -66,6 +62,9 @@ struct grub_partition
   /* Partition map type specific data.  */
   void *data;
 
+  /* Parent partition map.  */
+  struct grub_partition *parent;
+
   /* The type partition map.  */
   grub_partition_map_t partmap;
 };
@@ -101,7 +100,13 @@ void grub_apple_partition_map_fini (void);
 static inline grub_disk_addr_t
 grub_partition_get_start (const grub_partition_t p)
 {
-  return p->start;
+  grub_partition_t part;
+  grub_uint64_t part_start = 0;
+
+  for (part = p; part; part = part->parent)
+    part_start += part->start;
+
+  return part_start;
 }
 
 static inline grub_uint64_t
diff --git a/kern/disk.c b/kern/disk.c
index e463626..657ac8d 100644
--- a/kern/disk.c
+++ b/kern/disk.c
@@ -330,6 +330,7 @@ grub_disk_open (const char *name)
 void
 grub_disk_close (grub_disk_t disk)
 {
+  grub_partition_t part;
   grub_dprintf ("disk", "Closing `%s'.\n", disk->name);
 
   if (disk->dev && disk->dev->close)
@@ -338,7 +339,13 @@ grub_disk_close (grub_disk_t disk)
   /* Reset the timer.  */
   grub_last_time = grub_get_time_ms ();
 
-  grub_free (disk->partition);
+  while (disk->partition)
+    {
+      part = disk->partition->parent;
+      grub_free (disk->partition->data);
+      grub_free (disk->partition);
+      disk->partition = part;
+    }
   grub_free ((void *) disk->name);
   grub_free (disk);
 }
@@ -349,18 +356,19 @@ grub_disk_close (grub_disk_t disk)
    - Verify that the range is inside the partition.  */
 static grub_err_t
 grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
-		       grub_off_t *offset, grub_size_t size)
+			grub_off_t *offset, grub_size_t size)
 {
+  grub_partition_t part;
   *sector += *offset >> GRUB_DISK_SECTOR_BITS;
   *offset &= GRUB_DISK_SECTOR_SIZE - 1;
 
-  if (disk->partition)
+  for (part = disk->partition; part; part = part->parent)
     {
       grub_disk_addr_t start;
       grub_uint64_t len;
 
-      start = grub_partition_get_start (disk->partition);
-      len = grub_partition_get_len (disk->partition);
+      start = part->start;
+      len = part->len;
 
       if (*sector >= len
 	  || len - *sector < ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
diff --git a/kern/partition.c b/kern/partition.c
index 4d5c63a..4bcd8c7 100644
--- a/kern/partition.c
+++ b/kern/partition.c
@@ -17,6 +17,7 @@
  */
 
 #include <grub/misc.h>
+#include <grub/mm.h>
 #include <grub/partition.h>
 #include <grub/disk.h>
 
@@ -54,17 +55,58 @@ grub_partition_map_iterate (int (*hook) (const grub_partition_map_t partmap))
   return 0;
 }
 
+static grub_partition_t
+grub_partition_map_probe (const grub_partition_map_t partmap,
+			  grub_disk_t disk, int partnum)
+{
+  grub_partition_t p = 0;
+
+  auto int find_func (grub_disk_t d, const grub_partition_t partition);
+
+  int find_func (grub_disk_t d __attribute__ ((unused)),
+		 const grub_partition_t partition)
+    {
+      if (partnum == partition->number)
+	{
+	  p = (grub_partition_t) grub_malloc (sizeof (*p));
+	  if (! p)
+	    return 1;
+
+	  grub_memcpy (p, partition, sizeof (*p));
+	  return 1;
+	}
+
+      return 0;
+    }
+
+  partmap->iterate (disk, find_func);
+  if (grub_errno)
+    goto fail;
+
+  return p;
+
+ fail:
+  grub_free (p);
+  return 0;
+}
+
 grub_partition_t
 grub_partition_probe (struct grub_disk *disk, const char *str)
 {
   grub_partition_t part = 0;
+  grub_partition_t curpart = 0;
+  grub_partition_t tail;
+  const char *ptr;
+  int num;
 
   auto int part_map_probe (const grub_partition_map_t partmap);
 
   int part_map_probe (const grub_partition_map_t partmap)
     {
-      part = partmap->probe (disk, str);
-      if (part)
+      disk->partition = part;
+      curpart = grub_partition_map_probe (partmap, disk, num);
+      disk->partition = tail;
+      if (curpart)
 	return 1;
 
       if (grub_errno == GRUB_ERR_BAD_PART_TABLE)
@@ -77,27 +119,54 @@ grub_partition_probe (struct grub_disk *disk, const char *str)
       return 1;
     }
 
-  /* Use the first partition map type found.  */
-  grub_partition_map_iterate (part_map_probe);
+  part = tail = disk->partition;
+
+  for (ptr = str; *ptr;)
+    {
+      /* BSD-like partition specification.  */
+      if (*ptr >= 'a' && *ptr <= 'z')
+	num = *(ptr++) - 'a';
+      else
+	num = grub_strtoul (ptr, (char **) &ptr, 0) - 1;
+
+      curpart = 0;
+      /* Use the first partition map type found.  */
+      grub_partition_map_iterate (part_map_probe);
+
+      if (! curpart)
+	{
+	  while (part)
+	    {
+	      curpart = part->parent;
+	      grub_free (part);
+	      part = curpart;
+	    }
+	  return 0;
+	}
+      curpart->parent = part;
+      part = curpart;
+      if (! ptr || *ptr != ',')
+	break;
+      ptr++;
+    }
 
   return part;
 }
 
-int
-grub_partition_iterate (struct grub_disk *disk,
-			int (*hook) (grub_disk_t disk,
-				     const grub_partition_t partition))
+static grub_partition_map_t
+get_partmap (struct grub_disk *disk)
 {
   grub_partition_map_t partmap = 0;
-  int ret = 0;
-
+  struct grub_partition part;
+  int found = 0;
   auto int part_map_iterate (const grub_partition_map_t p);
   auto int part_map_iterate_hook (grub_disk_t d,
 				  const grub_partition_t partition);
-
   int part_map_iterate_hook (grub_disk_t d __attribute__ ((unused)),
-			     const grub_partition_t partition __attribute__ ((unused)))
+			     const grub_partition_t partition)
     {
+      found = 1;
+      part = *partition;
       return 1;
     }
 
@@ -106,22 +175,58 @@ grub_partition_iterate (struct grub_disk *disk,
       grub_dprintf ("partition", "Detecting %s...\n", p->name);
       p->iterate (disk, part_map_iterate_hook);
 
-      if (grub_errno != GRUB_ERR_NONE)
+      if (grub_errno != GRUB_ERR_NONE || ! found)
 	{
 	  /* Continue to next partition map type.  */
 	  grub_dprintf ("partition", "%s detection failed.\n", p->name);
 	  grub_errno = GRUB_ERR_NONE;
 	  return 0;
 	}
+      grub_free (part.data);
 
       grub_dprintf ("partition", "%s detection succeeded.\n", p->name);
       partmap = p;
       return 1;
     }
-
   grub_partition_map_iterate (part_map_iterate);
-  if (partmap)
-    ret = partmap->iterate (disk, hook);
+  return partmap;
+}
+
+int
+grub_partition_iterate (struct grub_disk *disk,
+			int (*hook) (grub_disk_t disk,
+				     const grub_partition_t partition))
+{
+  int ret = 0;
+
+  auto int part_iterate (grub_disk_t dsk, const grub_partition_t p);
+
+  int part_iterate (grub_disk_t dsk,
+		    const grub_partition_t partition)
+    {
+      struct grub_partition p = *partition;
+      grub_partition_map_t partmap = 0;
+      p.parent = dsk->partition;
+      dsk->partition = 0;
+      if (hook (dsk, &p))
+	  return 1;
+      if (p.start != 0)
+	{
+	  dsk->partition = &p;
+	  partmap = get_partmap (dsk);
+	  if (partmap)
+	    ret = partmap->iterate (dsk, part_iterate);
+	}
+      dsk->partition = p.parent;
+      return ret;
+    }
+
+  {
+    grub_partition_map_t partmap = 0;
+    partmap = get_partmap (disk);
+    if (partmap)
+      ret = partmap->iterate (disk, part_iterate);
+  }
 
   return ret;
 }
@@ -129,5 +234,30 @@ grub_partition_iterate (struct grub_disk *disk,
 char *
 grub_partition_get_name (const grub_partition_t partition)
 {
-  return partition->partmap->get_name (partition);
+  char *out = 0;
+  /* Even on 64-bit machines this buffer is enough to hold longest number.  */
+  char buf[25];
+  int curlen = 0;
+  grub_partition_t part;
+  for (part = partition; part; part = part->parent)
+    {
+      int strl;
+      grub_sprintf (buf, "%d", part->number + 1);
+      strl = grub_strlen (buf);
+      if (curlen)
+	{
+	  out = grub_realloc (out, curlen + strl + 2);
+	  grub_memcpy (out + strl + 1, out, curlen);
+	  out[curlen + 1 + strl] = 0;
+	  grub_memcpy (out, buf, strl);
+	  out[strl] = ',';
+	  curlen = curlen + 1 + strl;
+	}
+      else
+	{
+	  curlen = strl;
+	  out = grub_strdup (buf);
+	}
+    }
+  return out;
 }
diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c
index d5f677a..5f18b1b 100644
--- a/loader/i386/bsd.c
+++ b/loader/i386/bsd.c
@@ -129,7 +129,6 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
 		     grub_uint32_t * unit,
 		     grub_uint32_t * slice, grub_uint32_t * part)
 {
-  char *p;
   grub_device_t dev; 
 
   *biosdev = grub_get_root_biosnumber () & 0xff;
@@ -139,21 +138,13 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-
-      p = dev->disk->partition->partmap->get_name (dev->disk->partition);
-      if (p)
+      if (dev->disk->partition->parent)
 	{
-	  if ((p[0] >= '0') && (p[0] <= '9'))
-	    {
-	      *slice = grub_strtoul (p, &p, 0);
-
-	      if ((p) && (p[0] == ','))
-		p++;
-	    }
-
-	  if ((p[0] >= 'a') && (p[0] <= 'z'))
-	    *part = p[0] - 'a';
+	  *part = dev->disk->partition->number;
+	  *slice = dev->disk->partition->parent->number + 1;
 	}
+      else
+	*slice = dev->disk->partition->number + 1;
     }
   if (dev)
     grub_device_close (dev);
diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c
index 8c3139b..719a51d 100644
--- a/loader/i386/multiboot.c
+++ b/loader/i386/multiboot.c
@@ -155,7 +155,6 @@ static int
 grub_multiboot_get_bootdev (grub_uint32_t *bootdev)
 {
 #ifdef GRUB_MACHINE_PCBIOS
-  char *p;
   grub_uint32_t biosdev, slice = ~0, part = ~0;
   grub_device_t dev;
 
@@ -164,21 +163,13 @@ grub_multiboot_get_bootdev (grub_uint32_t *bootdev)
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-
-      p = dev->disk->partition->partmap->get_name (dev->disk->partition);
-      if (p)
+      if (dev->disk->partition->parent)
 	{
-	  if ((p[0] >= '0') && (p[0] <= '9'))
-	    {
-	      slice = grub_strtoul (p, &p, 0) - 1;
-
-	      if ((p) && (p[0] == ','))
-		p++;
-	    }
-
-	  if ((p[0] >= 'a') && (p[0] <= 'z'))
-	    part = p[0] - 'a';
+	  part = dev->disk->partition->number;
+	  slice = dev->disk->partition->parent->number;
 	}
+      else
+	slice = dev->disk->partition->number;
     }
   if (dev)
     grub_device_close (dev);
diff --git a/loader/i386/pc/chainloader.c b/loader/i386/pc/chainloader.c
index caf1450..79bc290 100644
--- a/loader/i386/pc/chainloader.c
+++ b/loader/i386/pc/chainloader.c
@@ -31,6 +31,7 @@
 #include <grub/machine/memory.h>
 #include <grub/dl.h>
 #include <grub/command.h>
+#include <grub/pc_partition.h>
 #include <grub/machine/biosnum.h>
 
 static grub_dl_t my_mod;
@@ -94,10 +95,22 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-      grub_disk_read (dev->disk, dev->disk->partition->offset, 446, 64,
-		      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
-      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
-			    + (dev->disk->partition->index << 4));
+      grub_disk_t disk = dev->disk;
+
+      if (disk)
+	{
+	  grub_partition_t p = disk->partition;
+
+	  if (p && grub_strcmp (p->partmap->name, "pc_partition_map") == 0)
+	    {
+	      disk->partition = p->parent;
+	      grub_disk_read (disk, p->offset, 446, 64,
+			      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
+	      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
+				    + (p->index << 4));
+	      disk->partition = p;
+	    }
+	}
     }
 
   if (dev)
diff --git a/partmap/acorn.c b/partmap/acorn.c
index 42fd61f..8443554 100644
--- a/partmap/acorn.c
+++ b/partmap/acorn.c
@@ -96,21 +96,17 @@ acorn_partition_map_iterate (grub_disk_t disk,
 					  const grub_partition_t partition))
 {
   struct grub_partition part;
-  struct grub_disk raw;
   struct linux_part map[LINUX_MAP_ENTRIES];
   int i;
-  grub_disk_addr_t sector;
+  grub_disk_addr_t sector = 0;
   grub_err_t err;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
-  err = acorn_partition_map_find (&raw, map, &sector);
+  err = acorn_partition_map_find (disk, map, &sector);
   if (err)
     return err;
 
   part.partmap = &grub_acorn_partition_map;
+  part.data = 0;
 
   for (i = 0; i != LINUX_MAP_ENTRIES; ++i)
     {
@@ -121,7 +117,7 @@ acorn_partition_map_iterate (grub_disk_t disk,
       part.start = sector + map[i].start;
       part.len = map[i].size;
       part.offset = 6;
-      part.index = i;
+      part.number = part.index = i;
 
       if (hook (disk, &part))
 	return grub_errno;
@@ -130,60 +126,6 @@ acorn_partition_map_iterate (grub_disk_t disk,
   return GRUB_ERR_NONE;
 }
 
-
-static grub_partition_t
-acorn_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  struct linux_part map[LINUX_MAP_ENTRIES];
-  struct grub_disk raw = *disk;
-  unsigned long partnum = grub_strtoul (str, 0, 10) - 1;
-  grub_disk_addr_t sector;
-  grub_err_t err;
-  grub_partition_t p;
-
-  /* Enforce raw disk access.  */
-  raw.partition = 0;
-
-  /* Get the partition number.  */
-  if (partnum > LINUX_MAP_ENTRIES)
-    goto fail;
-
-  err = acorn_partition_map_find (&raw, map, &sector);
-  if (err)
-    return 0;
-
-  if (map[partnum].magic != LINUX_NATIVE_MAGIC
-      && map[partnum].magic != LINUX_SWAP_MAGIC)
-    goto fail;
-
-  p = grub_malloc (sizeof (struct grub_partition));
-  if (! p)
-    return 0;
-
-  p->start = sector + map[partnum].start;
-  p->len = map[partnum].size;
-  p->offset = 6;
-  p->index = partnum;
-  return p;
-
-fail:
-  grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-  return 0;
-}
-
-
-static char *
-acorn_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
 \f
 
 /* Partition map type.  */
@@ -191,8 +133,6 @@ static struct grub_partition_map grub_acorn_partition_map =
 {
   .name = "Linux/ADFS partition map",
   .iterate = acorn_partition_map_iterate,
-  .probe = acorn_partition_map_probe,
-  .get_name = acorn_partition_map_get_name
 };
 
 GRUB_MOD_INIT(acorn_partition_map)
diff --git a/partmap/amiga.c b/partmap/amiga.c
index ffb807f..90cf525 100644
--- a/partmap/amiga.c
+++ b/partmap/amiga.c
@@ -76,20 +76,15 @@ amiga_partition_map_iterate (grub_disk_t disk,
 {
   struct grub_partition part;
   struct grub_amiga_rdsk rdsk;
-  struct grub_disk raw;
   int partno = 0;
   int next = -1;
   unsigned pos;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   /* The RDSK block is one of the first 15 blocks.  */
   for (pos = 0; pos < 15; pos++)
     {
       /* Read the RDSK block which is a descriptor for the entire disk.  */
-      if (grub_disk_read (&raw, pos, 0, sizeof (rdsk), &rdsk))
+      if (grub_disk_read (disk, pos, 0, sizeof (rdsk), &rdsk))
 	return grub_errno;
 
       if (grub_strcmp ((char *) rdsk.magic, "RDSK") == 0)
@@ -104,13 +99,15 @@ amiga_partition_map_iterate (grub_disk_t disk,
     return grub_error (GRUB_ERR_BAD_PART_TABLE,
 		       "Amiga partition map not found.");
 
+  part.data = 0;
+
   /* The end of the partition list is marked using "-1".  */
   while (next != -1)
     {
       struct grub_amiga_partition apart;
 
       /* Read the RDSK block which is a descriptor for the entire disk.  */
-      if (grub_disk_read (&raw, next, 0, sizeof (apart), &apart))
+      if (grub_disk_read (disk, next, 0, sizeof (apart), &apart))
 	return grub_errno;
 
       /* Calculate the first block and the size of the partition.  */
@@ -123,7 +120,8 @@ amiga_partition_map_iterate (grub_disk_t disk,
 		  * grub_be_to_cpu32 (apart.block_per_track));
 
       part.offset = (grub_off_t) next * 512;
-      part.index = partno;
+      part.number = partno;
+      part.index = 0;
       part.partmap = &grub_amiga_partition_map;
 
       if (hook (disk, &part))
@@ -136,72 +134,12 @@ amiga_partition_map_iterate (grub_disk_t disk,
   return 0;
 }
 
-
-static grub_partition_t
-amiga_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  if (amiga_partition_map_iterate (disk, find_func))
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-amiga_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_amiga_partition_map =
   {
     .name = "amiga_partition_map",
     .iterate = amiga_partition_map_iterate,
-    .probe = amiga_partition_map_probe,
-    .get_name = amiga_partition_map_get_name
   };
 
 GRUB_MOD_INIT(amiga_partition_map)
diff --git a/partmap/apple.c b/partmap/apple.c
index 04ccff1..e1b5bff 100644
--- a/partmap/apple.c
+++ b/partmap/apple.c
@@ -105,17 +105,12 @@ apple_partition_map_iterate (grub_disk_t disk,
   struct grub_partition part;
   struct grub_apple_header aheader;
   struct grub_apple_part apart;
-  struct grub_disk raw;
   int partno = 0, partnum = 0;
   unsigned pos;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   part.partmap = &grub_apple_partition_map;
 
-  if (grub_disk_read (&raw, 0, 0, sizeof (aheader), &aheader))
+  if (grub_disk_read (disk, 0, 0, sizeof (aheader), &aheader))
     return grub_errno;
 
   if (grub_be_to_cpu16 (aheader.magic) != GRUB_APPLE_HEADER_MAGIC)
@@ -127,14 +122,17 @@ apple_partition_map_iterate (grub_disk_t disk,
       goto fail;
     }
 
+  part.data = 0;
   pos = grub_be_to_cpu16 (aheader.blocksize);
 
   do
     {
-      if (grub_disk_read (&raw, pos / GRUB_DISK_SECTOR_SIZE,
-			  pos % GRUB_DISK_SECTOR_SIZE,
-			  sizeof (struct grub_apple_part),  &apart))
-	return grub_errno;
+       part.offset = pos / GRUB_DISK_SECTOR_SIZE;
+       part.index = pos % GRUB_DISK_SECTOR_SIZE;
+
+       if (grub_disk_read (disk, part.offset, part.index,
+			   sizeof (struct grub_apple_part),  &apart))
+	 return grub_errno;
 
       if (grub_be_to_cpu16 (apart.magic) != GRUB_APPLE_PART_MAGIC)
 	{
@@ -156,6 +154,7 @@ apple_partition_map_iterate (grub_disk_t disk,
 	/ GRUB_DISK_SECTOR_SIZE;
       part.offset = pos;
       part.index = partno;
+      part.number = partno;
 
       grub_dprintf ("partition",
 		    "partition %d: name %s, type %s, start 0x%x, len 0x%x\n",
@@ -179,72 +178,12 @@ apple_partition_map_iterate (grub_disk_t disk,
 		     "Apple partition map not found.");
 }
 
-
-static grub_partition_t
-apple_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  if (apple_partition_map_iterate (disk, find_func))
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-apple_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_apple_partition_map =
   {
     .name = "apple_partition_map",
     .iterate = apple_partition_map_iterate,
-    .probe = apple_partition_map_probe,
-    .get_name = apple_partition_map_get_name
   };
 
 GRUB_MOD_INIT(apple_partition_map)
diff --git a/partmap/bsdlabel.c b/partmap/bsdlabel.c
new file mode 100644
index 0000000..75d9d6e
--- /dev/null
+++ b/partmap/bsdlabel.c
@@ -0,0 +1,97 @@
+/* bsdlabel.c - Read BSD style partition tables.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2004,2005,2006,2007,2008,2009  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/partition.h>
+#include <grub/bsdlabel.h>
+#include <grub/disk.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/dl.h>
+
+static struct grub_partition_map grub_bsdlabel_partition_map;
+\f
+
+static grub_err_t
+bsdlabel_partition_map_iterate (grub_disk_t disk,
+			  int (*hook) (grub_disk_t disk,
+				       const grub_partition_t partition))
+{
+  struct grub_pc_partition_disk_label label;
+  struct grub_partition p;
+  grub_disk_addr_t delta = 0;
+  unsigned pos;
+
+  /* BSDLabel offsets are absolute even when it's embed inside partition.  */
+  delta = grub_partition_get_start (disk->partition);
+
+  /* Read the BSD label.  */
+  if (grub_disk_read (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR,
+		      0, sizeof (label), &label))
+    return grub_errno;
+
+  /* Check if it is valid.  */
+  if (label.magic != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
+    return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
+
+  pos = sizeof (label) + GRUB_PC_PARTITION_BSD_LABEL_SECTOR
+    * GRUB_DISK_SECTOR_SIZE;
+
+  for (p.number = 0;
+       p.number < grub_cpu_to_le16 (label.num_partitions);
+       p.number++)
+    {
+      struct grub_pc_partition_bsd_entry be;
+
+      p.offset = pos / GRUB_DISK_SECTOR_SIZE;
+      p.index = pos % GRUB_DISK_SECTOR_SIZE;
+
+      if (grub_disk_read (disk, p.offset, p.index, sizeof (be),  &be))
+	return grub_errno;
+
+      p.start = grub_le_to_cpu32 (be.offset) - delta;
+      p.len = grub_le_to_cpu32 (be.size);
+      p.partmap = &grub_bsdlabel_partition_map;
+
+      if (be.fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
+	if (hook (disk, &p))
+	  return grub_errno;
+
+      pos += sizeof (struct grub_pc_partition_bsd_entry);
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+\f
+/* Partition map type.  */
+static struct grub_partition_map grub_bsdlabel_partition_map =
+  {
+    .name = "bsd_partition_map",
+    .iterate = bsdlabel_partition_map_iterate,
+  };
+
+GRUB_MOD_INIT(bsd_partition_map)
+{
+  grub_partition_map_register (&grub_bsdlabel_partition_map);
+}
+
+GRUB_MOD_FINI(bsd_partition_map)
+{
+  grub_partition_map_unregister (&grub_bsdlabel_partition_map);
+}
diff --git a/partmap/gpt.c b/partmap/gpt.c
index e860f35..375f175 100644
--- a/partmap/gpt.c
+++ b/partmap/gpt.c
@@ -44,18 +44,13 @@ gpt_partition_map_iterate (grub_disk_t disk,
   struct grub_partition part;
   struct grub_gpt_header gpt;
   struct grub_gpt_partentry entry;
-  struct grub_disk raw;
   struct grub_msdos_partition_mbr mbr;
   grub_uint64_t entries;
   unsigned int i;
   int last_offset = 0;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   /* Read the protective MBR.  */
-  if (grub_disk_read (&raw, 0, 0, sizeof (mbr), &mbr))
+  if (grub_disk_read (disk, 0, 0, sizeof (mbr), &mbr))
     return grub_errno;
 
   /* Check if it is valid.  */
@@ -67,7 +62,7 @@ gpt_partition_map_iterate (grub_disk_t disk,
     return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
 
   /* Read the GPT header.  */
-  if (grub_disk_read (&raw, 1, 0, sizeof (gpt), &gpt))
+  if (grub_disk_read (disk, 1, 0, sizeof (gpt), &gpt))
     return grub_errno;
 
   if (grub_memcmp (gpt.magic, grub_gpt_magic, sizeof (grub_gpt_magic)))
@@ -76,11 +71,15 @@ gpt_partition_map_iterate (grub_disk_t disk,
   grub_dprintf ("gpt", "Read a valid GPT header\n");
 
   entries = grub_le_to_cpu64 (gpt.partitions);
+  part.data = grub_malloc (sizeof (entry));
   for (i = 0; i < grub_le_to_cpu32 (gpt.maxpart); i++)
     {
-      if (grub_disk_read (&raw, entries, last_offset,
+      if (grub_disk_read (disk, entries, last_offset,
 			  sizeof (entry), &entry))
-	return grub_errno;
+	{
+	  grub_free (part.data);
+	  return grub_errno;
+	}
 
       if (grub_memcmp (&grub_gpt_partition_type_empty, &entry.type,
 		       sizeof (grub_gpt_partition_type_empty)))
@@ -90,16 +89,17 @@ gpt_partition_map_iterate (grub_disk_t disk,
 	  part.len = (grub_le_to_cpu64 (entry.end)
 		      - grub_le_to_cpu64 (entry.start) + 1);
 	  part.offset = entries;
-	  part.index = i;
+	  part.number = i;
+	  part.index = last_offset;
 	  part.partmap = &grub_gpt_partition_map;
-	  part.data = &entry;
+	  grub_memcpy (part.data, &entry, sizeof (entry));
 
 	  grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", i,
 			(unsigned long long) part.start,
 			(unsigned long long) part.len);
 
 	  if (hook (disk, &part))
-	    return 1;
+	    return grub_errno;
 	}
 
       last_offset += grub_le_to_cpu32 (gpt.partentry_size);
@@ -109,67 +109,9 @@ gpt_partition_map_iterate (grub_disk_t disk,
 	  entries++;
 	}
     }
+  grub_free (part.data);
 
-  return 0;
-}
-
-
-static grub_partition_t
-gpt_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  gpt_partition_map_iterate (disk, find_func);
-  if (grub_errno)
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-gpt_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
+  return GRUB_ERR_NONE;
 }
 
 \f
@@ -178,8 +120,6 @@ static struct grub_partition_map grub_gpt_partition_map =
   {
     .name = "gpt_partition_map",
     .iterate = gpt_partition_map_iterate,
-    .probe = gpt_partition_map_probe,
-    .get_name = gpt_partition_map_get_name
   };
 
 GRUB_MOD_INIT(gpt_partition_map)
diff --git a/partmap/msdos.c b/partmap/msdos.c
index 9fc620d..dda6b59 100644
--- a/partmap/msdos.c
+++ b/partmap/msdos.c
@@ -27,85 +27,19 @@
 static struct grub_partition_map grub_msdos_partition_map;
 \f
 
-/* Parse the partition representation in STR and return a partition.  */
-static grub_partition_t
-grub_partition_parse (const char *str)
-{
-  grub_partition_t p;
-  struct grub_msdos_partition *pcdata;
-
-  char *s = (char *) str;
-
-  p = (grub_partition_t) grub_malloc (sizeof (*p));
-  if (! p)
-    return 0;
-
-  pcdata = (struct grub_msdos_partition *) grub_malloc (sizeof (*pcdata));
-  if (! pcdata)
-    goto fail;
-
-  p->data = pcdata;
-  p->partmap = &grub_msdos_partition_map;
-
-  /* Initialize some of the fields with invalid values.  */
-  pcdata->bsd_part = pcdata->dos_type = pcdata->bsd_type = p->index = -1;
-
-  /* Get the DOS partition number. The number is counted from one for
-     the user interface, and from zero internally.  */
-  pcdata->dos_part = grub_strtoul (s, &s, 0) - 1;
-
-  if (grub_errno)
-    {
-      /* Not found. Maybe only a BSD label is specified.  */
-      pcdata->dos_part = -1;
-      grub_errno = GRUB_ERR_NONE;
-    }
-  else if (*s == ',')
-    s++;
-
-  if (*s)
-    {
-      if (*s >= 'a' && *s <= 'h')
-	{
-	  pcdata->bsd_part = *s - 'a';
-	  s++;
-	}
-
-      if (*s)
-	goto fail;
-    }
-
-  if (pcdata->dos_part == -1 && pcdata->bsd_part == -1)
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  grub_free (pcdata);
-  grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-  return 0;
-}
-
 static grub_err_t
 pc_partition_map_iterate (grub_disk_t disk,
 			  int (*hook) (grub_disk_t disk,
 				       const grub_partition_t partition))
 {
   struct grub_partition p;
-  struct grub_msdos_partition pcdata;
   struct grub_msdos_partition_mbr mbr;
-  struct grub_msdos_partition_disk_label label;
-  struct grub_disk raw;
-
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
+  grub_disk_addr_t ext_offset;
 
   p.offset = 0;
-  pcdata.ext_offset = 0;
-  pcdata.dos_part = -1;
-  p.data = &pcdata;
+  ext_offset = 0;
+  p.data = 0;
+  p.number = -1;
   p.partmap = &grub_msdos_partition_map;
 
   while (1)
@@ -114,7 +48,7 @@ pc_partition_map_iterate (grub_disk_t disk,
       struct grub_msdos_partition_entry *e;
 
       /* Read the MBR.  */
-      if (grub_disk_read (&raw, p.offset, 0, sizeof (mbr), &mbr))
+      if (grub_disk_read (disk, p.offset, 0, sizeof (mbr), &mbr))
 	goto finish;
 
       /* Check if it is valid.  */
@@ -132,13 +66,10 @@ pc_partition_map_iterate (grub_disk_t disk,
 
 	  p.start = p.offset + grub_le_to_cpu32 (e->start);
 	  p.len = grub_le_to_cpu32 (e->length);
-	  pcdata.bsd_part = -1;
-	  pcdata.dos_type = e->type;
-	  pcdata.bsd_type = -1;
 
 	  grub_dprintf ("partition",
 			"partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n",
-			p.index, e->flag, pcdata.dos_type,
+			p.index, e->flag, e->type,
 			(unsigned long long) p.start,
 			(unsigned long long) p.len);
 
@@ -150,59 +81,15 @@ pc_partition_map_iterate (grub_disk_t disk,
 	  if (! grub_msdos_partition_is_empty (e->type)
 	      && ! grub_msdos_partition_is_extended (e->type))
 	    {
-	      pcdata.dos_part++;
+	      p.number++;
 
 	      if (hook (disk, &p))
-		return 1;
-
-	      /* Check if this is a BSD partition.  */
-	      if (grub_msdos_partition_is_bsd (e->type))
-		{
-		  /* Check if the BSD label is within the DOS partition.  */
-		  if (p.len <= GRUB_PC_PARTITION_BSD_LABEL_SECTOR)
-		    {
-		      grub_dprintf ("partition", "no space for disk label\n");
-		      continue;
-		    }
-		  /* Read the BSD label.  */
-		  if (grub_disk_read (&raw,
-				      (p.start
-				       + GRUB_PC_PARTITION_BSD_LABEL_SECTOR),
-				      0,
-				      sizeof (label),
-				      &label))
-		    goto finish;
-
-		  /* Check if it is valid.  */
-		  if (label.magic
-		      != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
-		    {
-		      grub_dprintf ("partition",
-				    "invalid disk label magic 0x%x on partition %d\n",
-				    label.magic, p.index);
-		      continue;
-		    }
-		  for (pcdata.bsd_part = 0;
-		       pcdata.bsd_part < grub_cpu_to_le16 (label.num_partitions);
-		       pcdata.bsd_part++)
-		    {
-		      struct grub_msdos_partition_bsd_entry *be
-			= label.entries + pcdata.bsd_part;
-
-		      p.start = grub_le_to_cpu32 (be->offset);
-		      p.len = grub_le_to_cpu32 (be->size);
-		      pcdata.bsd_type = be->fs_type;
-
-		      if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
-			if (hook (disk, &p))
-			  return 1;
-		    }
-		}
+		return grub_errno;
 	    }
-	  else if (pcdata.dos_part < 4)
+	  else if (p.number < 4)
 	    /* If this partition is a logical one, shouldn't increase the
 	       partition number.  */
-	    pcdata.dos_part++;
+	    p.number++;
 	}
 
       /* Find an extended partition.  */
@@ -212,9 +99,9 @@ pc_partition_map_iterate (grub_disk_t disk,
 
 	  if (grub_msdos_partition_is_extended (e->type))
 	    {
-	      p.offset = pcdata.ext_offset + grub_le_to_cpu32 (e->start);
-	      if (! pcdata.ext_offset)
-		pcdata.ext_offset = p.offset;
+	      p.offset = ext_offset + grub_le_to_cpu32 (e->start);
+	      if (! ext_offset)
+		ext_offset = p.offset;
 
 	      break;
 	    }
@@ -229,84 +116,12 @@ pc_partition_map_iterate (grub_disk_t disk,
   return grub_errno;
 }
 
-
-static grub_partition_t
-pc_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p;
-  struct grub_msdos_partition *pcdata;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      struct grub_msdos_partition *partdata = partition->data;
-
-      if ((pcdata->dos_part == partdata->dos_part || pcdata->dos_part == -1)
-	  && pcdata->bsd_part == partdata->bsd_part)
-	{
-	  grub_memcpy (p, partition, sizeof (*p));
-	  p->data = pcdata;
-	  grub_memcpy (pcdata, partdata, sizeof (*pcdata));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  p = grub_partition_parse (str);
-  if (! p)
-    return 0;
-
-  pcdata = p->data;
-  pc_partition_map_iterate (disk, find_func);
-  if (grub_errno)
-    goto fail;
-
-  if (p->index < 0)
-    {
-      grub_error (GRUB_ERR_BAD_DEVICE, "no such partition");
-      goto fail;
-    }
-
-  return p;
-
- fail:
-  grub_free (p);
-  grub_free (pcdata);
-  return 0;
-}
-
-
-static char *
-pc_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-  struct grub_msdos_partition *pcdata = p->data;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  if (pcdata->bsd_part < 0)
-    grub_sprintf (name, "%d", pcdata->dos_part + 1);
-  else if (pcdata->dos_part < 0)
-    grub_sprintf (name, "%c", pcdata->bsd_part + 'a');
-  else
-    grub_sprintf (name, "%d,%c", pcdata->dos_part + 1, pcdata->bsd_part + 'a');
-
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_msdos_partition_map =
   {
     .name = "msdos_partition_map",
     .iterate = pc_partition_map_iterate,
-    .probe = pc_partition_map_probe,
-    .get_name = pc_partition_map_get_name
   };
 
 GRUB_MOD_INIT(pc_partition_map)
diff --git a/partmap/sun.c b/partmap/sun.c
index ce6d588..63ba6ae 100644
--- a/partmap/sun.c
+++ b/partmap/sun.c
@@ -88,19 +88,15 @@ sun_partition_map_iterate (grub_disk_t disk,
 					const grub_partition_t partition))
 {
   grub_partition_t p;
-  struct grub_disk raw;
   struct grub_sun_block block;
   int partnum;
 
-  raw = *disk;
-  raw.partition = 0;
-
   p = (grub_partition_t) grub_zalloc (sizeof (struct grub_partition));
   if (! p)
     return grub_errno;
 
   p->partmap = &grub_sun_partition_map;
-  if (grub_disk_read (&raw, 0, 0, sizeof (struct grub_sun_block),
+  if (grub_disk_read (disk, 0, 0, sizeof (struct grub_sun_block),
 		      &block) == GRUB_ERR_NONE)
     {
       if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.magic))
@@ -124,7 +120,7 @@ sun_partition_map_iterate (grub_disk_t disk,
 		      * grub_be_to_cpu16 (block.ntrks)
 		      * grub_be_to_cpu16 (block.nsect));
 	  p->len = grub_be_to_cpu32 (desc->num_sectors);
-	  p->index = partnum;
+	  p->number = p->index = partnum;
 	  if (p->len)
 	    {
 	      if (hook (disk, p))
@@ -138,68 +134,11 @@ sun_partition_map_iterate (grub_disk_t disk,
   return grub_errno;
 }
 
-static grub_partition_t
-sun_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-        {
-          p = (grub_partition_t) grub_malloc (sizeof (*p));
-          if (p)
-            grub_memcpy (p, partition, sizeof (*p));
-
-          return 1;
-        }
-
-      return 0;
-    }
-
-  grub_errno = GRUB_ERR_NONE;
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno == GRUB_ERR_NONE)
-    {
-      if (sun_partition_map_iterate (disk, find_func))
-        {
-          grub_free (p);
-          p = 0;
-        }
-    }
-  else
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      p = 0;
-    }
-
-  return p;
-}
-
-static char *
-sun_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (name)
-    grub_sprintf (name, "%d", p->index + 1);
-
-  return name;
-}
-
 /* Partition map type.  */
 static struct grub_partition_map grub_sun_partition_map =
   {
     .name = "sun_partition_map",
     .iterate = sun_partition_map_iterate,
-    .probe = sun_partition_map_probe,
-    .get_name = sun_partition_map_get_name
   };
 
 GRUB_MOD_INIT(sun_partition_map)
diff --git a/parttool/msdospart.c b/parttool/msdospart.c
index 1bb9cd3..2edf825 100644
--- a/parttool/msdospart.c
+++ b/parttool/msdospart.c
@@ -49,7 +49,7 @@ static grub_err_t grub_pcpart_boot (const grub_device_t dev,
 
   index = dev->disk->partition->index;
   part = dev->disk->partition;
-  dev->disk->partition = 0;
+  dev->disk->partition = part->parent;
 
   /* Read the MBR.  */
   if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr))
@@ -96,7 +96,7 @@ static grub_err_t grub_pcpart_type (const grub_device_t dev,
 
   index = dev->disk->partition->index;
   part = dev->disk->partition;
-  dev->disk->partition = 0;
+  dev->disk->partition = part->parent;
 
   /* Read the parttable.  */
   if (grub_disk_read (dev->disk, part->offset, 0,
diff --git a/util/hostdisk.c b/util/hostdisk.c
index 8a3e2ef..6e876df 100644
--- a/util/hostdisk.c
+++ b/util/hostdisk.c
@@ -333,10 +333,13 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
   {
     int is_partition = 0;
     char dev[PATH_MAX];
+    grub_disk_addr_t part_start = 0;
+
+    part_start = grub_partition_get_start (disk->partition);
 
     strcpy (dev, map[disk->id].device);
     if (disk->partition && strncmp (map[disk->id].device, "/dev/", 5) == 0)
-      is_partition = linux_find_partition (dev, disk->partition->start);
+      is_partition = linux_find_partition (dev, part_start);
 
     /* Open the partition.  */
     grub_dprintf ("hostdisk", "opening the device `%s' in open_device()", dev);
@@ -351,7 +354,7 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
     ioctl (fd, BLKFLSBUF, 0);
 
     if (is_partition)
-      sector -= disk->partition->start;
+      sector -= part_start;
   }
 #else /* ! __linux__ */
 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -947,39 +950,25 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
     int find_partition (grub_disk_t disk __attribute__ ((unused)),
 			const grub_partition_t partition)
       {
- 	struct grub_msdos_partition *pcdata = NULL;
-
-	if (strcmp (partition->partmap->name, "msdos_partition_map") == 0)
-	  pcdata = partition->data;
+	grub_disk_addr_t part_start = 0;
+	grub_util_info ("Partition %d starts from %lu",
+			partition->number, partition->start);
 
-	if (pcdata)
-	  {
-	    if (pcdata->bsd_part < 0)
-	      grub_util_info ("DOS partition %d starts from %lu",
-			      pcdata->dos_part, partition->start);
-	    else
-	      grub_util_info ("BSD partition %d,%c starts from %lu",
-			      pcdata->dos_part, pcdata->bsd_part + 'a',
-			      partition->start);
-	  }
-	else
-	  {
-	      grub_util_info ("Partition %d starts from %lu",
-			      partition->index, partition->start);
-	  }
+	part_start = grub_partition_get_start (partition);
 
-	if (hdg.start == partition->start)
+	if (hdg.start == part_start)
 	  {
-	    if (pcdata)
+	    if (partition->parent)
 	      {
-		dos_part = pcdata->dos_part;
-		bsd_part = pcdata->bsd_part;
+		dos_part = partition->parent->number;
+		bsd_part = partition->number;
 	      }
 	    else
 	      {
-		dos_part = partition->index;
+		dos_part = partition->number;
 		bsd_part = -1;
 	      }
+
 	    return 1;
 	  }
 
diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c
index 0dc2e2c..bf435ac 100644
--- a/util/i386/pc/grub-setup.c
+++ b/util/i386/pc/grub-setup.c
@@ -121,15 +121,10 @@ setup (const char *dir,
   int NESTED_FUNC_ATTR find_usable_region_msdos (grub_disk_t disk __attribute__ ((unused)),
 						 const grub_partition_t p)
     {
-      struct grub_msdos_partition *pcdata = p->data;
-
       /* There's always an embed region, and it starts right after the MBR.  */
       embed_region.start = 1;
 
-      /* For its end offset, include as many dummy partitions as we can.  */
-      if (! grub_msdos_partition_is_empty (pcdata->dos_type)
-	  && ! grub_msdos_partition_is_bsd (pcdata->dos_type)
-	  && embed_region.end > p->start)
+      if (embed_region.end > p->start)
 	embed_region.end = p->start;
 
       return 0;
@@ -278,22 +273,19 @@ setup (const char *dir,
       /* Embed information about the installed location.  */
       if (root_dev->disk->partition)
 	{
-	  if (strcmp (root_dev->disk->partition->partmap->name,
-		      "msdos_partition_map") == 0)
+	  if (root_dev->disk->partition->parent)
 	    {
-	      struct grub_msdos_partition *pcdata =
-		root_dev->disk->partition->data;
-	      dos_part = pcdata->dos_part;
-	      bsd_part = pcdata->bsd_part;
+	      if (root_dev->disk->partition->parent->parent)
+		grub_util_error ("Installing on doubly nested partitiond is "
+				 "not supported");
+	      dos_part = root_dev->disk->partition->parent->number;
+	      bsd_part = root_dev->disk->partition->number;
 	    }
-	  else if (strcmp (root_dev->disk->partition->partmap->name,
-			   "gpt_partition_map") == 0)
+	  else
 	    {
-	      dos_part = root_dev->disk->partition->index;
+	      dos_part = root_dev->disk->partition->number;
 	      bsd_part = -1;
 	    }
-	  else
-	    grub_util_error ("No PC style partitions found");
 	}
       else
 	dos_part = bsd_part = -1;
@@ -326,6 +318,8 @@ setup (const char *dir,
   int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk __attribute__ ((unused)),
 					 const grub_partition_t p)
     {
+      if (p->parent)
+	return 0;
       dest_partmap = p->partmap->name;
       return 1;
     }

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-23 22:57                   ` Vladimir 'phcoder' Serbinenko
@ 2009-08-24 13:39                     ` Vladimir 'phcoder' Serbinenko
  2009-08-25 20:14                       ` Vladimir 'phcoder' Serbinenko
  2009-08-25 20:35                       ` Seth Goldberg
  0 siblings, 2 replies; 36+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-08-24 13:39 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 2684 bytes --]

Rediff

On Mon, Aug 24, 2009 at 12:57 AM, Vladimir 'phcoder'
Serbinenko<phcoder@gmail.com> wrote:
> Rediff
> On Mon, Aug 17, 2009 at 4:34 PM, Vladimir 'phcoder'
> Serbinenko<phcoder@gmail.com> wrote:
>> On Mon, Aug 17, 2009 at 4:06 PM, Robert Millan<rmh@aybabtu.com> wrote:
>>> On Mon, Aug 17, 2009 at 03:00:52PM +0200, Vladimir 'phcoder' Serbinenko wrote:
>>>> Rediff and few fixes
>>>
>>> Please note that after what we discussed on IRC, we need to find a solution
>>> that wouldn't make boot time increase linearly with the number of filesystems
>>> or partmaps GRUB supports.
>>>
>> It probe time scales linearly no matter what we do. Fortunately with
>> disk cache few first sectors are read and checked for different
>> signatures which is fast. As for module autoload with search patch it
>> doesn't happen except in the failure to access requested device.
>>> I really think supporting every sort of combination is too extreme.  For
>>> example who would want an msdos/msdos chain?  OpenSolaris creates one, but
>>> it's a false positive.
>>>
>> minix does it and it's not a false positive.
>>> The overall idea *is* nice.  Some combinations (e.g. msdos/bsd) are cleaner
>>> this way, but supporting everything doesn't scale well.
>> AFAIK no partmap goes beyond first 16K for signature checking. Time
>> for signature checking can be neglected and 16K would be read for
>> filesystem probe too. Additionally e.g. (hd0,1) is probed for
>> subpartitions only if (hd0,1,X) is requested or we're scanning through
>> partitions. In last case we're likely to fsprobe partition anyway so
>> it doesn't create any overhead
>>>
>>> Perhaps we can explicitly list which combinations make sense?  So when an
>>> msdos label is found, its partitions are probed for bsd labels too, but not
>>> for msdos labels again, etc.
>>>
>>> --
>>> Robert Millan
>>>
>>>  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
>>>  how) you may access your data; but nobody's threatening your freedom: we
>>>  still allow you to remove your data and not access it at all."
>>>
>>>
>>> _______________________________________________
>>> Grub-devel mailing list
>>> Grub-devel@gnu.org
>>> http://lists.gnu.org/mailman/listinfo/grub-devel
>>>
>>
>>
>>
>> --
>> Regards
>> Vladimir 'phcoder' Serbinenko
>>
>> Personal git repository: http://repo.or.cz/w/grub2/phcoder.git
>>
>
>
>
> --
> Regards
> Vladimir 'phcoder' Serbinenko
>
> Personal git repository: http://repo.or.cz/w/grub2/phcoder.git
>



-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git

[-- Attachment #2: nestpart.diff --]
[-- Type: text/plain, Size: 61753 bytes --]

diff --git a/Changelog.phcoder b/Changelog.phcoder
new file mode 100644
index 0000000..a272618
--- /dev/null
+++ b/Changelog.phcoder
@@ -0,0 +1,73 @@
+2009-06-08  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	Nested partitions
+
+	* commands/blocklist.c (grub_cmd_blocklist): Don't check whether
+	'partition' is NULL, grub_partition_get_start already does that.
+	* commands/loadenv.c (check_blocklists): Likewise.
+	(write_blocklists): Likewise.
+	* conf/common.rmk (grub_probe_SOURCES): Add partmap/bsdlabel.c.
+	(grub_fstest_SOURCES): Likewise.
+	(pkglib_MODULES): Add bsdlabel.mod.
+	(bsdlabel_mod_SOURCES): New variable.
+	(bsdlabel_mod_CFLAGS): Likewise.
+	(bsdlabel_mod_LDFLAGS): Likewise.
+	* conf/i386-coreboot.rmk (grub_emu_SOURCES): Add partmap/bsdlabel.c.
+	* conf/i386-pc.rmk (grub_setup_SOURCES): Likewise.
+	(grub_emu_SOURCES): Likewise.
+	* conf/powerpc-ieee1275.rmk (grub_emu_SOURCES): Likewise.
+	* conf/sparc64-ieee1275.rmk (grub_emu_SOURCES): Likewise.
+	* include/grub/bsdlabel.h: New file.
+	* include/grub/partition.h (grub_partition_map): Remove 'probe' and
+	'get_name'.
+	(grub_partition): Add 'parent' and 'number'.
+	(grub_partition_get_start): Handle nested partitions.
+	* include/grub/pc_partition.h: Remove bsd-related entries.
+	(grub_pc_partition): Remove.
+	* kern/disk.c (grub_disk_close): Free partition data.
+	(grub_disk_adjust_range): Handle nested partitions.
+	* kern/partition.c (grub_partition_map_probe): New function.
+	(grub_partition_probe): Parse name to number, handle subpartitions.
+	(get_partmap): New function.
+	(grub_partition_iterate): Handle subpartitions.
+	(grub_partition_get_name): Likewise.
+	* loader/i386/pc/bsd.c (grub_bsd_get_device): Likewise.
+	* loader/i386/multiboot.c (grub_multiboot_get_bootdev): Likewise.
+	* loader/i386/pc/chainloader.c (grub_chainloader_cmd): Likewise.
+	* partmap/acorn.c (acorn_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	(acorn_partition_map_probe): Remove.
+	(acorn_partition_map_get_name): Likewise.
+	* partmap/amiga.c (amiga_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Set 'index' to 0 since there can be only one partition entry per sector.
+	(amiga_partition_map_probe): Remove.
+	(amiga_partition_map_get_name): Likewise.
+	* partmap/apple.c (apple_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Set 'offset' and 'index' to real positions of partitions.
+	(apple_partition_map_probe): Remove.
+	(apple_partition_map_get_name): Likewise.
+	* partmap/bsdlabel.c: New file.
+	* partmap/gpt.c (gpt_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Allocate 'data' so it can be correctly freed.
+	Set 'index' to offset inside sector.
+	(gpt_partition_map_probe): Remove.
+	(gpt_partition_map_get_name): Likewise.
+	* partmap/pc.c (grub_partition_parse): Remove.
+	(pc_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Make 'ext_offset' a local variable.
+	(pc_partition_map_probe): Remove.
+	(pc_partition_map_get_name): Remove.
+	* partmap/sun.c (sun_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	(sun_partition_map_probe): Remove.
+	(sun_partition_map_get_name): Likewise.
+	* parttool/pcpart.c (grub_pcpart_boot): Handle nested partitions.
+	(grub_pcpart_type): Likewise.
+	* util/hostdisk.c (open_device): Handle new numbering scheme.
+	(grub_util_biosdisk_get_grub_dev): Handle nested partitions.
+	* util/i386/pc/grub-setup.c (setup): Handle new numbering scheme.
+	* util/grub-probe.c (probe_partmap): Handle nested paritions.
diff --git a/commands/blocklist.c b/commands/blocklist.c
index b457b7c..6cc7d69 100644
--- a/commands/blocklist.c
+++ b/commands/blocklist.c
@@ -89,8 +89,7 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)),
     return grub_error (GRUB_ERR_BAD_DEVICE,
 		       "this command is available only for disk devices.");
 
-  if (file->device->disk->partition)
-    part_start = grub_partition_get_start (file->device->disk->partition);
+  part_start = grub_partition_get_start (file->device->disk->partition);
 
   file->read_hook = read_blocklist;
 
diff --git a/commands/loadenv.c b/commands/loadenv.c
index 22665f9..51cffd3 100644
--- a/commands/loadenv.c
+++ b/commands/loadenv.c
@@ -236,10 +236,8 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
   /* One more sanity check. Re-read all sectors by blocklists, and compare
      those with the data read via a file.  */
   disk = file->device->disk;
-  if (disk->partition)
-    part_start = grub_partition_get_start (disk->partition);
-  else
-    part_start = 0;
+
+  part_start = grub_partition_get_start (disk->partition);
 
   buf = grub_envblk_buffer (envblk);
   for (p = blocklists, index = 0; p; p = p->next, index += p->length)
@@ -272,10 +270,7 @@ write_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
 
   buf = grub_envblk_buffer (envblk);
   disk = file->device->disk;
-  if (disk->partition)
-    part_start = grub_partition_get_start (disk->partition);
-  else
-    part_start = 0;
+  part_start = grub_partition_get_start (disk->partition);
 
   index = 0;
   for (p = blocklists; p; p = p->next, index += p->length)
diff --git a/conf/common.rmk b/conf/common.rmk
index c33e800..15ab189 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -19,7 +19,8 @@ grub_probe_SOURCES = util/grub-probe.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c		\
 	\
-	partmap/msdos.c partmap/apple.c partmap/sun.c partmap/gpt.c\
+	partmap/msdos.c partmap/bsdlabel.c partmap/apple.c \
+	partmap/sun.c partmap/gpt.c\
 	kern/fs.c kern/env.c fs/fshelp.c			\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c grub_probe_init.c
 
@@ -40,8 +41,8 @@ grub_fstest_SOURCES = util/grub-fstest.c util/hostfs.c util/misc.c 	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c			\
 	fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c			\
 	\
-	kern/partition.c partmap/msdos.c partmap/apple.c partmap/sun.c	\
-	partmap/gpt.c							\
+	kern/partition.c partmap/msdos.c partmap/bsdlabel.c		\
+	partmap/apple.c partmap/sun.c partmap/gpt.c			\
 	kern/fs.c kern/env.c fs/fshelp.c disk/raid.c			\
 	disk/raid5_recover.c disk/raid6_recover.c 			\
 	disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c 		\
@@ -316,6 +317,11 @@ part_gpt_mod_SOURCES = partmap/gpt.c
 part_gpt_mod_CFLAGS = $(COMMON_CFLAGS)
 part_gpt_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+pkglib_MODULES += part_bsd.mod
+part_bsd_mod_SOURCES = partmap/bsdlabel.c
+part_bsd_mod_CFLAGS = $(COMMON_CFLAGS)
+part_bsd_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # Special disk structures and generic drivers
 
 pkglib_MODULES += raid.mod raid5rec.mod raid6rec.mod mdraid.mod dm_nv.mod \
diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk
index de30041..64fe91e 100644
--- a/conf/i386-coreboot.rmk
+++ b/conf/i386-coreboot.rmk
@@ -134,8 +134,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c       \
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c          \
-	partmap/amiga.c	partmap/apple.c partmap/msdos.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/msdos.c			\
+	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c partmap/gpt.c	\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk
index 98aaf58..bebf905 100644
--- a/conf/i386-ieee1275.rmk
+++ b/conf/i386-ieee1275.rmk
@@ -88,8 +88,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c		\
-	partmap/amiga.c	partmap/apple.c partmap/msdos.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/msdos.c			\
+	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c partmap/gpt.c	\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index 13aaa26..7e55a70 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -104,7 +104,7 @@ grub_setup_SOURCES = util/i386/pc/grub-setup.c util/hostdisk.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c			\
 	\
-	partmap/msdos.c partmap/gpt.c				\
+	partmap/msdos.c partmap/bsdlabel.c partmap/gpt.c		\
 	\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
 	util/raid.c util/lvm.c					\
@@ -140,8 +140,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/menu_text.c						\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c		\
-	partmap/amiga.c	partmap/apple.c partmap/msdos.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/bsdlabel.c 		\
+	partmap/msdos.c partmap/sun.c partmap/acorn.c partmap/gpt.c	\
 	\
 	fs/affs.c fs/cpio.c  fs/fat.c fs/ext2.c fs/hfs.c		\
 	fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c		\
diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk
index c1c04e4..bf67daa 100644
--- a/conf/powerpc-ieee1275.rmk
+++ b/conf/powerpc-ieee1275.rmk
@@ -69,8 +69,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c 	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c				\
-	partmap/amiga.c	partmap/apple.c partmap/msdos.c partmap/sun.c	\
-	partmap/acorn.c							\
+	partmap/amiga.c	partmap/apple.c partmap/msdos.c 		\
+	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c		\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk
index c3ecba2..eeb03f8 100644
--- a/conf/sparc64-ieee1275.rmk
+++ b/conf/sparc64-ieee1275.rmk
@@ -80,8 +80,8 @@ grub_setup_SOURCES = util/sparc64/ieee1275/grub-setup.c util/hostdisk.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c			\
 	\
-	partmap/amiga.c	partmap/apple.c partmap/msdos.c		\
-	partmap/sun.c partmap/acorn.c				\
+	partmap/amiga.c	partmap/apple.c partmap/msdos.c 	\
+	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c	\
 	\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
 	util/raid.c util/lvm.c					\
diff --git a/include/grub/bsdlabel.h b/include/grub/bsdlabel.h
new file mode 100644
index 0000000..0139b42
--- /dev/null
+++ b/include/grub/bsdlabel.h
@@ -0,0 +1,89 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2004,2007  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_BSDLABEL_PARTITION_HEADER
+#define GRUB_BSDLABEL_PARTITION_HEADER	1
+
+/* Constants for BSD disk label.  */
+#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR	1
+#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC	0x82564557
+
+/* BSD partition types.  */
+#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED	0
+#define GRUB_PC_PARTITION_BSD_TYPE_SWAP		1
+#define GRUB_PC_PARTITION_BSD_TYPE_V6		2
+#define GRUB_PC_PARTITION_BSD_TYPE_V7		3
+#define GRUB_PC_PARTITION_BSD_TYPE_SYSV		4
+#define GRUB_PC_PARTITION_BSD_TYPE_V71K		5
+#define GRUB_PC_PARTITION_BSD_TYPE_V8		6
+#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS	7
+#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS	8
+#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS	9
+#define GRUB_PC_PARTITION_BSD_TYPE_OTHER	10
+#define GRUB_PC_PARTITION_BSD_TYPE_HPFS		11
+#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660	12
+#define GRUB_PC_PARTITION_BSD_TYPE_BOOT		13
+
+/* FreeBSD-specific types.  */
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM	14
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID	15
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2	21
+
+/* NetBSD-specific types.  */
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_ADOS	14
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_HFS	15
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE	16
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS	17
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_NTFS	18
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_RAID	19
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_CCD	20
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_JFS2	21
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS	22
+
+/* OpenBSD-specific types.  */
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS	14
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_HFS	15
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE	16
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS	17
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS	18
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_RAID	19
+
+/* The BSD partition entry.  */
+struct grub_pc_partition_bsd_entry
+{
+  grub_uint32_t size;
+  grub_uint32_t offset;
+  grub_uint32_t fragment_size;
+  grub_uint8_t fs_type;
+  grub_uint8_t fs_fragments;
+  grub_uint16_t fs_cylinders;
+} __attribute__ ((packed));
+
+/* The BSD disk label. Only define members useful for GRUB.  */
+struct grub_pc_partition_disk_label
+{
+  grub_uint32_t magic;
+  grub_uint8_t padding[128];
+  grub_uint32_t magic2;
+  grub_uint16_t checksum;
+  grub_uint16_t num_partitions;
+  grub_uint32_t boot_size;
+  grub_uint32_t superblock_size;
+} __attribute__ ((packed));
+
+#endif /* ! GRUB_PC_PARTITION_HEADER */
diff --git a/include/grub/msdos_partition.h b/include/grub/msdos_partition.h
index 273d8c9..650d784 100644
--- a/include/grub/msdos_partition.h
+++ b/include/grub/msdos_partition.h
@@ -53,75 +53,6 @@
 #define GRUB_PC_PARTITION_TYPE_GPT_DISK		0xee
 #define GRUB_PC_PARTITION_TYPE_LINUX_RAID	0xfd
 
-/* Constants for BSD disk label.  */
-#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR	1
-#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC	0x82564557
-#define GRUB_PC_PARTITION_BSD_MAX_ENTRIES	8
-
-/* BSD partition types.  */
-#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED	0
-#define GRUB_PC_PARTITION_BSD_TYPE_SWAP		1
-#define GRUB_PC_PARTITION_BSD_TYPE_V6		2
-#define GRUB_PC_PARTITION_BSD_TYPE_V7		3
-#define GRUB_PC_PARTITION_BSD_TYPE_SYSV		4
-#define GRUB_PC_PARTITION_BSD_TYPE_V71K		5
-#define GRUB_PC_PARTITION_BSD_TYPE_V8		6
-#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS	7
-#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS	8
-#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS	9
-#define GRUB_PC_PARTITION_BSD_TYPE_OTHER	10
-#define GRUB_PC_PARTITION_BSD_TYPE_HPFS		11
-#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660	12
-#define GRUB_PC_PARTITION_BSD_TYPE_BOOT		13
-
-/* FreeBSD-specific types.  */
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM	14
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID	15
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2	21
-
-/* NetBSD-specific types.  */
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_ADOS	14
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_HFS	15
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE	16
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS	17
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_NTFS	18
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_RAID	19
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_CCD	20
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_JFS2	21
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS	22
-
-/* OpenBSD-specific types.  */
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS	14
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_HFS	15
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE	16
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS	17
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS	18
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_RAID	19
-
-/* The BSD partition entry.  */
-struct grub_msdos_partition_bsd_entry
-{
-  grub_uint32_t size;
-  grub_uint32_t offset;
-  grub_uint32_t fragment_size;
-  grub_uint8_t fs_type;
-  grub_uint8_t fs_fragments;
-  grub_uint16_t fs_cylinders;
-} __attribute__ ((packed));
-
-/* The BSD disk label. Only define members useful for GRUB.  */
-struct grub_msdos_partition_disk_label
-{
-  grub_uint32_t magic;
-  grub_uint8_t padding[128];
-  grub_uint32_t magic2;
-  grub_uint16_t checksum;
-  grub_uint16_t num_partitions;
-  grub_uint32_t boot_size;
-  grub_uint32_t superblock_size;
-  struct grub_msdos_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES];
-} __attribute__ ((packed));
-
 /* The partition entry.  */
 struct grub_msdos_partition_entry
 {
@@ -168,23 +99,6 @@ struct grub_msdos_partition_mbr
 } __attribute__ ((packed));
 
 \f
-struct grub_msdos_partition
-{
-    /* The DOS partition number.  */
-  int dos_part;
-
-  /* The BSD partition number (a == 0).  */
-  int bsd_part;
-
-  /* The DOS partition type.  */
-  int dos_type;
-
-  /* The BSD partition type.  */
-  int bsd_type;
-
-  /* The offset of the extended partition.  */
-  unsigned long ext_offset;
-};
 
 static inline int
 grub_msdos_partition_is_empty (int type)
@@ -200,12 +114,4 @@ grub_msdos_partition_is_extended (int type)
 	  || type == GRUB_PC_PARTITION_TYPE_LINUX_EXTENDED);
 }
 
-static inline int
-grub_msdos_partition_is_bsd (int type)
-{
-  return (type == GRUB_PC_PARTITION_TYPE_FREEBSD
-	  || type == GRUB_PC_PARTITION_TYPE_OPENBSD
-	  || type == GRUB_PC_PARTITION_TYPE_NETBSD);
-}
-
 #endif /* ! GRUB_PC_PARTITION_HEADER */
diff --git a/include/grub/partition.h b/include/grub/partition.h
index d35658c..5e8c476 100644
--- a/include/grub/partition.h
+++ b/include/grub/partition.h
@@ -36,13 +36,6 @@ struct grub_partition_map
 			 int (*hook) (struct grub_disk *disk,
 				      const grub_partition_t partition));
 
-  /* Return the partition named STR on the disk DISK.  */
-  grub_partition_t (*probe) (struct grub_disk *disk,
-			     const char *str);
-
-  /* Return the name of the partition PARTITION.  */
-  char *(*get_name) (const grub_partition_t partition);
-
   /* The next partition map type.  */
   struct grub_partition_map *next;
 };
@@ -51,6 +44,9 @@ typedef struct grub_partition_map *grub_partition_map_t;
 /* Partition description.  */
 struct grub_partition
 {
+  /* The partition number.  */
+  int number;
+
   /* The start sector.  */
   grub_disk_addr_t start;
 
@@ -66,6 +62,9 @@ struct grub_partition
   /* Partition map type specific data.  */
   void *data;
 
+  /* Parent partition map.  */
+  struct grub_partition *parent;
+
   /* The type partition map.  */
   grub_partition_map_t partmap;
 };
@@ -101,7 +100,13 @@ void grub_apple_partition_map_fini (void);
 static inline grub_disk_addr_t
 grub_partition_get_start (const grub_partition_t p)
 {
-  return p->start;
+  grub_partition_t part;
+  grub_uint64_t part_start = 0;
+
+  for (part = p; part; part = part->parent)
+    part_start += part->start;
+
+  return part_start;
 }
 
 static inline grub_uint64_t
diff --git a/kern/disk.c b/kern/disk.c
index e463626..657ac8d 100644
--- a/kern/disk.c
+++ b/kern/disk.c
@@ -330,6 +330,7 @@ grub_disk_open (const char *name)
 void
 grub_disk_close (grub_disk_t disk)
 {
+  grub_partition_t part;
   grub_dprintf ("disk", "Closing `%s'.\n", disk->name);
 
   if (disk->dev && disk->dev->close)
@@ -338,7 +339,13 @@ grub_disk_close (grub_disk_t disk)
   /* Reset the timer.  */
   grub_last_time = grub_get_time_ms ();
 
-  grub_free (disk->partition);
+  while (disk->partition)
+    {
+      part = disk->partition->parent;
+      grub_free (disk->partition->data);
+      grub_free (disk->partition);
+      disk->partition = part;
+    }
   grub_free ((void *) disk->name);
   grub_free (disk);
 }
@@ -349,18 +356,19 @@ grub_disk_close (grub_disk_t disk)
    - Verify that the range is inside the partition.  */
 static grub_err_t
 grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
-		       grub_off_t *offset, grub_size_t size)
+			grub_off_t *offset, grub_size_t size)
 {
+  grub_partition_t part;
   *sector += *offset >> GRUB_DISK_SECTOR_BITS;
   *offset &= GRUB_DISK_SECTOR_SIZE - 1;
 
-  if (disk->partition)
+  for (part = disk->partition; part; part = part->parent)
     {
       grub_disk_addr_t start;
       grub_uint64_t len;
 
-      start = grub_partition_get_start (disk->partition);
-      len = grub_partition_get_len (disk->partition);
+      start = part->start;
+      len = part->len;
 
       if (*sector >= len
 	  || len - *sector < ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
diff --git a/kern/partition.c b/kern/partition.c
index 4d5c63a..4bcd8c7 100644
--- a/kern/partition.c
+++ b/kern/partition.c
@@ -17,6 +17,7 @@
  */
 
 #include <grub/misc.h>
+#include <grub/mm.h>
 #include <grub/partition.h>
 #include <grub/disk.h>
 
@@ -54,17 +55,58 @@ grub_partition_map_iterate (int (*hook) (const grub_partition_map_t partmap))
   return 0;
 }
 
+static grub_partition_t
+grub_partition_map_probe (const grub_partition_map_t partmap,
+			  grub_disk_t disk, int partnum)
+{
+  grub_partition_t p = 0;
+
+  auto int find_func (grub_disk_t d, const grub_partition_t partition);
+
+  int find_func (grub_disk_t d __attribute__ ((unused)),
+		 const grub_partition_t partition)
+    {
+      if (partnum == partition->number)
+	{
+	  p = (grub_partition_t) grub_malloc (sizeof (*p));
+	  if (! p)
+	    return 1;
+
+	  grub_memcpy (p, partition, sizeof (*p));
+	  return 1;
+	}
+
+      return 0;
+    }
+
+  partmap->iterate (disk, find_func);
+  if (grub_errno)
+    goto fail;
+
+  return p;
+
+ fail:
+  grub_free (p);
+  return 0;
+}
+
 grub_partition_t
 grub_partition_probe (struct grub_disk *disk, const char *str)
 {
   grub_partition_t part = 0;
+  grub_partition_t curpart = 0;
+  grub_partition_t tail;
+  const char *ptr;
+  int num;
 
   auto int part_map_probe (const grub_partition_map_t partmap);
 
   int part_map_probe (const grub_partition_map_t partmap)
     {
-      part = partmap->probe (disk, str);
-      if (part)
+      disk->partition = part;
+      curpart = grub_partition_map_probe (partmap, disk, num);
+      disk->partition = tail;
+      if (curpart)
 	return 1;
 
       if (grub_errno == GRUB_ERR_BAD_PART_TABLE)
@@ -77,27 +119,54 @@ grub_partition_probe (struct grub_disk *disk, const char *str)
       return 1;
     }
 
-  /* Use the first partition map type found.  */
-  grub_partition_map_iterate (part_map_probe);
+  part = tail = disk->partition;
+
+  for (ptr = str; *ptr;)
+    {
+      /* BSD-like partition specification.  */
+      if (*ptr >= 'a' && *ptr <= 'z')
+	num = *(ptr++) - 'a';
+      else
+	num = grub_strtoul (ptr, (char **) &ptr, 0) - 1;
+
+      curpart = 0;
+      /* Use the first partition map type found.  */
+      grub_partition_map_iterate (part_map_probe);
+
+      if (! curpart)
+	{
+	  while (part)
+	    {
+	      curpart = part->parent;
+	      grub_free (part);
+	      part = curpart;
+	    }
+	  return 0;
+	}
+      curpart->parent = part;
+      part = curpart;
+      if (! ptr || *ptr != ',')
+	break;
+      ptr++;
+    }
 
   return part;
 }
 
-int
-grub_partition_iterate (struct grub_disk *disk,
-			int (*hook) (grub_disk_t disk,
-				     const grub_partition_t partition))
+static grub_partition_map_t
+get_partmap (struct grub_disk *disk)
 {
   grub_partition_map_t partmap = 0;
-  int ret = 0;
-
+  struct grub_partition part;
+  int found = 0;
   auto int part_map_iterate (const grub_partition_map_t p);
   auto int part_map_iterate_hook (grub_disk_t d,
 				  const grub_partition_t partition);
-
   int part_map_iterate_hook (grub_disk_t d __attribute__ ((unused)),
-			     const grub_partition_t partition __attribute__ ((unused)))
+			     const grub_partition_t partition)
     {
+      found = 1;
+      part = *partition;
       return 1;
     }
 
@@ -106,22 +175,58 @@ grub_partition_iterate (struct grub_disk *disk,
       grub_dprintf ("partition", "Detecting %s...\n", p->name);
       p->iterate (disk, part_map_iterate_hook);
 
-      if (grub_errno != GRUB_ERR_NONE)
+      if (grub_errno != GRUB_ERR_NONE || ! found)
 	{
 	  /* Continue to next partition map type.  */
 	  grub_dprintf ("partition", "%s detection failed.\n", p->name);
 	  grub_errno = GRUB_ERR_NONE;
 	  return 0;
 	}
+      grub_free (part.data);
 
       grub_dprintf ("partition", "%s detection succeeded.\n", p->name);
       partmap = p;
       return 1;
     }
-
   grub_partition_map_iterate (part_map_iterate);
-  if (partmap)
-    ret = partmap->iterate (disk, hook);
+  return partmap;
+}
+
+int
+grub_partition_iterate (struct grub_disk *disk,
+			int (*hook) (grub_disk_t disk,
+				     const grub_partition_t partition))
+{
+  int ret = 0;
+
+  auto int part_iterate (grub_disk_t dsk, const grub_partition_t p);
+
+  int part_iterate (grub_disk_t dsk,
+		    const grub_partition_t partition)
+    {
+      struct grub_partition p = *partition;
+      grub_partition_map_t partmap = 0;
+      p.parent = dsk->partition;
+      dsk->partition = 0;
+      if (hook (dsk, &p))
+	  return 1;
+      if (p.start != 0)
+	{
+	  dsk->partition = &p;
+	  partmap = get_partmap (dsk);
+	  if (partmap)
+	    ret = partmap->iterate (dsk, part_iterate);
+	}
+      dsk->partition = p.parent;
+      return ret;
+    }
+
+  {
+    grub_partition_map_t partmap = 0;
+    partmap = get_partmap (disk);
+    if (partmap)
+      ret = partmap->iterate (disk, part_iterate);
+  }
 
   return ret;
 }
@@ -129,5 +234,30 @@ grub_partition_iterate (struct grub_disk *disk,
 char *
 grub_partition_get_name (const grub_partition_t partition)
 {
-  return partition->partmap->get_name (partition);
+  char *out = 0;
+  /* Even on 64-bit machines this buffer is enough to hold longest number.  */
+  char buf[25];
+  int curlen = 0;
+  grub_partition_t part;
+  for (part = partition; part; part = part->parent)
+    {
+      int strl;
+      grub_sprintf (buf, "%d", part->number + 1);
+      strl = grub_strlen (buf);
+      if (curlen)
+	{
+	  out = grub_realloc (out, curlen + strl + 2);
+	  grub_memcpy (out + strl + 1, out, curlen);
+	  out[curlen + 1 + strl] = 0;
+	  grub_memcpy (out, buf, strl);
+	  out[strl] = ',';
+	  curlen = curlen + 1 + strl;
+	}
+      else
+	{
+	  curlen = strl;
+	  out = grub_strdup (buf);
+	}
+    }
+  return out;
 }
diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c
index 1b6f190..47db493 100644
--- a/loader/i386/bsd.c
+++ b/loader/i386/bsd.c
@@ -135,7 +135,6 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
 		     grub_uint32_t * unit,
 		     grub_uint32_t * slice, grub_uint32_t * part)
 {
-  char *p;
   grub_device_t dev; 
 
   *biosdev = grub_get_root_biosnumber () & 0xff;
@@ -145,21 +144,13 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-
-      p = dev->disk->partition->partmap->get_name (dev->disk->partition);
-      if (p)
+      if (dev->disk->partition->parent)
 	{
-	  if ((p[0] >= '0') && (p[0] <= '9'))
-	    {
-	      *slice = grub_strtoul (p, &p, 0);
-
-	      if ((p) && (p[0] == ','))
-		p++;
-	    }
-
-	  if ((p[0] >= 'a') && (p[0] <= 'z'))
-	    *part = p[0] - 'a';
+	  *part = dev->disk->partition->number;
+	  *slice = dev->disk->partition->parent->number + 1;
 	}
+      else
+	*slice = dev->disk->partition->number + 1;
     }
   if (dev)
     grub_device_close (dev);
diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c
index 8c3139b..719a51d 100644
--- a/loader/i386/multiboot.c
+++ b/loader/i386/multiboot.c
@@ -155,7 +155,6 @@ static int
 grub_multiboot_get_bootdev (grub_uint32_t *bootdev)
 {
 #ifdef GRUB_MACHINE_PCBIOS
-  char *p;
   grub_uint32_t biosdev, slice = ~0, part = ~0;
   grub_device_t dev;
 
@@ -164,21 +163,13 @@ grub_multiboot_get_bootdev (grub_uint32_t *bootdev)
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-
-      p = dev->disk->partition->partmap->get_name (dev->disk->partition);
-      if (p)
+      if (dev->disk->partition->parent)
 	{
-	  if ((p[0] >= '0') && (p[0] <= '9'))
-	    {
-	      slice = grub_strtoul (p, &p, 0) - 1;
-
-	      if ((p) && (p[0] == ','))
-		p++;
-	    }
-
-	  if ((p[0] >= 'a') && (p[0] <= 'z'))
-	    part = p[0] - 'a';
+	  part = dev->disk->partition->number;
+	  slice = dev->disk->partition->parent->number;
 	}
+      else
+	slice = dev->disk->partition->number;
     }
   if (dev)
     grub_device_close (dev);
diff --git a/loader/i386/pc/chainloader.c b/loader/i386/pc/chainloader.c
index caf1450..79bc290 100644
--- a/loader/i386/pc/chainloader.c
+++ b/loader/i386/pc/chainloader.c
@@ -31,6 +31,7 @@
 #include <grub/machine/memory.h>
 #include <grub/dl.h>
 #include <grub/command.h>
+#include <grub/pc_partition.h>
 #include <grub/machine/biosnum.h>
 
 static grub_dl_t my_mod;
@@ -94,10 +95,22 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-      grub_disk_read (dev->disk, dev->disk->partition->offset, 446, 64,
-		      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
-      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
-			    + (dev->disk->partition->index << 4));
+      grub_disk_t disk = dev->disk;
+
+      if (disk)
+	{
+	  grub_partition_t p = disk->partition;
+
+	  if (p && grub_strcmp (p->partmap->name, "pc_partition_map") == 0)
+	    {
+	      disk->partition = p->parent;
+	      grub_disk_read (disk, p->offset, 446, 64,
+			      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
+	      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
+				    + (p->index << 4));
+	      disk->partition = p;
+	    }
+	}
     }
 
   if (dev)
diff --git a/partmap/acorn.c b/partmap/acorn.c
index e005975..af9498e 100644
--- a/partmap/acorn.c
+++ b/partmap/acorn.c
@@ -96,21 +96,17 @@ acorn_partition_map_iterate (grub_disk_t disk,
 					  const grub_partition_t partition))
 {
   struct grub_partition part;
-  struct grub_disk raw;
   struct linux_part map[LINUX_MAP_ENTRIES];
   int i;
-  grub_disk_addr_t sector;
+  grub_disk_addr_t sector = 0;
   grub_err_t err;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
-  err = acorn_partition_map_find (&raw, map, &sector);
+  err = acorn_partition_map_find (disk, map, &sector);
   if (err)
     return err;
 
   part.partmap = &grub_acorn_partition_map;
+  part.data = 0;
 
   for (i = 0; i != LINUX_MAP_ENTRIES; ++i)
     {
@@ -121,7 +117,7 @@ acorn_partition_map_iterate (grub_disk_t disk,
       part.start = sector + map[i].start;
       part.len = map[i].size;
       part.offset = 6;
-      part.index = i;
+      part.number = part.index = i;
 
       if (hook (disk, &part))
 	return grub_errno;
@@ -130,60 +126,6 @@ acorn_partition_map_iterate (grub_disk_t disk,
   return GRUB_ERR_NONE;
 }
 
-
-static grub_partition_t
-acorn_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  struct linux_part map[LINUX_MAP_ENTRIES];
-  struct grub_disk raw = *disk;
-  unsigned long partnum = grub_strtoul (str, 0, 10) - 1;
-  grub_disk_addr_t sector;
-  grub_err_t err;
-  grub_partition_t p;
-
-  /* Enforce raw disk access.  */
-  raw.partition = 0;
-
-  /* Get the partition number.  */
-  if (partnum > LINUX_MAP_ENTRIES)
-    goto fail;
-
-  err = acorn_partition_map_find (&raw, map, &sector);
-  if (err)
-    return 0;
-
-  if (map[partnum].magic != LINUX_NATIVE_MAGIC
-      && map[partnum].magic != LINUX_SWAP_MAGIC)
-    goto fail;
-
-  p = grub_malloc (sizeof (struct grub_partition));
-  if (! p)
-    return 0;
-
-  p->start = sector + map[partnum].start;
-  p->len = map[partnum].size;
-  p->offset = 6;
-  p->index = partnum;
-  return p;
-
-fail:
-  grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-  return 0;
-}
-
-
-static char *
-acorn_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
 \f
 
 /* Partition map type.  */
@@ -191,8 +133,6 @@ static struct grub_partition_map grub_acorn_partition_map =
 {
   .name = "part_acorn",
   .iterate = acorn_partition_map_iterate,
-  .probe = acorn_partition_map_probe,
-  .get_name = acorn_partition_map_get_name
 };
 
 GRUB_MOD_INIT(acorn_partition_map)
diff --git a/partmap/amiga.c b/partmap/amiga.c
index dce9f4f..27ccf95 100644
--- a/partmap/amiga.c
+++ b/partmap/amiga.c
@@ -76,20 +76,15 @@ amiga_partition_map_iterate (grub_disk_t disk,
 {
   struct grub_partition part;
   struct grub_amiga_rdsk rdsk;
-  struct grub_disk raw;
   int partno = 0;
   int next = -1;
   unsigned pos;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   /* The RDSK block is one of the first 15 blocks.  */
   for (pos = 0; pos < 15; pos++)
     {
       /* Read the RDSK block which is a descriptor for the entire disk.  */
-      if (grub_disk_read (&raw, pos, 0, sizeof (rdsk), &rdsk))
+      if (grub_disk_read (disk, pos, 0, sizeof (rdsk), &rdsk))
 	return grub_errno;
 
       if (grub_strcmp ((char *) rdsk.magic, "RDSK") == 0)
@@ -104,13 +99,15 @@ amiga_partition_map_iterate (grub_disk_t disk,
     return grub_error (GRUB_ERR_BAD_PART_TABLE,
 		       "Amiga partition map not found.");
 
+  part.data = 0;
+
   /* The end of the partition list is marked using "-1".  */
   while (next != -1)
     {
       struct grub_amiga_partition apart;
 
       /* Read the RDSK block which is a descriptor for the entire disk.  */
-      if (grub_disk_read (&raw, next, 0, sizeof (apart), &apart))
+      if (grub_disk_read (disk, next, 0, sizeof (apart), &apart))
 	return grub_errno;
 
       /* Calculate the first block and the size of the partition.  */
@@ -123,7 +120,8 @@ amiga_partition_map_iterate (grub_disk_t disk,
 		  * grub_be_to_cpu32 (apart.block_per_track));
 
       part.offset = (grub_off_t) next * 512;
-      part.index = partno;
+      part.number = partno;
+      part.index = 0;
       part.partmap = &grub_amiga_partition_map;
 
       if (hook (disk, &part))
@@ -136,72 +134,12 @@ amiga_partition_map_iterate (grub_disk_t disk,
   return 0;
 }
 
-
-static grub_partition_t
-amiga_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  if (amiga_partition_map_iterate (disk, find_func))
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-amiga_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_amiga_partition_map =
   {
     .name = "part_amiga",
     .iterate = amiga_partition_map_iterate,
-    .probe = amiga_partition_map_probe,
-    .get_name = amiga_partition_map_get_name
   };
 
 GRUB_MOD_INIT(amiga_partition_map)
diff --git a/partmap/apple.c b/partmap/apple.c
index 4dea55a..3534ac3 100644
--- a/partmap/apple.c
+++ b/partmap/apple.c
@@ -105,17 +105,12 @@ apple_partition_map_iterate (grub_disk_t disk,
   struct grub_partition part;
   struct grub_apple_header aheader;
   struct grub_apple_part apart;
-  struct grub_disk raw;
   int partno = 0, partnum = 0;
   unsigned pos;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   part.partmap = &grub_apple_partition_map;
 
-  if (grub_disk_read (&raw, 0, 0, sizeof (aheader), &aheader))
+  if (grub_disk_read (disk, 0, 0, sizeof (aheader), &aheader))
     return grub_errno;
 
   if (grub_be_to_cpu16 (aheader.magic) != GRUB_APPLE_HEADER_MAGIC)
@@ -127,14 +122,17 @@ apple_partition_map_iterate (grub_disk_t disk,
       goto fail;
     }
 
+  part.data = 0;
   pos = grub_be_to_cpu16 (aheader.blocksize);
 
   do
     {
-      if (grub_disk_read (&raw, pos / GRUB_DISK_SECTOR_SIZE,
-			  pos % GRUB_DISK_SECTOR_SIZE,
-			  sizeof (struct grub_apple_part),  &apart))
-	return grub_errno;
+       part.offset = pos / GRUB_DISK_SECTOR_SIZE;
+       part.index = pos % GRUB_DISK_SECTOR_SIZE;
+
+       if (grub_disk_read (disk, part.offset, part.index,
+			   sizeof (struct grub_apple_part),  &apart))
+	 return grub_errno;
 
       if (grub_be_to_cpu16 (apart.magic) != GRUB_APPLE_PART_MAGIC)
 	{
@@ -156,6 +154,7 @@ apple_partition_map_iterate (grub_disk_t disk,
 	/ GRUB_DISK_SECTOR_SIZE;
       part.offset = pos;
       part.index = partno;
+      part.number = partno;
 
       grub_dprintf ("partition",
 		    "partition %d: name %s, type %s, start 0x%x, len 0x%x\n",
@@ -179,72 +178,12 @@ apple_partition_map_iterate (grub_disk_t disk,
 		     "Apple partition map not found.");
 }
 
-
-static grub_partition_t
-apple_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  if (apple_partition_map_iterate (disk, find_func))
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-apple_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_apple_partition_map =
   {
     .name = "part_apple",
     .iterate = apple_partition_map_iterate,
-    .probe = apple_partition_map_probe,
-    .get_name = apple_partition_map_get_name
   };
 
 GRUB_MOD_INIT(apple_partition_map)
diff --git a/partmap/bsdlabel.c b/partmap/bsdlabel.c
new file mode 100644
index 0000000..558a2dc
--- /dev/null
+++ b/partmap/bsdlabel.c
@@ -0,0 +1,97 @@
+/* bsdlabel.c - Read BSD style partition tables.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2004,2005,2006,2007,2008,2009  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/partition.h>
+#include <grub/bsdlabel.h>
+#include <grub/disk.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/dl.h>
+
+static struct grub_partition_map grub_bsdlabel_partition_map;
+\f
+
+static grub_err_t
+bsdlabel_partition_map_iterate (grub_disk_t disk,
+			  int (*hook) (grub_disk_t disk,
+				       const grub_partition_t partition))
+{
+  struct grub_pc_partition_disk_label label;
+  struct grub_partition p;
+  grub_disk_addr_t delta = 0;
+  unsigned pos;
+
+  /* BSDLabel offsets are absolute even when it's embed inside partition.  */
+  delta = grub_partition_get_start (disk->partition);
+
+  /* Read the BSD label.  */
+  if (grub_disk_read (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR,
+		      0, sizeof (label), &label))
+    return grub_errno;
+
+  /* Check if it is valid.  */
+  if (label.magic != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
+    return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
+
+  pos = sizeof (label) + GRUB_PC_PARTITION_BSD_LABEL_SECTOR
+    * GRUB_DISK_SECTOR_SIZE;
+
+  for (p.number = 0;
+       p.number < grub_cpu_to_le16 (label.num_partitions);
+       p.number++)
+    {
+      struct grub_pc_partition_bsd_entry be;
+
+      p.offset = pos / GRUB_DISK_SECTOR_SIZE;
+      p.index = pos % GRUB_DISK_SECTOR_SIZE;
+
+      if (grub_disk_read (disk, p.offset, p.index, sizeof (be),  &be))
+	return grub_errno;
+
+      p.start = grub_le_to_cpu32 (be.offset) - delta;
+      p.len = grub_le_to_cpu32 (be.size);
+      p.partmap = &grub_bsdlabel_partition_map;
+
+      if (be.fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
+	if (hook (disk, &p))
+	  return grub_errno;
+
+      pos += sizeof (struct grub_pc_partition_bsd_entry);
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+\f
+/* Partition map type.  */
+static struct grub_partition_map grub_bsdlabel_partition_map =
+  {
+    .name = "part_bsd",
+    .iterate = bsdlabel_partition_map_iterate,
+  };
+
+GRUB_MOD_INIT(bsd_partition_map)
+{
+  grub_partition_map_register (&grub_bsdlabel_partition_map);
+}
+
+GRUB_MOD_FINI(bsd_partition_map)
+{
+  grub_partition_map_unregister (&grub_bsdlabel_partition_map);
+}
diff --git a/partmap/gpt.c b/partmap/gpt.c
index 4a49574..c53c395 100644
--- a/partmap/gpt.c
+++ b/partmap/gpt.c
@@ -44,18 +44,13 @@ gpt_partition_map_iterate (grub_disk_t disk,
   struct grub_partition part;
   struct grub_gpt_header gpt;
   struct grub_gpt_partentry entry;
-  struct grub_disk raw;
   struct grub_msdos_partition_mbr mbr;
   grub_uint64_t entries;
   unsigned int i;
   int last_offset = 0;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   /* Read the protective MBR.  */
-  if (grub_disk_read (&raw, 0, 0, sizeof (mbr), &mbr))
+  if (grub_disk_read (disk, 0, 0, sizeof (mbr), &mbr))
     return grub_errno;
 
   /* Check if it is valid.  */
@@ -67,7 +62,7 @@ gpt_partition_map_iterate (grub_disk_t disk,
     return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
 
   /* Read the GPT header.  */
-  if (grub_disk_read (&raw, 1, 0, sizeof (gpt), &gpt))
+  if (grub_disk_read (disk, 1, 0, sizeof (gpt), &gpt))
     return grub_errno;
 
   if (grub_memcmp (gpt.magic, grub_gpt_magic, sizeof (grub_gpt_magic)))
@@ -76,11 +71,15 @@ gpt_partition_map_iterate (grub_disk_t disk,
   grub_dprintf ("gpt", "Read a valid GPT header\n");
 
   entries = grub_le_to_cpu64 (gpt.partitions);
+  part.data = grub_malloc (sizeof (entry));
   for (i = 0; i < grub_le_to_cpu32 (gpt.maxpart); i++)
     {
-      if (grub_disk_read (&raw, entries, last_offset,
+      if (grub_disk_read (disk, entries, last_offset,
 			  sizeof (entry), &entry))
-	return grub_errno;
+	{
+	  grub_free (part.data);
+	  return grub_errno;
+	}
 
       if (grub_memcmp (&grub_gpt_partition_type_empty, &entry.type,
 		       sizeof (grub_gpt_partition_type_empty)))
@@ -90,16 +89,17 @@ gpt_partition_map_iterate (grub_disk_t disk,
 	  part.len = (grub_le_to_cpu64 (entry.end)
 		      - grub_le_to_cpu64 (entry.start) + 1);
 	  part.offset = entries;
-	  part.index = i;
+	  part.number = i;
+	  part.index = last_offset;
 	  part.partmap = &grub_gpt_partition_map;
-	  part.data = &entry;
+	  grub_memcpy (part.data, &entry, sizeof (entry));
 
 	  grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", i,
 			(unsigned long long) part.start,
 			(unsigned long long) part.len);
 
 	  if (hook (disk, &part))
-	    return 1;
+	    return grub_errno;
 	}
 
       last_offset += grub_le_to_cpu32 (gpt.partentry_size);
@@ -109,67 +109,9 @@ gpt_partition_map_iterate (grub_disk_t disk,
 	  entries++;
 	}
     }
+  grub_free (part.data);
 
-  return 0;
-}
-
-
-static grub_partition_t
-gpt_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  gpt_partition_map_iterate (disk, find_func);
-  if (grub_errno)
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-gpt_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
+  return GRUB_ERR_NONE;
 }
 
 \f
@@ -178,8 +120,6 @@ static struct grub_partition_map grub_gpt_partition_map =
   {
     .name = "part_gpt",
     .iterate = gpt_partition_map_iterate,
-    .probe = gpt_partition_map_probe,
-    .get_name = gpt_partition_map_get_name
   };
 
 GRUB_MOD_INIT(gpt_partition_map)
diff --git a/partmap/msdos.c b/partmap/msdos.c
index d0fc18e..598d189 100644
--- a/partmap/msdos.c
+++ b/partmap/msdos.c
@@ -27,85 +27,19 @@
 static struct grub_partition_map grub_msdos_partition_map;
 \f
 
-/* Parse the partition representation in STR and return a partition.  */
-static grub_partition_t
-grub_partition_parse (const char *str)
-{
-  grub_partition_t p;
-  struct grub_msdos_partition *pcdata;
-
-  char *s = (char *) str;
-
-  p = (grub_partition_t) grub_malloc (sizeof (*p));
-  if (! p)
-    return 0;
-
-  pcdata = (struct grub_msdos_partition *) grub_malloc (sizeof (*pcdata));
-  if (! pcdata)
-    goto fail;
-
-  p->data = pcdata;
-  p->partmap = &grub_msdos_partition_map;
-
-  /* Initialize some of the fields with invalid values.  */
-  pcdata->bsd_part = pcdata->dos_type = pcdata->bsd_type = p->index = -1;
-
-  /* Get the DOS partition number. The number is counted from one for
-     the user interface, and from zero internally.  */
-  pcdata->dos_part = grub_strtoul (s, &s, 0) - 1;
-
-  if (grub_errno)
-    {
-      /* Not found. Maybe only a BSD label is specified.  */
-      pcdata->dos_part = -1;
-      grub_errno = GRUB_ERR_NONE;
-    }
-  else if (*s == ',')
-    s++;
-
-  if (*s)
-    {
-      if (*s >= 'a' && *s <= 'h')
-	{
-	  pcdata->bsd_part = *s - 'a';
-	  s++;
-	}
-
-      if (*s)
-	goto fail;
-    }
-
-  if (pcdata->dos_part == -1 && pcdata->bsd_part == -1)
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  grub_free (pcdata);
-  grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-  return 0;
-}
-
 static grub_err_t
 pc_partition_map_iterate (grub_disk_t disk,
 			  int (*hook) (grub_disk_t disk,
 				       const grub_partition_t partition))
 {
   struct grub_partition p;
-  struct grub_msdos_partition pcdata;
   struct grub_msdos_partition_mbr mbr;
-  struct grub_msdos_partition_disk_label label;
-  struct grub_disk raw;
-
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
+  grub_disk_addr_t ext_offset;
 
   p.offset = 0;
-  pcdata.ext_offset = 0;
-  pcdata.dos_part = -1;
-  p.data = &pcdata;
+  ext_offset = 0;
+  p.data = 0;
+  p.number = -1;
   p.partmap = &grub_msdos_partition_map;
 
   while (1)
@@ -114,7 +48,7 @@ pc_partition_map_iterate (grub_disk_t disk,
       struct grub_msdos_partition_entry *e;
 
       /* Read the MBR.  */
-      if (grub_disk_read (&raw, p.offset, 0, sizeof (mbr), &mbr))
+      if (grub_disk_read (disk, p.offset, 0, sizeof (mbr), &mbr))
 	goto finish;
 
       /* Check if it is valid.  */
@@ -132,13 +66,10 @@ pc_partition_map_iterate (grub_disk_t disk,
 
 	  p.start = p.offset + grub_le_to_cpu32 (e->start);
 	  p.len = grub_le_to_cpu32 (e->length);
-	  pcdata.bsd_part = -1;
-	  pcdata.dos_type = e->type;
-	  pcdata.bsd_type = -1;
 
 	  grub_dprintf ("partition",
 			"partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n",
-			p.index, e->flag, pcdata.dos_type,
+			p.index, e->flag, e->type,
 			(unsigned long long) p.start,
 			(unsigned long long) p.len);
 
@@ -150,59 +81,15 @@ pc_partition_map_iterate (grub_disk_t disk,
 	  if (! grub_msdos_partition_is_empty (e->type)
 	      && ! grub_msdos_partition_is_extended (e->type))
 	    {
-	      pcdata.dos_part++;
+	      p.number++;
 
 	      if (hook (disk, &p))
-		return 1;
-
-	      /* Check if this is a BSD partition.  */
-	      if (grub_msdos_partition_is_bsd (e->type))
-		{
-		  /* Check if the BSD label is within the DOS partition.  */
-		  if (p.len <= GRUB_PC_PARTITION_BSD_LABEL_SECTOR)
-		    {
-		      grub_dprintf ("partition", "no space for disk label\n");
-		      continue;
-		    }
-		  /* Read the BSD label.  */
-		  if (grub_disk_read (&raw,
-				      (p.start
-				       + GRUB_PC_PARTITION_BSD_LABEL_SECTOR),
-				      0,
-				      sizeof (label),
-				      &label))
-		    goto finish;
-
-		  /* Check if it is valid.  */
-		  if (label.magic
-		      != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
-		    {
-		      grub_dprintf ("partition",
-				    "invalid disk label magic 0x%x on partition %d\n",
-				    label.magic, p.index);
-		      continue;
-		    }
-		  for (pcdata.bsd_part = 0;
-		       pcdata.bsd_part < grub_cpu_to_le16 (label.num_partitions);
-		       pcdata.bsd_part++)
-		    {
-		      struct grub_msdos_partition_bsd_entry *be
-			= label.entries + pcdata.bsd_part;
-
-		      p.start = grub_le_to_cpu32 (be->offset);
-		      p.len = grub_le_to_cpu32 (be->size);
-		      pcdata.bsd_type = be->fs_type;
-
-		      if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
-			if (hook (disk, &p))
-			  return 1;
-		    }
-		}
+		return grub_errno;
 	    }
-	  else if (pcdata.dos_part < 4)
+	  else if (p.number < 4)
 	    /* If this partition is a logical one, shouldn't increase the
 	       partition number.  */
-	    pcdata.dos_part++;
+	    p.number++;
 	}
 
       /* Find an extended partition.  */
@@ -212,9 +99,9 @@ pc_partition_map_iterate (grub_disk_t disk,
 
 	  if (grub_msdos_partition_is_extended (e->type))
 	    {
-	      p.offset = pcdata.ext_offset + grub_le_to_cpu32 (e->start);
-	      if (! pcdata.ext_offset)
-		pcdata.ext_offset = p.offset;
+	      p.offset = ext_offset + grub_le_to_cpu32 (e->start);
+	      if (! ext_offset)
+		ext_offset = p.offset;
 
 	      break;
 	    }
@@ -229,84 +116,12 @@ pc_partition_map_iterate (grub_disk_t disk,
   return grub_errno;
 }
 
-
-static grub_partition_t
-pc_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p;
-  struct grub_msdos_partition *pcdata;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      struct grub_msdos_partition *partdata = partition->data;
-
-      if ((pcdata->dos_part == partdata->dos_part || pcdata->dos_part == -1)
-	  && pcdata->bsd_part == partdata->bsd_part)
-	{
-	  grub_memcpy (p, partition, sizeof (*p));
-	  p->data = pcdata;
-	  grub_memcpy (pcdata, partdata, sizeof (*pcdata));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  p = grub_partition_parse (str);
-  if (! p)
-    return 0;
-
-  pcdata = p->data;
-  pc_partition_map_iterate (disk, find_func);
-  if (grub_errno)
-    goto fail;
-
-  if (p->index < 0)
-    {
-      grub_error (GRUB_ERR_BAD_DEVICE, "no such partition");
-      goto fail;
-    }
-
-  return p;
-
- fail:
-  grub_free (p);
-  grub_free (pcdata);
-  return 0;
-}
-
-
-static char *
-pc_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-  struct grub_msdos_partition *pcdata = p->data;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  if (pcdata->bsd_part < 0)
-    grub_sprintf (name, "%d", pcdata->dos_part + 1);
-  else if (pcdata->dos_part < 0)
-    grub_sprintf (name, "%c", pcdata->bsd_part + 'a');
-  else
-    grub_sprintf (name, "%d,%c", pcdata->dos_part + 1, pcdata->bsd_part + 'a');
-
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_msdos_partition_map =
   {
     .name = "part_msdos",
     .iterate = pc_partition_map_iterate,
-    .probe = pc_partition_map_probe,
-    .get_name = pc_partition_map_get_name
   };
 
 GRUB_MOD_INIT(pc_partition_map)
diff --git a/partmap/sun.c b/partmap/sun.c
index e816ec1..ff01d10 100644
--- a/partmap/sun.c
+++ b/partmap/sun.c
@@ -88,19 +88,15 @@ sun_partition_map_iterate (grub_disk_t disk,
 					const grub_partition_t partition))
 {
   grub_partition_t p;
-  struct grub_disk raw;
   struct grub_sun_block block;
   int partnum;
 
-  raw = *disk;
-  raw.partition = 0;
-
   p = (grub_partition_t) grub_zalloc (sizeof (struct grub_partition));
   if (! p)
     return grub_errno;
 
   p->partmap = &grub_sun_partition_map;
-  if (grub_disk_read (&raw, 0, 0, sizeof (struct grub_sun_block),
+  if (grub_disk_read (disk, 0, 0, sizeof (struct grub_sun_block),
 		      &block) == GRUB_ERR_NONE)
     {
       if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.magic))
@@ -124,7 +120,7 @@ sun_partition_map_iterate (grub_disk_t disk,
 		      * grub_be_to_cpu16 (block.ntrks)
 		      * grub_be_to_cpu16 (block.nsect));
 	  p->len = grub_be_to_cpu32 (desc->num_sectors);
-	  p->index = partnum;
+	  p->number = p->index = partnum;
 	  if (p->len)
 	    {
 	      if (hook (disk, p))
@@ -138,68 +134,11 @@ sun_partition_map_iterate (grub_disk_t disk,
   return grub_errno;
 }
 
-static grub_partition_t
-sun_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-        {
-          p = (grub_partition_t) grub_malloc (sizeof (*p));
-          if (p)
-            grub_memcpy (p, partition, sizeof (*p));
-
-          return 1;
-        }
-
-      return 0;
-    }
-
-  grub_errno = GRUB_ERR_NONE;
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno == GRUB_ERR_NONE)
-    {
-      if (sun_partition_map_iterate (disk, find_func))
-        {
-          grub_free (p);
-          p = 0;
-        }
-    }
-  else
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      p = 0;
-    }
-
-  return p;
-}
-
-static char *
-sun_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (name)
-    grub_sprintf (name, "%d", p->index + 1);
-
-  return name;
-}
-
 /* Partition map type.  */
 static struct grub_partition_map grub_sun_partition_map =
   {
     .name = "part_sun",
     .iterate = sun_partition_map_iterate,
-    .probe = sun_partition_map_probe,
-    .get_name = sun_partition_map_get_name
   };
 
 GRUB_MOD_INIT(sun_partition_map)
diff --git a/parttool/msdospart.c b/parttool/msdospart.c
index dbb25bc..b1fe689 100644
--- a/parttool/msdospart.c
+++ b/parttool/msdospart.c
@@ -49,7 +49,7 @@ static grub_err_t grub_pcpart_boot (const grub_device_t dev,
 
   index = dev->disk->partition->index;
   part = dev->disk->partition;
-  dev->disk->partition = 0;
+  dev->disk->partition = part->parent;
 
   /* Read the MBR.  */
   if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr))
@@ -96,7 +96,7 @@ static grub_err_t grub_pcpart_type (const grub_device_t dev,
 
   index = dev->disk->partition->index;
   part = dev->disk->partition;
-  dev->disk->partition = 0;
+  dev->disk->partition = part->parent;
 
   /* Read the parttable.  */
   if (grub_disk_read (dev->disk, part->offset, 0,
diff --git a/util/grub-probe.c b/util/grub-probe.c
index 1710ec5..d6406ce 100644
--- a/util/grub-probe.c
+++ b/util/grub-probe.c
@@ -79,13 +79,16 @@ grub_refresh (void)
 static void
 probe_partmap (grub_disk_t disk)
 {
+  grub_partition_t part;
+
   if (disk->partition == NULL)
     {
       grub_util_info ("No partition map found for %s", disk->name);
       return;
     }
 
-  printf ("%s\n", disk->partition->partmap->name);
+  for (part = disk->partition; part; part = part->parent)
+    printf ("%s\n", part->partmap->name);
 }
 
 static int
diff --git a/util/hostdisk.c b/util/hostdisk.c
index a06ecca..6e876df 100644
--- a/util/hostdisk.c
+++ b/util/hostdisk.c
@@ -333,10 +333,13 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
   {
     int is_partition = 0;
     char dev[PATH_MAX];
+    grub_disk_addr_t part_start = 0;
+
+    part_start = grub_partition_get_start (disk->partition);
 
     strcpy (dev, map[disk->id].device);
     if (disk->partition && strncmp (map[disk->id].device, "/dev/", 5) == 0)
-      is_partition = linux_find_partition (dev, disk->partition->start);
+      is_partition = linux_find_partition (dev, part_start);
 
     /* Open the partition.  */
     grub_dprintf ("hostdisk", "opening the device `%s' in open_device()", dev);
@@ -351,7 +354,7 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
     ioctl (fd, BLKFLSBUF, 0);
 
     if (is_partition)
-      sector -= disk->partition->start;
+      sector -= part_start;
   }
 #else /* ! __linux__ */
 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -947,39 +950,25 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
     int find_partition (grub_disk_t disk __attribute__ ((unused)),
 			const grub_partition_t partition)
       {
- 	struct grub_msdos_partition *pcdata = NULL;
-
-	if (strcmp (partition->partmap->name, "part_msdos") == 0)
-	  pcdata = partition->data;
+	grub_disk_addr_t part_start = 0;
+	grub_util_info ("Partition %d starts from %lu",
+			partition->number, partition->start);
 
-	if (pcdata)
-	  {
-	    if (pcdata->bsd_part < 0)
-	      grub_util_info ("DOS partition %d starts from %lu",
-			      pcdata->dos_part, partition->start);
-	    else
-	      grub_util_info ("BSD partition %d,%c starts from %lu",
-			      pcdata->dos_part, pcdata->bsd_part + 'a',
-			      partition->start);
-	  }
-	else
-	  {
-	      grub_util_info ("Partition %d starts from %lu",
-			      partition->index, partition->start);
-	  }
+	part_start = grub_partition_get_start (partition);
 
-	if (hdg.start == partition->start)
+	if (hdg.start == part_start)
 	  {
-	    if (pcdata)
+	    if (partition->parent)
 	      {
-		dos_part = pcdata->dos_part;
-		bsd_part = pcdata->bsd_part;
+		dos_part = partition->parent->number;
+		bsd_part = partition->number;
 	      }
 	    else
 	      {
-		dos_part = partition->index;
+		dos_part = partition->number;
 		bsd_part = -1;
 	      }
+
 	    return 1;
 	  }
 
diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c
index 7f38c42..bf435ac 100644
--- a/util/i386/pc/grub-setup.c
+++ b/util/i386/pc/grub-setup.c
@@ -121,15 +121,10 @@ setup (const char *dir,
   int NESTED_FUNC_ATTR find_usable_region_msdos (grub_disk_t disk __attribute__ ((unused)),
 						 const grub_partition_t p)
     {
-      struct grub_msdos_partition *pcdata = p->data;
-
       /* There's always an embed region, and it starts right after the MBR.  */
       embed_region.start = 1;
 
-      /* For its end offset, include as many dummy partitions as we can.  */
-      if (! grub_msdos_partition_is_empty (pcdata->dos_type)
-	  && ! grub_msdos_partition_is_bsd (pcdata->dos_type)
-	  && embed_region.end > p->start)
+      if (embed_region.end > p->start)
 	embed_region.end = p->start;
 
       return 0;
@@ -278,22 +273,19 @@ setup (const char *dir,
       /* Embed information about the installed location.  */
       if (root_dev->disk->partition)
 	{
-	  if (strcmp (root_dev->disk->partition->partmap->name,
-		      "part_msdos") == 0)
+	  if (root_dev->disk->partition->parent)
 	    {
-	      struct grub_msdos_partition *pcdata =
-		root_dev->disk->partition->data;
-	      dos_part = pcdata->dos_part;
-	      bsd_part = pcdata->bsd_part;
+	      if (root_dev->disk->partition->parent->parent)
+		grub_util_error ("Installing on doubly nested partitiond is "
+				 "not supported");
+	      dos_part = root_dev->disk->partition->parent->number;
+	      bsd_part = root_dev->disk->partition->number;
 	    }
-	  else if (strcmp (root_dev->disk->partition->partmap->name,
-			   "part_gpt") == 0)
+	  else
 	    {
-	      dos_part = root_dev->disk->partition->index;
+	      dos_part = root_dev->disk->partition->number;
 	      bsd_part = -1;
 	    }
-	  else
-	    grub_util_error ("No PC style partitions found");
 	}
       else
 	dos_part = bsd_part = -1;
@@ -326,6 +318,8 @@ setup (const char *dir,
   int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk __attribute__ ((unused)),
 					 const grub_partition_t p)
     {
+      if (p->parent)
+	return 0;
       dest_partmap = p->partmap->name;
       return 1;
     }

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-24 13:39                     ` Vladimir 'phcoder' Serbinenko
@ 2009-08-25 20:14                       ` Vladimir 'phcoder' Serbinenko
  2009-08-25 23:07                         ` Robert Millan
  2009-08-25 20:35                       ` Seth Goldberg
  1 sibling, 1 reply; 36+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-08-25 20:14 UTC (permalink / raw)
  To: The development of GRUB 2

On Robert's request I write about the usage cases I'm aware. It's by
no means complete

1) bsdlabel on PC-style. By most *BSD flavours
2) sunpc on PC-style. By Solaris
3) Some kind on PC-style on PC-style by Minix. (not sure about this
one -it was a long time ago)
I vaguely heard of (I may be completely wrong):
4) amiga on PC-style by AROS
5) sun on apple. Polaris (?)

On Mon, Aug 24, 2009 at 3:39 PM, Vladimir 'phcoder'
Serbinenko<phcoder@gmail.com> wrote:
> Rediff
>
> On Mon, Aug 24, 2009 at 12:57 AM, Vladimir 'phcoder'
> Serbinenko<phcoder@gmail.com> wrote:
>> Rediff
>> On Mon, Aug 17, 2009 at 4:34 PM, Vladimir 'phcoder'
>> Serbinenko<phcoder@gmail.com> wrote:
>>> On Mon, Aug 17, 2009 at 4:06 PM, Robert Millan<rmh@aybabtu.com> wrote:
>>>> On Mon, Aug 17, 2009 at 03:00:52PM +0200, Vladimir 'phcoder' Serbinenko wrote:
>>>>> Rediff and few fixes
>>>>
>>>> Please note that after what we discussed on IRC, we need to find a solution
>>>> that wouldn't make boot time increase linearly with the number of filesystems
>>>> or partmaps GRUB supports.
>>>>
>>> It probe time scales linearly no matter what we do. Fortunately with
>>> disk cache few first sectors are read and checked for different
>>> signatures which is fast. As for module autoload with search patch it
>>> doesn't happen except in the failure to access requested device.
>>>> I really think supporting every sort of combination is too extreme.  For
>>>> example who would want an msdos/msdos chain?  OpenSolaris creates one, but
>>>> it's a false positive.
>>>>
>>> minix does it and it's not a false positive.
>>>> The overall idea *is* nice.  Some combinations (e.g. msdos/bsd) are cleaner
>>>> this way, but supporting everything doesn't scale well.
>>> AFAIK no partmap goes beyond first 16K for signature checking. Time
>>> for signature checking can be neglected and 16K would be read for
>>> filesystem probe too. Additionally e.g. (hd0,1) is probed for
>>> subpartitions only if (hd0,1,X) is requested or we're scanning through
>>> partitions. In last case we're likely to fsprobe partition anyway so
>>> it doesn't create any overhead
>>>>
>>>> Perhaps we can explicitly list which combinations make sense?  So when an
>>>> msdos label is found, its partitions are probed for bsd labels too, but not
>>>> for msdos labels again, etc.
>>>>
>>>> --
>>>> Robert Millan
>>>>
>>>>  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
>>>>  how) you may access your data; but nobody's threatening your freedom: we
>>>>  still allow you to remove your data and not access it at all."
>>>>
>>>>
>>>> _______________________________________________
>>>> Grub-devel mailing list
>>>> Grub-devel@gnu.org
>>>> http://lists.gnu.org/mailman/listinfo/grub-devel
>>>>
>>>
>>>
>>>
>>> --
>>> Regards
>>> Vladimir 'phcoder' Serbinenko
>>>
>>> Personal git repository: http://repo.or.cz/w/grub2/phcoder.git
>>>
>>
>>
>>
>> --
>> Regards
>> Vladimir 'phcoder' Serbinenko
>>
>> Personal git repository: http://repo.or.cz/w/grub2/phcoder.git
>>
>
>
>
> --
> Regards
> Vladimir 'phcoder' Serbinenko
>
> Personal git repository: http://repo.or.cz/w/grub2/phcoder.git
>



-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-24 13:39                     ` Vladimir 'phcoder' Serbinenko
  2009-08-25 20:14                       ` Vladimir 'phcoder' Serbinenko
@ 2009-08-25 20:35                       ` Seth Goldberg
  2009-08-25 21:12                         ` Vladimir 'phcoder' Serbinenko
  1 sibling, 1 reply; 36+ messages in thread
From: Seth Goldberg @ 2009-08-25 20:35 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: TEXT/PLAIN, Size: 2956 bytes --]


  Typo:

+               grub_util_error ("Installing on doubly nested partitiond is "

  --S


Quoting Vladimir 'phcoder' Serbinenko, who wrote the following on Mon, 24...:

> Rediff
>
> On Mon, Aug 24, 2009 at 12:57 AM, Vladimir 'phcoder'
> Serbinenko<phcoder@gmail.com> wrote:
>> Rediff
>> On Mon, Aug 17, 2009 at 4:34 PM, Vladimir 'phcoder'
>> Serbinenko<phcoder@gmail.com> wrote:
>>> On Mon, Aug 17, 2009 at 4:06 PM, Robert Millan<rmh@aybabtu.com> wrote:
>>>> On Mon, Aug 17, 2009 at 03:00:52PM +0200, Vladimir 'phcoder' Serbinenko wrote:
>>>>> Rediff and few fixes
>>>>
>>>> Please note that after what we discussed on IRC, we need to find a solution
>>>> that wouldn't make boot time increase linearly with the number of filesystems
>>>> or partmaps GRUB supports.
>>>>
>>> It probe time scales linearly no matter what we do. Fortunately with
>>> disk cache few first sectors are read and checked for different
>>> signatures which is fast. As for module autoload with search patch it
>>> doesn't happen except in the failure to access requested device.
>>>> I really think supporting every sort of combination is too extreme.  For
>>>> example who would want an msdos/msdos chain?  OpenSolaris creates one, but
>>>> it's a false positive.
>>>>
>>> minix does it and it's not a false positive.
>>>> The overall idea *is* nice.  Some combinations (e.g. msdos/bsd) are cleaner
>>>> this way, but supporting everything doesn't scale well.
>>> AFAIK no partmap goes beyond first 16K for signature checking. Time
>>> for signature checking can be neglected and 16K would be read for
>>> filesystem probe too. Additionally e.g. (hd0,1) is probed for
>>> subpartitions only if (hd0,1,X) is requested or we're scanning through
>>> partitions. In last case we're likely to fsprobe partition anyway so
>>> it doesn't create any overhead
>>>>
>>>> Perhaps we can explicitly list which combinations make sense?  So when an
>>>> msdos label is found, its partitions are probed for bsd labels too, but not
>>>> for msdos labels again, etc.
>>>>
>>>> --
>>>> Robert Millan
>>>>
>>>>  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
>>>>  how) you may access your data; but nobody's threatening your freedom: we
>>>>  still allow you to remove your data and not access it at all."
>>>>
>>>>
>>>> _______________________________________________
>>>> Grub-devel mailing list
>>>> Grub-devel@gnu.org
>>>> http://lists.gnu.org/mailman/listinfo/grub-devel
>>>>
>>>
>>>
>>>
>>> --
>>> Regards
>>> Vladimir 'phcoder' Serbinenko
>>>
>>> Personal git repository: http://repo.or.cz/w/grub2/phcoder.git
>>>
>>
>>
>>
>> --
>> Regards
>> Vladimir 'phcoder' Serbinenko
>>
>> Personal git repository: http://repo.or.cz/w/grub2/phcoder.git
>>
>
>
>
> -- 
> Regards
> Vladimir 'phcoder' Serbinenko
>
> Personal git repository: http://repo.or.cz/w/grub2/phcoder.git
>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-25 20:35                       ` Seth Goldberg
@ 2009-08-25 21:12                         ` Vladimir 'phcoder' Serbinenko
  2010-01-22 16:53                           ` Robert Millan
  0 siblings, 1 reply; 36+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-08-25 21:12 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 3595 bytes --]

On Tue, Aug 25, 2009 at 10:35 PM, Seth Goldberg<Seth.Goldberg@sun.com> wrote:
>
>  Typo:
>
> +               grub_util_error ("Installing on doubly nested partitiond is
> "
Thanks. This and other issues you pointed out on IRC fixed. New patch.
>
>  --S
>
>
> Quoting Vladimir 'phcoder' Serbinenko, who wrote the following on Mon,
> 24...:
>
>> Rediff
>>
>> On Mon, Aug 24, 2009 at 12:57 AM, Vladimir 'phcoder'
>> Serbinenko<phcoder@gmail.com> wrote:
>>>
>>> Rediff
>>> On Mon, Aug 17, 2009 at 4:34 PM, Vladimir 'phcoder'
>>> Serbinenko<phcoder@gmail.com> wrote:
>>>>
>>>> On Mon, Aug 17, 2009 at 4:06 PM, Robert Millan<rmh@aybabtu.com> wrote:
>>>>>
>>>>> On Mon, Aug 17, 2009 at 03:00:52PM +0200, Vladimir 'phcoder' Serbinenko
>>>>> wrote:
>>>>>>
>>>>>> Rediff and few fixes
>>>>>
>>>>> Please note that after what we discussed on IRC, we need to find a
>>>>> solution
>>>>> that wouldn't make boot time increase linearly with the number of
>>>>> filesystems
>>>>> or partmaps GRUB supports.
>>>>>
>>>> It probe time scales linearly no matter what we do. Fortunately with
>>>> disk cache few first sectors are read and checked for different
>>>> signatures which is fast. As for module autoload with search patch it
>>>> doesn't happen except in the failure to access requested device.
>>>>>
>>>>> I really think supporting every sort of combination is too extreme.
>>>>>  For
>>>>> example who would want an msdos/msdos chain?  OpenSolaris creates one,
>>>>> but
>>>>> it's a false positive.
>>>>>
>>>> minix does it and it's not a false positive.
>>>>>
>>>>> The overall idea *is* nice.  Some combinations (e.g. msdos/bsd) are
>>>>> cleaner
>>>>> this way, but supporting everything doesn't scale well.
>>>>
>>>> AFAIK no partmap goes beyond first 16K for signature checking. Time
>>>> for signature checking can be neglected and 16K would be read for
>>>> filesystem probe too. Additionally e.g. (hd0,1) is probed for
>>>> subpartitions only if (hd0,1,X) is requested or we're scanning through
>>>> partitions. In last case we're likely to fsprobe partition anyway so
>>>> it doesn't create any overhead
>>>>>
>>>>> Perhaps we can explicitly list which combinations make sense?  So when
>>>>> an
>>>>> msdos label is found, its partitions are probed for bsd labels too, but
>>>>> not
>>>>> for msdos labels again, etc.
>>>>>
>>>>> --
>>>>> Robert Millan
>>>>>
>>>>>  The DRM opt-in fallacy: "Your data belongs to us. We will decide when
>>>>> (and
>>>>>  how) you may access your data; but nobody's threatening your freedom:
>>>>> we
>>>>>  still allow you to remove your data and not access it at all."
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> Grub-devel mailing list
>>>>> Grub-devel@gnu.org
>>>>> http://lists.gnu.org/mailman/listinfo/grub-devel
>>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> Regards
>>>> Vladimir 'phcoder' Serbinenko
>>>>
>>>> Personal git repository: http://repo.or.cz/w/grub2/phcoder.git
>>>>
>>>
>>>
>>>
>>> --
>>> Regards
>>> Vladimir 'phcoder' Serbinenko
>>>
>>> Personal git repository: http://repo.or.cz/w/grub2/phcoder.git
>>>
>>
>>
>>
>> --
>> Regards
>> Vladimir 'phcoder' Serbinenko
>>
>> Personal git repository: http://repo.or.cz/w/grub2/phcoder.git
>>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>
>



-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git

[-- Attachment #2: nestpart.diff --]
[-- Type: text/plain, Size: 61741 bytes --]

diff --git a/Changelog.phcoder b/Changelog.phcoder
new file mode 100644
index 0000000..a272618
--- /dev/null
+++ b/Changelog.phcoder
@@ -0,0 +1,73 @@
+2009-06-08  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	Nested partitions
+
+	* commands/blocklist.c (grub_cmd_blocklist): Don't check whether
+	'partition' is NULL, grub_partition_get_start already does that.
+	* commands/loadenv.c (check_blocklists): Likewise.
+	(write_blocklists): Likewise.
+	* conf/common.rmk (grub_probe_SOURCES): Add partmap/bsdlabel.c.
+	(grub_fstest_SOURCES): Likewise.
+	(pkglib_MODULES): Add bsdlabel.mod.
+	(bsdlabel_mod_SOURCES): New variable.
+	(bsdlabel_mod_CFLAGS): Likewise.
+	(bsdlabel_mod_LDFLAGS): Likewise.
+	* conf/i386-coreboot.rmk (grub_emu_SOURCES): Add partmap/bsdlabel.c.
+	* conf/i386-pc.rmk (grub_setup_SOURCES): Likewise.
+	(grub_emu_SOURCES): Likewise.
+	* conf/powerpc-ieee1275.rmk (grub_emu_SOURCES): Likewise.
+	* conf/sparc64-ieee1275.rmk (grub_emu_SOURCES): Likewise.
+	* include/grub/bsdlabel.h: New file.
+	* include/grub/partition.h (grub_partition_map): Remove 'probe' and
+	'get_name'.
+	(grub_partition): Add 'parent' and 'number'.
+	(grub_partition_get_start): Handle nested partitions.
+	* include/grub/pc_partition.h: Remove bsd-related entries.
+	(grub_pc_partition): Remove.
+	* kern/disk.c (grub_disk_close): Free partition data.
+	(grub_disk_adjust_range): Handle nested partitions.
+	* kern/partition.c (grub_partition_map_probe): New function.
+	(grub_partition_probe): Parse name to number, handle subpartitions.
+	(get_partmap): New function.
+	(grub_partition_iterate): Handle subpartitions.
+	(grub_partition_get_name): Likewise.
+	* loader/i386/pc/bsd.c (grub_bsd_get_device): Likewise.
+	* loader/i386/multiboot.c (grub_multiboot_get_bootdev): Likewise.
+	* loader/i386/pc/chainloader.c (grub_chainloader_cmd): Likewise.
+	* partmap/acorn.c (acorn_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	(acorn_partition_map_probe): Remove.
+	(acorn_partition_map_get_name): Likewise.
+	* partmap/amiga.c (amiga_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Set 'index' to 0 since there can be only one partition entry per sector.
+	(amiga_partition_map_probe): Remove.
+	(amiga_partition_map_get_name): Likewise.
+	* partmap/apple.c (apple_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Set 'offset' and 'index' to real positions of partitions.
+	(apple_partition_map_probe): Remove.
+	(apple_partition_map_get_name): Likewise.
+	* partmap/bsdlabel.c: New file.
+	* partmap/gpt.c (gpt_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Allocate 'data' so it can be correctly freed.
+	Set 'index' to offset inside sector.
+	(gpt_partition_map_probe): Remove.
+	(gpt_partition_map_get_name): Likewise.
+	* partmap/pc.c (grub_partition_parse): Remove.
+	(pc_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	Make 'ext_offset' a local variable.
+	(pc_partition_map_probe): Remove.
+	(pc_partition_map_get_name): Remove.
+	* partmap/sun.c (sun_partition_map_iterate): Don't force raw access.
+	Set 'number'.
+	(sun_partition_map_probe): Remove.
+	(sun_partition_map_get_name): Likewise.
+	* parttool/pcpart.c (grub_pcpart_boot): Handle nested partitions.
+	(grub_pcpart_type): Likewise.
+	* util/hostdisk.c (open_device): Handle new numbering scheme.
+	(grub_util_biosdisk_get_grub_dev): Handle nested partitions.
+	* util/i386/pc/grub-setup.c (setup): Handle new numbering scheme.
+	* util/grub-probe.c (probe_partmap): Handle nested paritions.
diff --git a/commands/blocklist.c b/commands/blocklist.c
index b457b7c..6cc7d69 100644
--- a/commands/blocklist.c
+++ b/commands/blocklist.c
@@ -89,8 +89,7 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)),
     return grub_error (GRUB_ERR_BAD_DEVICE,
 		       "this command is available only for disk devices.");
 
-  if (file->device->disk->partition)
-    part_start = grub_partition_get_start (file->device->disk->partition);
+  part_start = grub_partition_get_start (file->device->disk->partition);
 
   file->read_hook = read_blocklist;
 
diff --git a/commands/loadenv.c b/commands/loadenv.c
index 22665f9..51cffd3 100644
--- a/commands/loadenv.c
+++ b/commands/loadenv.c
@@ -236,10 +236,8 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
   /* One more sanity check. Re-read all sectors by blocklists, and compare
      those with the data read via a file.  */
   disk = file->device->disk;
-  if (disk->partition)
-    part_start = grub_partition_get_start (disk->partition);
-  else
-    part_start = 0;
+
+  part_start = grub_partition_get_start (disk->partition);
 
   buf = grub_envblk_buffer (envblk);
   for (p = blocklists, index = 0; p; p = p->next, index += p->length)
@@ -272,10 +270,7 @@ write_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
 
   buf = grub_envblk_buffer (envblk);
   disk = file->device->disk;
-  if (disk->partition)
-    part_start = grub_partition_get_start (disk->partition);
-  else
-    part_start = 0;
+  part_start = grub_partition_get_start (disk->partition);
 
   index = 0;
   for (p = blocklists; p; p = p->next, index += p->length)
diff --git a/conf/common.rmk b/conf/common.rmk
index 6d76746..2aee811 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -19,7 +19,8 @@ grub_probe_SOURCES = util/grub-probe.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c		\
 	\
-	partmap/msdos.c partmap/apple.c partmap/sun.c partmap/gpt.c\
+	partmap/msdos.c partmap/bsdlabel.c partmap/apple.c \
+	partmap/sun.c partmap/gpt.c\
 	kern/fs.c kern/env.c fs/fshelp.c			\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c grub_probe_init.c
 
@@ -40,8 +41,8 @@ grub_fstest_SOURCES = util/grub-fstest.c util/hostfs.c util/misc.c 	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c			\
 	fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c			\
 	\
-	kern/partition.c partmap/msdos.c partmap/apple.c partmap/sun.c	\
-	partmap/gpt.c							\
+	kern/partition.c partmap/msdos.c partmap/bsdlabel.c		\
+	partmap/apple.c partmap/sun.c partmap/gpt.c			\
 	kern/fs.c kern/env.c fs/fshelp.c disk/raid.c			\
 	disk/raid5_recover.c disk/raid6_recover.c 			\
 	disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c 		\
@@ -316,6 +317,11 @@ part_gpt_mod_SOURCES = partmap/gpt.c
 part_gpt_mod_CFLAGS = $(COMMON_CFLAGS)
 part_gpt_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+pkglib_MODULES += part_bsd.mod
+part_bsd_mod_SOURCES = partmap/bsdlabel.c
+part_bsd_mod_CFLAGS = $(COMMON_CFLAGS)
+part_bsd_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # Special disk structures and generic drivers
 
 pkglib_MODULES += raid.mod raid5rec.mod raid6rec.mod mdraid.mod dm_nv.mod \
diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk
index 7e9f853..a626a9a 100644
--- a/conf/i386-coreboot.rmk
+++ b/conf/i386-coreboot.rmk
@@ -135,8 +135,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c       \
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c          \
-	partmap/amiga.c	partmap/apple.c partmap/msdos.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/msdos.c			\
+	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c partmap/gpt.c	\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk
index 67234eb..f21a612 100644
--- a/conf/i386-ieee1275.rmk
+++ b/conf/i386-ieee1275.rmk
@@ -89,8 +89,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c		\
-	partmap/amiga.c	partmap/apple.c partmap/msdos.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/msdos.c			\
+	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c partmap/gpt.c	\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index 6b17796..55bd22f 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -104,7 +104,7 @@ grub_setup_SOURCES = util/i386/pc/grub-setup.c util/hostdisk.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c			\
 	\
-	partmap/msdos.c partmap/gpt.c				\
+	partmap/msdos.c partmap/bsdlabel.c partmap/gpt.c		\
 	\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
 	util/raid.c util/lvm.c					\
@@ -141,8 +141,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c	\
 	normal/menu_text.c						\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c grub_script.tab.c		\
-	partmap/amiga.c	partmap/apple.c partmap/msdos.c partmap/sun.c	\
-	partmap/acorn.c partmap/gpt.c					\
+	partmap/amiga.c	partmap/apple.c partmap/bsdlabel.c 		\
+	partmap/msdos.c partmap/sun.c partmap/acorn.c partmap/gpt.c	\
 	\
 	fs/affs.c fs/cpio.c  fs/fat.c fs/ext2.c fs/hfs.c		\
 	fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c		\
diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk
index c9b7e75..db423e1 100644
--- a/conf/powerpc-ieee1275.rmk
+++ b/conf/powerpc-ieee1275.rmk
@@ -70,8 +70,8 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c 	\
 	normal/color.c							\
 	script/sh/main.c script/sh/execute.c script/sh/function.c	\
 	script/sh/lexer.c script/sh/script.c				\
-	partmap/amiga.c	partmap/apple.c partmap/msdos.c partmap/sun.c	\
-	partmap/acorn.c							\
+	partmap/amiga.c	partmap/apple.c partmap/msdos.c 		\
+	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c		\
 	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
 	util/hostdisk.c util/getroot.c					\
 	\
diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk
index 6216213..c2cb7b0 100644
--- a/conf/sparc64-ieee1275.rmk
+++ b/conf/sparc64-ieee1275.rmk
@@ -80,8 +80,8 @@ grub_setup_SOURCES = util/sparc64/ieee1275/grub-setup.c util/hostdisk.c	\
 	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c		\
 	fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/befs.c fs/tar.c			\
 	\
-	partmap/amiga.c	partmap/apple.c partmap/msdos.c		\
-	partmap/sun.c partmap/acorn.c				\
+	partmap/amiga.c	partmap/apple.c partmap/msdos.c 	\
+	partmap/bsdlabel.c partmap/sun.c partmap/acorn.c	\
 	\
 	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
 	util/raid.c util/lvm.c					\
diff --git a/include/grub/bsdlabel.h b/include/grub/bsdlabel.h
new file mode 100644
index 0000000..d88b253
--- /dev/null
+++ b/include/grub/bsdlabel.h
@@ -0,0 +1,89 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2004,2007  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_BSDLABEL_PARTITION_HEADER
+#define GRUB_BSDLABEL_PARTITION_HEADER	1
+
+/* Constants for BSD disk label.  */
+#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR	1
+#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC	0x82564557
+
+/* BSD partition types.  */
+#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED	0
+#define GRUB_PC_PARTITION_BSD_TYPE_SWAP		1
+#define GRUB_PC_PARTITION_BSD_TYPE_V6		2
+#define GRUB_PC_PARTITION_BSD_TYPE_V7		3
+#define GRUB_PC_PARTITION_BSD_TYPE_SYSV		4
+#define GRUB_PC_PARTITION_BSD_TYPE_V71K		5
+#define GRUB_PC_PARTITION_BSD_TYPE_V8		6
+#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS	7
+#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS	8
+#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS	9
+#define GRUB_PC_PARTITION_BSD_TYPE_OTHER	10
+#define GRUB_PC_PARTITION_BSD_TYPE_HPFS		11
+#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660	12
+#define GRUB_PC_PARTITION_BSD_TYPE_BOOT		13
+
+/* FreeBSD-specific types.  */
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM	14
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID	15
+#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2	21
+
+/* NetBSD-specific types.  */
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_ADOS	14
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_HFS	15
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE	16
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS	17
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_NTFS	18
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_RAID	19
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_CCD	20
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_JFS2	21
+#define	GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS	22
+
+/* OpenBSD-specific types.  */
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS	14
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_HFS	15
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE	16
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS	17
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS	18
+#define	GRUB_PC_PARTITION_OPENBSD_TYPE_RAID	19
+
+/* The BSD partition entry.  */
+struct grub_partition_bsd_entry
+{
+  grub_uint32_t size;
+  grub_uint32_t offset;
+  grub_uint32_t fragment_size;
+  grub_uint8_t fs_type;
+  grub_uint8_t fs_fragments;
+  grub_uint16_t fs_cylinders;
+} __attribute__ ((packed));
+
+/* The BSD disk label. Only define members useful for GRUB.  */
+struct grub_partition_bsd_disk_label
+{
+  grub_uint32_t magic;
+  grub_uint8_t padding[128];
+  grub_uint32_t magic2;
+  grub_uint16_t checksum;
+  grub_uint16_t num_partitions;
+  grub_uint32_t boot_size;
+  grub_uint32_t superblock_size;
+} __attribute__ ((packed));
+
+#endif /* ! GRUB_PC_PARTITION_HEADER */
diff --git a/include/grub/msdos_partition.h b/include/grub/msdos_partition.h
index 273d8c9..650d784 100644
--- a/include/grub/msdos_partition.h
+++ b/include/grub/msdos_partition.h
@@ -53,75 +53,6 @@
 #define GRUB_PC_PARTITION_TYPE_GPT_DISK		0xee
 #define GRUB_PC_PARTITION_TYPE_LINUX_RAID	0xfd
 
-/* Constants for BSD disk label.  */
-#define GRUB_PC_PARTITION_BSD_LABEL_SECTOR	1
-#define GRUB_PC_PARTITION_BSD_LABEL_MAGIC	0x82564557
-#define GRUB_PC_PARTITION_BSD_MAX_ENTRIES	8
-
-/* BSD partition types.  */
-#define GRUB_PC_PARTITION_BSD_TYPE_UNUSED	0
-#define GRUB_PC_PARTITION_BSD_TYPE_SWAP		1
-#define GRUB_PC_PARTITION_BSD_TYPE_V6		2
-#define GRUB_PC_PARTITION_BSD_TYPE_V7		3
-#define GRUB_PC_PARTITION_BSD_TYPE_SYSV		4
-#define GRUB_PC_PARTITION_BSD_TYPE_V71K		5
-#define GRUB_PC_PARTITION_BSD_TYPE_V8		6
-#define GRUB_PC_PARTITION_BSD_TYPE_BSDFFS	7
-#define GRUB_PC_PARTITION_BSD_TYPE_MSDOS	8
-#define GRUB_PC_PARTITION_BSD_TYPE_BSDLFS	9
-#define GRUB_PC_PARTITION_BSD_TYPE_OTHER	10
-#define GRUB_PC_PARTITION_BSD_TYPE_HPFS		11
-#define GRUB_PC_PARTITION_BSD_TYPE_ISO9660	12
-#define GRUB_PC_PARTITION_BSD_TYPE_BOOT		13
-
-/* FreeBSD-specific types.  */
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_VINUM	14
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_RAID	15
-#define GRUB_PC_PARTITION_FREEBSD_TYPE_JFS2	21
-
-/* NetBSD-specific types.  */
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_ADOS	14
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_HFS	15
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_FILECORE	16
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_EXT2FS	17
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_NTFS	18
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_RAID	19
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_CCD	20
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_JFS2	21
-#define	GRUB_PC_PARTITION_NETBSD_TYPE_APPLEUFS	22
-
-/* OpenBSD-specific types.  */
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_ADOS	14
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_HFS	15
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_FILECORE	16
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_EXT2FS	17
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS	18
-#define	GRUB_PC_PARTITION_OPENBSD_TYPE_RAID	19
-
-/* The BSD partition entry.  */
-struct grub_msdos_partition_bsd_entry
-{
-  grub_uint32_t size;
-  grub_uint32_t offset;
-  grub_uint32_t fragment_size;
-  grub_uint8_t fs_type;
-  grub_uint8_t fs_fragments;
-  grub_uint16_t fs_cylinders;
-} __attribute__ ((packed));
-
-/* The BSD disk label. Only define members useful for GRUB.  */
-struct grub_msdos_partition_disk_label
-{
-  grub_uint32_t magic;
-  grub_uint8_t padding[128];
-  grub_uint32_t magic2;
-  grub_uint16_t checksum;
-  grub_uint16_t num_partitions;
-  grub_uint32_t boot_size;
-  grub_uint32_t superblock_size;
-  struct grub_msdos_partition_bsd_entry entries[GRUB_PC_PARTITION_BSD_MAX_ENTRIES];
-} __attribute__ ((packed));
-
 /* The partition entry.  */
 struct grub_msdos_partition_entry
 {
@@ -168,23 +99,6 @@ struct grub_msdos_partition_mbr
 } __attribute__ ((packed));
 
 \f
-struct grub_msdos_partition
-{
-    /* The DOS partition number.  */
-  int dos_part;
-
-  /* The BSD partition number (a == 0).  */
-  int bsd_part;
-
-  /* The DOS partition type.  */
-  int dos_type;
-
-  /* The BSD partition type.  */
-  int bsd_type;
-
-  /* The offset of the extended partition.  */
-  unsigned long ext_offset;
-};
 
 static inline int
 grub_msdos_partition_is_empty (int type)
@@ -200,12 +114,4 @@ grub_msdos_partition_is_extended (int type)
 	  || type == GRUB_PC_PARTITION_TYPE_LINUX_EXTENDED);
 }
 
-static inline int
-grub_msdos_partition_is_bsd (int type)
-{
-  return (type == GRUB_PC_PARTITION_TYPE_FREEBSD
-	  || type == GRUB_PC_PARTITION_TYPE_OPENBSD
-	  || type == GRUB_PC_PARTITION_TYPE_NETBSD);
-}
-
 #endif /* ! GRUB_PC_PARTITION_HEADER */
diff --git a/include/grub/partition.h b/include/grub/partition.h
index d35658c..5e8c476 100644
--- a/include/grub/partition.h
+++ b/include/grub/partition.h
@@ -36,13 +36,6 @@ struct grub_partition_map
 			 int (*hook) (struct grub_disk *disk,
 				      const grub_partition_t partition));
 
-  /* Return the partition named STR on the disk DISK.  */
-  grub_partition_t (*probe) (struct grub_disk *disk,
-			     const char *str);
-
-  /* Return the name of the partition PARTITION.  */
-  char *(*get_name) (const grub_partition_t partition);
-
   /* The next partition map type.  */
   struct grub_partition_map *next;
 };
@@ -51,6 +44,9 @@ typedef struct grub_partition_map *grub_partition_map_t;
 /* Partition description.  */
 struct grub_partition
 {
+  /* The partition number.  */
+  int number;
+
   /* The start sector.  */
   grub_disk_addr_t start;
 
@@ -66,6 +62,9 @@ struct grub_partition
   /* Partition map type specific data.  */
   void *data;
 
+  /* Parent partition map.  */
+  struct grub_partition *parent;
+
   /* The type partition map.  */
   grub_partition_map_t partmap;
 };
@@ -101,7 +100,13 @@ void grub_apple_partition_map_fini (void);
 static inline grub_disk_addr_t
 grub_partition_get_start (const grub_partition_t p)
 {
-  return p->start;
+  grub_partition_t part;
+  grub_uint64_t part_start = 0;
+
+  for (part = p; part; part = part->parent)
+    part_start += part->start;
+
+  return part_start;
 }
 
 static inline grub_uint64_t
diff --git a/kern/disk.c b/kern/disk.c
index e463626..657ac8d 100644
--- a/kern/disk.c
+++ b/kern/disk.c
@@ -330,6 +330,7 @@ grub_disk_open (const char *name)
 void
 grub_disk_close (grub_disk_t disk)
 {
+  grub_partition_t part;
   grub_dprintf ("disk", "Closing `%s'.\n", disk->name);
 
   if (disk->dev && disk->dev->close)
@@ -338,7 +339,13 @@ grub_disk_close (grub_disk_t disk)
   /* Reset the timer.  */
   grub_last_time = grub_get_time_ms ();
 
-  grub_free (disk->partition);
+  while (disk->partition)
+    {
+      part = disk->partition->parent;
+      grub_free (disk->partition->data);
+      grub_free (disk->partition);
+      disk->partition = part;
+    }
   grub_free ((void *) disk->name);
   grub_free (disk);
 }
@@ -349,18 +356,19 @@ grub_disk_close (grub_disk_t disk)
    - Verify that the range is inside the partition.  */
 static grub_err_t
 grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
-		       grub_off_t *offset, grub_size_t size)
+			grub_off_t *offset, grub_size_t size)
 {
+  grub_partition_t part;
   *sector += *offset >> GRUB_DISK_SECTOR_BITS;
   *offset &= GRUB_DISK_SECTOR_SIZE - 1;
 
-  if (disk->partition)
+  for (part = disk->partition; part; part = part->parent)
     {
       grub_disk_addr_t start;
       grub_uint64_t len;
 
-      start = grub_partition_get_start (disk->partition);
-      len = grub_partition_get_len (disk->partition);
+      start = part->start;
+      len = part->len;
 
       if (*sector >= len
 	  || len - *sector < ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
diff --git a/kern/partition.c b/kern/partition.c
index 4d5c63a..4bcd8c7 100644
--- a/kern/partition.c
+++ b/kern/partition.c
@@ -17,6 +17,7 @@
  */
 
 #include <grub/misc.h>
+#include <grub/mm.h>
 #include <grub/partition.h>
 #include <grub/disk.h>
 
@@ -54,17 +55,58 @@ grub_partition_map_iterate (int (*hook) (const grub_partition_map_t partmap))
   return 0;
 }
 
+static grub_partition_t
+grub_partition_map_probe (const grub_partition_map_t partmap,
+			  grub_disk_t disk, int partnum)
+{
+  grub_partition_t p = 0;
+
+  auto int find_func (grub_disk_t d, const grub_partition_t partition);
+
+  int find_func (grub_disk_t d __attribute__ ((unused)),
+		 const grub_partition_t partition)
+    {
+      if (partnum == partition->number)
+	{
+	  p = (grub_partition_t) grub_malloc (sizeof (*p));
+	  if (! p)
+	    return 1;
+
+	  grub_memcpy (p, partition, sizeof (*p));
+	  return 1;
+	}
+
+      return 0;
+    }
+
+  partmap->iterate (disk, find_func);
+  if (grub_errno)
+    goto fail;
+
+  return p;
+
+ fail:
+  grub_free (p);
+  return 0;
+}
+
 grub_partition_t
 grub_partition_probe (struct grub_disk *disk, const char *str)
 {
   grub_partition_t part = 0;
+  grub_partition_t curpart = 0;
+  grub_partition_t tail;
+  const char *ptr;
+  int num;
 
   auto int part_map_probe (const grub_partition_map_t partmap);
 
   int part_map_probe (const grub_partition_map_t partmap)
     {
-      part = partmap->probe (disk, str);
-      if (part)
+      disk->partition = part;
+      curpart = grub_partition_map_probe (partmap, disk, num);
+      disk->partition = tail;
+      if (curpart)
 	return 1;
 
       if (grub_errno == GRUB_ERR_BAD_PART_TABLE)
@@ -77,27 +119,54 @@ grub_partition_probe (struct grub_disk *disk, const char *str)
       return 1;
     }
 
-  /* Use the first partition map type found.  */
-  grub_partition_map_iterate (part_map_probe);
+  part = tail = disk->partition;
+
+  for (ptr = str; *ptr;)
+    {
+      /* BSD-like partition specification.  */
+      if (*ptr >= 'a' && *ptr <= 'z')
+	num = *(ptr++) - 'a';
+      else
+	num = grub_strtoul (ptr, (char **) &ptr, 0) - 1;
+
+      curpart = 0;
+      /* Use the first partition map type found.  */
+      grub_partition_map_iterate (part_map_probe);
+
+      if (! curpart)
+	{
+	  while (part)
+	    {
+	      curpart = part->parent;
+	      grub_free (part);
+	      part = curpart;
+	    }
+	  return 0;
+	}
+      curpart->parent = part;
+      part = curpart;
+      if (! ptr || *ptr != ',')
+	break;
+      ptr++;
+    }
 
   return part;
 }
 
-int
-grub_partition_iterate (struct grub_disk *disk,
-			int (*hook) (grub_disk_t disk,
-				     const grub_partition_t partition))
+static grub_partition_map_t
+get_partmap (struct grub_disk *disk)
 {
   grub_partition_map_t partmap = 0;
-  int ret = 0;
-
+  struct grub_partition part;
+  int found = 0;
   auto int part_map_iterate (const grub_partition_map_t p);
   auto int part_map_iterate_hook (grub_disk_t d,
 				  const grub_partition_t partition);
-
   int part_map_iterate_hook (grub_disk_t d __attribute__ ((unused)),
-			     const grub_partition_t partition __attribute__ ((unused)))
+			     const grub_partition_t partition)
     {
+      found = 1;
+      part = *partition;
       return 1;
     }
 
@@ -106,22 +175,58 @@ grub_partition_iterate (struct grub_disk *disk,
       grub_dprintf ("partition", "Detecting %s...\n", p->name);
       p->iterate (disk, part_map_iterate_hook);
 
-      if (grub_errno != GRUB_ERR_NONE)
+      if (grub_errno != GRUB_ERR_NONE || ! found)
 	{
 	  /* Continue to next partition map type.  */
 	  grub_dprintf ("partition", "%s detection failed.\n", p->name);
 	  grub_errno = GRUB_ERR_NONE;
 	  return 0;
 	}
+      grub_free (part.data);
 
       grub_dprintf ("partition", "%s detection succeeded.\n", p->name);
       partmap = p;
       return 1;
     }
-
   grub_partition_map_iterate (part_map_iterate);
-  if (partmap)
-    ret = partmap->iterate (disk, hook);
+  return partmap;
+}
+
+int
+grub_partition_iterate (struct grub_disk *disk,
+			int (*hook) (grub_disk_t disk,
+				     const grub_partition_t partition))
+{
+  int ret = 0;
+
+  auto int part_iterate (grub_disk_t dsk, const grub_partition_t p);
+
+  int part_iterate (grub_disk_t dsk,
+		    const grub_partition_t partition)
+    {
+      struct grub_partition p = *partition;
+      grub_partition_map_t partmap = 0;
+      p.parent = dsk->partition;
+      dsk->partition = 0;
+      if (hook (dsk, &p))
+	  return 1;
+      if (p.start != 0)
+	{
+	  dsk->partition = &p;
+	  partmap = get_partmap (dsk);
+	  if (partmap)
+	    ret = partmap->iterate (dsk, part_iterate);
+	}
+      dsk->partition = p.parent;
+      return ret;
+    }
+
+  {
+    grub_partition_map_t partmap = 0;
+    partmap = get_partmap (disk);
+    if (partmap)
+      ret = partmap->iterate (disk, part_iterate);
+  }
 
   return ret;
 }
@@ -129,5 +234,30 @@ grub_partition_iterate (struct grub_disk *disk,
 char *
 grub_partition_get_name (const grub_partition_t partition)
 {
-  return partition->partmap->get_name (partition);
+  char *out = 0;
+  /* Even on 64-bit machines this buffer is enough to hold longest number.  */
+  char buf[25];
+  int curlen = 0;
+  grub_partition_t part;
+  for (part = partition; part; part = part->parent)
+    {
+      int strl;
+      grub_sprintf (buf, "%d", part->number + 1);
+      strl = grub_strlen (buf);
+      if (curlen)
+	{
+	  out = grub_realloc (out, curlen + strl + 2);
+	  grub_memcpy (out + strl + 1, out, curlen);
+	  out[curlen + 1 + strl] = 0;
+	  grub_memcpy (out, buf, strl);
+	  out[strl] = ',';
+	  curlen = curlen + 1 + strl;
+	}
+      else
+	{
+	  curlen = strl;
+	  out = grub_strdup (buf);
+	}
+    }
+  return out;
 }
diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c
index 0b9a2b4..792d38f 100644
--- a/loader/i386/bsd.c
+++ b/loader/i386/bsd.c
@@ -135,7 +135,6 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
 		     grub_uint32_t * unit,
 		     grub_uint32_t * slice, grub_uint32_t * part)
 {
-  char *p;
   grub_device_t dev; 
 
   *biosdev = grub_get_root_biosnumber () & 0xff;
@@ -145,21 +144,13 @@ grub_bsd_get_device (grub_uint32_t * biosdev,
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-
-      p = dev->disk->partition->partmap->get_name (dev->disk->partition);
-      if (p)
+      if (dev->disk->partition->parent)
 	{
-	  if ((p[0] >= '0') && (p[0] <= '9'))
-	    {
-	      *slice = grub_strtoul (p, &p, 0);
-
-	      if ((p) && (p[0] == ','))
-		p++;
-	    }
-
-	  if ((p[0] >= 'a') && (p[0] <= 'z'))
-	    *part = p[0] - 'a';
+	  *part = dev->disk->partition->number;
+	  *slice = dev->disk->partition->parent->number + 1;
 	}
+      else
+	*slice = dev->disk->partition->number + 1;
     }
   if (dev)
     grub_device_close (dev);
diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c
index 8c3139b..719a51d 100644
--- a/loader/i386/multiboot.c
+++ b/loader/i386/multiboot.c
@@ -155,7 +155,6 @@ static int
 grub_multiboot_get_bootdev (grub_uint32_t *bootdev)
 {
 #ifdef GRUB_MACHINE_PCBIOS
-  char *p;
   grub_uint32_t biosdev, slice = ~0, part = ~0;
   grub_device_t dev;
 
@@ -164,21 +163,13 @@ grub_multiboot_get_bootdev (grub_uint32_t *bootdev)
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-
-      p = dev->disk->partition->partmap->get_name (dev->disk->partition);
-      if (p)
+      if (dev->disk->partition->parent)
 	{
-	  if ((p[0] >= '0') && (p[0] <= '9'))
-	    {
-	      slice = grub_strtoul (p, &p, 0) - 1;
-
-	      if ((p) && (p[0] == ','))
-		p++;
-	    }
-
-	  if ((p[0] >= 'a') && (p[0] <= 'z'))
-	    part = p[0] - 'a';
+	  part = dev->disk->partition->number;
+	  slice = dev->disk->partition->parent->number;
 	}
+      else
+	slice = dev->disk->partition->number;
     }
   if (dev)
     grub_device_close (dev);
diff --git a/loader/i386/pc/chainloader.c b/loader/i386/pc/chainloader.c
index caf1450..b0503ae 100644
--- a/loader/i386/pc/chainloader.c
+++ b/loader/i386/pc/chainloader.c
@@ -31,6 +31,7 @@
 #include <grub/machine/memory.h>
 #include <grub/dl.h>
 #include <grub/command.h>
+#include <grub/msdos_partition.h>
 #include <grub/machine/biosnum.h>
 
 static grub_dl_t my_mod;
@@ -94,10 +95,22 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
   dev = grub_device_open (0);
   if (dev && dev->disk && dev->disk->partition)
     {
-      grub_disk_read (dev->disk, dev->disk->partition->offset, 446, 64,
-		      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
-      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
-			    + (dev->disk->partition->index << 4));
+      grub_disk_t disk = dev->disk;
+
+      if (disk)
+	{
+	  grub_partition_t p = disk->partition;
+
+	  if (p && grub_strcmp (p->partmap->name, "part_msdos") == 0)
+	    {
+	      disk->partition = p->parent;
+	      grub_disk_read (disk, p->offset, 446, 64,
+			      (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR);
+	      part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR
+				    + (p->index << 4));
+	      disk->partition = p;
+	    }
+	}
     }
 
   if (dev)
diff --git a/partmap/acorn.c b/partmap/acorn.c
index e005975..af9498e 100644
--- a/partmap/acorn.c
+++ b/partmap/acorn.c
@@ -96,21 +96,17 @@ acorn_partition_map_iterate (grub_disk_t disk,
 					  const grub_partition_t partition))
 {
   struct grub_partition part;
-  struct grub_disk raw;
   struct linux_part map[LINUX_MAP_ENTRIES];
   int i;
-  grub_disk_addr_t sector;
+  grub_disk_addr_t sector = 0;
   grub_err_t err;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
-  err = acorn_partition_map_find (&raw, map, &sector);
+  err = acorn_partition_map_find (disk, map, &sector);
   if (err)
     return err;
 
   part.partmap = &grub_acorn_partition_map;
+  part.data = 0;
 
   for (i = 0; i != LINUX_MAP_ENTRIES; ++i)
     {
@@ -121,7 +117,7 @@ acorn_partition_map_iterate (grub_disk_t disk,
       part.start = sector + map[i].start;
       part.len = map[i].size;
       part.offset = 6;
-      part.index = i;
+      part.number = part.index = i;
 
       if (hook (disk, &part))
 	return grub_errno;
@@ -130,60 +126,6 @@ acorn_partition_map_iterate (grub_disk_t disk,
   return GRUB_ERR_NONE;
 }
 
-
-static grub_partition_t
-acorn_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  struct linux_part map[LINUX_MAP_ENTRIES];
-  struct grub_disk raw = *disk;
-  unsigned long partnum = grub_strtoul (str, 0, 10) - 1;
-  grub_disk_addr_t sector;
-  grub_err_t err;
-  grub_partition_t p;
-
-  /* Enforce raw disk access.  */
-  raw.partition = 0;
-
-  /* Get the partition number.  */
-  if (partnum > LINUX_MAP_ENTRIES)
-    goto fail;
-
-  err = acorn_partition_map_find (&raw, map, &sector);
-  if (err)
-    return 0;
-
-  if (map[partnum].magic != LINUX_NATIVE_MAGIC
-      && map[partnum].magic != LINUX_SWAP_MAGIC)
-    goto fail;
-
-  p = grub_malloc (sizeof (struct grub_partition));
-  if (! p)
-    return 0;
-
-  p->start = sector + map[partnum].start;
-  p->len = map[partnum].size;
-  p->offset = 6;
-  p->index = partnum;
-  return p;
-
-fail:
-  grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-  return 0;
-}
-
-
-static char *
-acorn_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
 \f
 
 /* Partition map type.  */
@@ -191,8 +133,6 @@ static struct grub_partition_map grub_acorn_partition_map =
 {
   .name = "part_acorn",
   .iterate = acorn_partition_map_iterate,
-  .probe = acorn_partition_map_probe,
-  .get_name = acorn_partition_map_get_name
 };
 
 GRUB_MOD_INIT(acorn_partition_map)
diff --git a/partmap/amiga.c b/partmap/amiga.c
index dce9f4f..27ccf95 100644
--- a/partmap/amiga.c
+++ b/partmap/amiga.c
@@ -76,20 +76,15 @@ amiga_partition_map_iterate (grub_disk_t disk,
 {
   struct grub_partition part;
   struct grub_amiga_rdsk rdsk;
-  struct grub_disk raw;
   int partno = 0;
   int next = -1;
   unsigned pos;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   /* The RDSK block is one of the first 15 blocks.  */
   for (pos = 0; pos < 15; pos++)
     {
       /* Read the RDSK block which is a descriptor for the entire disk.  */
-      if (grub_disk_read (&raw, pos, 0, sizeof (rdsk), &rdsk))
+      if (grub_disk_read (disk, pos, 0, sizeof (rdsk), &rdsk))
 	return grub_errno;
 
       if (grub_strcmp ((char *) rdsk.magic, "RDSK") == 0)
@@ -104,13 +99,15 @@ amiga_partition_map_iterate (grub_disk_t disk,
     return grub_error (GRUB_ERR_BAD_PART_TABLE,
 		       "Amiga partition map not found.");
 
+  part.data = 0;
+
   /* The end of the partition list is marked using "-1".  */
   while (next != -1)
     {
       struct grub_amiga_partition apart;
 
       /* Read the RDSK block which is a descriptor for the entire disk.  */
-      if (grub_disk_read (&raw, next, 0, sizeof (apart), &apart))
+      if (grub_disk_read (disk, next, 0, sizeof (apart), &apart))
 	return grub_errno;
 
       /* Calculate the first block and the size of the partition.  */
@@ -123,7 +120,8 @@ amiga_partition_map_iterate (grub_disk_t disk,
 		  * grub_be_to_cpu32 (apart.block_per_track));
 
       part.offset = (grub_off_t) next * 512;
-      part.index = partno;
+      part.number = partno;
+      part.index = 0;
       part.partmap = &grub_amiga_partition_map;
 
       if (hook (disk, &part))
@@ -136,72 +134,12 @@ amiga_partition_map_iterate (grub_disk_t disk,
   return 0;
 }
 
-
-static grub_partition_t
-amiga_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  if (amiga_partition_map_iterate (disk, find_func))
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-amiga_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_amiga_partition_map =
   {
     .name = "part_amiga",
     .iterate = amiga_partition_map_iterate,
-    .probe = amiga_partition_map_probe,
-    .get_name = amiga_partition_map_get_name
   };
 
 GRUB_MOD_INIT(amiga_partition_map)
diff --git a/partmap/apple.c b/partmap/apple.c
index 4dea55a..3534ac3 100644
--- a/partmap/apple.c
+++ b/partmap/apple.c
@@ -105,17 +105,12 @@ apple_partition_map_iterate (grub_disk_t disk,
   struct grub_partition part;
   struct grub_apple_header aheader;
   struct grub_apple_part apart;
-  struct grub_disk raw;
   int partno = 0, partnum = 0;
   unsigned pos;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   part.partmap = &grub_apple_partition_map;
 
-  if (grub_disk_read (&raw, 0, 0, sizeof (aheader), &aheader))
+  if (grub_disk_read (disk, 0, 0, sizeof (aheader), &aheader))
     return grub_errno;
 
   if (grub_be_to_cpu16 (aheader.magic) != GRUB_APPLE_HEADER_MAGIC)
@@ -127,14 +122,17 @@ apple_partition_map_iterate (grub_disk_t disk,
       goto fail;
     }
 
+  part.data = 0;
   pos = grub_be_to_cpu16 (aheader.blocksize);
 
   do
     {
-      if (grub_disk_read (&raw, pos / GRUB_DISK_SECTOR_SIZE,
-			  pos % GRUB_DISK_SECTOR_SIZE,
-			  sizeof (struct grub_apple_part),  &apart))
-	return grub_errno;
+       part.offset = pos / GRUB_DISK_SECTOR_SIZE;
+       part.index = pos % GRUB_DISK_SECTOR_SIZE;
+
+       if (grub_disk_read (disk, part.offset, part.index,
+			   sizeof (struct grub_apple_part),  &apart))
+	 return grub_errno;
 
       if (grub_be_to_cpu16 (apart.magic) != GRUB_APPLE_PART_MAGIC)
 	{
@@ -156,6 +154,7 @@ apple_partition_map_iterate (grub_disk_t disk,
 	/ GRUB_DISK_SECTOR_SIZE;
       part.offset = pos;
       part.index = partno;
+      part.number = partno;
 
       grub_dprintf ("partition",
 		    "partition %d: name %s, type %s, start 0x%x, len 0x%x\n",
@@ -179,72 +178,12 @@ apple_partition_map_iterate (grub_disk_t disk,
 		     "Apple partition map not found.");
 }
 
-
-static grub_partition_t
-apple_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  if (apple_partition_map_iterate (disk, find_func))
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-apple_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_apple_partition_map =
   {
     .name = "part_apple",
     .iterate = apple_partition_map_iterate,
-    .probe = apple_partition_map_probe,
-    .get_name = apple_partition_map_get_name
   };
 
 GRUB_MOD_INIT(apple_partition_map)
diff --git a/partmap/bsdlabel.c b/partmap/bsdlabel.c
new file mode 100644
index 0000000..8613881
--- /dev/null
+++ b/partmap/bsdlabel.c
@@ -0,0 +1,97 @@
+/* bsdlabel.c - Read BSD style partition tables.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2004,2005,2006,2007,2008,2009  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/partition.h>
+#include <grub/bsdlabel.h>
+#include <grub/disk.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/dl.h>
+
+static struct grub_partition_map grub_bsdlabel_partition_map;
+\f
+
+static grub_err_t
+bsdlabel_partition_map_iterate (grub_disk_t disk,
+				int (*hook) (grub_disk_t disk,
+					     const grub_partition_t partition))
+{
+  struct grub_partition_bsd_disk_label label;
+  struct grub_partition p;
+  grub_disk_addr_t delta = 0;
+  unsigned pos;
+
+  /* BSDLabel offsets are absolute even when it's embed inside partition.  */
+  delta = grub_partition_get_start (disk->partition);
+
+  /* Read the BSD label.  */
+  if (grub_disk_read (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR,
+		      0, sizeof (label), &label))
+    return grub_errno;
+
+  /* Check if it is valid.  */
+  if (label.magic != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
+    return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
+
+  pos = sizeof (label) + GRUB_PC_PARTITION_BSD_LABEL_SECTOR
+    * GRUB_DISK_SECTOR_SIZE;
+
+  for (p.number = 0;
+       p.number < grub_cpu_to_le16 (label.num_partitions);
+       p.number++)
+    {
+      struct grub_partition_bsd_entry be;
+
+      p.offset = pos / GRUB_DISK_SECTOR_SIZE;
+      p.index = pos % GRUB_DISK_SECTOR_SIZE;
+
+      if (grub_disk_read (disk, p.offset, p.index, sizeof (be),  &be))
+	return grub_errno;
+
+      p.start = grub_le_to_cpu32 (be.offset) - delta;
+      p.len = grub_le_to_cpu32 (be.size);
+      p.partmap = &grub_bsdlabel_partition_map;
+
+      if (be.fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
+	if (hook (disk, &p))
+	  return grub_errno;
+
+      pos += sizeof (struct grub_partition_bsd_entry);
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+\f
+/* Partition map type.  */
+static struct grub_partition_map grub_bsdlabel_partition_map =
+  {
+    .name = "part_bsd",
+    .iterate = bsdlabel_partition_map_iterate,
+  };
+
+GRUB_MOD_INIT(bsd_partition_map)
+{
+  grub_partition_map_register (&grub_bsdlabel_partition_map);
+}
+
+GRUB_MOD_FINI(bsd_partition_map)
+{
+  grub_partition_map_unregister (&grub_bsdlabel_partition_map);
+}
diff --git a/partmap/gpt.c b/partmap/gpt.c
index 4a49574..c53c395 100644
--- a/partmap/gpt.c
+++ b/partmap/gpt.c
@@ -44,18 +44,13 @@ gpt_partition_map_iterate (grub_disk_t disk,
   struct grub_partition part;
   struct grub_gpt_header gpt;
   struct grub_gpt_partentry entry;
-  struct grub_disk raw;
   struct grub_msdos_partition_mbr mbr;
   grub_uint64_t entries;
   unsigned int i;
   int last_offset = 0;
 
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
-
   /* Read the protective MBR.  */
-  if (grub_disk_read (&raw, 0, 0, sizeof (mbr), &mbr))
+  if (grub_disk_read (disk, 0, 0, sizeof (mbr), &mbr))
     return grub_errno;
 
   /* Check if it is valid.  */
@@ -67,7 +62,7 @@ gpt_partition_map_iterate (grub_disk_t disk,
     return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found");
 
   /* Read the GPT header.  */
-  if (grub_disk_read (&raw, 1, 0, sizeof (gpt), &gpt))
+  if (grub_disk_read (disk, 1, 0, sizeof (gpt), &gpt))
     return grub_errno;
 
   if (grub_memcmp (gpt.magic, grub_gpt_magic, sizeof (grub_gpt_magic)))
@@ -76,11 +71,15 @@ gpt_partition_map_iterate (grub_disk_t disk,
   grub_dprintf ("gpt", "Read a valid GPT header\n");
 
   entries = grub_le_to_cpu64 (gpt.partitions);
+  part.data = grub_malloc (sizeof (entry));
   for (i = 0; i < grub_le_to_cpu32 (gpt.maxpart); i++)
     {
-      if (grub_disk_read (&raw, entries, last_offset,
+      if (grub_disk_read (disk, entries, last_offset,
 			  sizeof (entry), &entry))
-	return grub_errno;
+	{
+	  grub_free (part.data);
+	  return grub_errno;
+	}
 
       if (grub_memcmp (&grub_gpt_partition_type_empty, &entry.type,
 		       sizeof (grub_gpt_partition_type_empty)))
@@ -90,16 +89,17 @@ gpt_partition_map_iterate (grub_disk_t disk,
 	  part.len = (grub_le_to_cpu64 (entry.end)
 		      - grub_le_to_cpu64 (entry.start) + 1);
 	  part.offset = entries;
-	  part.index = i;
+	  part.number = i;
+	  part.index = last_offset;
 	  part.partmap = &grub_gpt_partition_map;
-	  part.data = &entry;
+	  grub_memcpy (part.data, &entry, sizeof (entry));
 
 	  grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", i,
 			(unsigned long long) part.start,
 			(unsigned long long) part.len);
 
 	  if (hook (disk, &part))
-	    return 1;
+	    return grub_errno;
 	}
 
       last_offset += grub_le_to_cpu32 (gpt.partentry_size);
@@ -109,67 +109,9 @@ gpt_partition_map_iterate (grub_disk_t disk,
 	  entries++;
 	}
     }
+  grub_free (part.data);
 
-  return 0;
-}
-
-
-static grub_partition_t
-gpt_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-	{
-	  p = (grub_partition_t) grub_malloc (sizeof (*p));
-	  if (! p)
-	    return 1;
-
-	  grub_memcpy (p, partition, sizeof (*p));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  /* Get the partition number.  */
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno)
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      return 0;
-    }
-
-  gpt_partition_map_iterate (disk, find_func);
-  if (grub_errno)
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  return 0;
-}
-
-
-static char *
-gpt_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  grub_sprintf (name, "%d", p->index + 1);
-  return name;
+  return GRUB_ERR_NONE;
 }
 
 \f
@@ -178,8 +120,6 @@ static struct grub_partition_map grub_gpt_partition_map =
   {
     .name = "part_gpt",
     .iterate = gpt_partition_map_iterate,
-    .probe = gpt_partition_map_probe,
-    .get_name = gpt_partition_map_get_name
   };
 
 GRUB_MOD_INIT(gpt_partition_map)
diff --git a/partmap/msdos.c b/partmap/msdos.c
index d0fc18e..598d189 100644
--- a/partmap/msdos.c
+++ b/partmap/msdos.c
@@ -27,85 +27,19 @@
 static struct grub_partition_map grub_msdos_partition_map;
 \f
 
-/* Parse the partition representation in STR and return a partition.  */
-static grub_partition_t
-grub_partition_parse (const char *str)
-{
-  grub_partition_t p;
-  struct grub_msdos_partition *pcdata;
-
-  char *s = (char *) str;
-
-  p = (grub_partition_t) grub_malloc (sizeof (*p));
-  if (! p)
-    return 0;
-
-  pcdata = (struct grub_msdos_partition *) grub_malloc (sizeof (*pcdata));
-  if (! pcdata)
-    goto fail;
-
-  p->data = pcdata;
-  p->partmap = &grub_msdos_partition_map;
-
-  /* Initialize some of the fields with invalid values.  */
-  pcdata->bsd_part = pcdata->dos_type = pcdata->bsd_type = p->index = -1;
-
-  /* Get the DOS partition number. The number is counted from one for
-     the user interface, and from zero internally.  */
-  pcdata->dos_part = grub_strtoul (s, &s, 0) - 1;
-
-  if (grub_errno)
-    {
-      /* Not found. Maybe only a BSD label is specified.  */
-      pcdata->dos_part = -1;
-      grub_errno = GRUB_ERR_NONE;
-    }
-  else if (*s == ',')
-    s++;
-
-  if (*s)
-    {
-      if (*s >= 'a' && *s <= 'h')
-	{
-	  pcdata->bsd_part = *s - 'a';
-	  s++;
-	}
-
-      if (*s)
-	goto fail;
-    }
-
-  if (pcdata->dos_part == -1 && pcdata->bsd_part == -1)
-    goto fail;
-
-  return p;
-
- fail:
-  grub_free (p);
-  grub_free (pcdata);
-  grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-  return 0;
-}
-
 static grub_err_t
 pc_partition_map_iterate (grub_disk_t disk,
 			  int (*hook) (grub_disk_t disk,
 				       const grub_partition_t partition))
 {
   struct grub_partition p;
-  struct grub_msdos_partition pcdata;
   struct grub_msdos_partition_mbr mbr;
-  struct grub_msdos_partition_disk_label label;
-  struct grub_disk raw;
-
-  /* Enforce raw disk access.  */
-  raw = *disk;
-  raw.partition = 0;
+  grub_disk_addr_t ext_offset;
 
   p.offset = 0;
-  pcdata.ext_offset = 0;
-  pcdata.dos_part = -1;
-  p.data = &pcdata;
+  ext_offset = 0;
+  p.data = 0;
+  p.number = -1;
   p.partmap = &grub_msdos_partition_map;
 
   while (1)
@@ -114,7 +48,7 @@ pc_partition_map_iterate (grub_disk_t disk,
       struct grub_msdos_partition_entry *e;
 
       /* Read the MBR.  */
-      if (grub_disk_read (&raw, p.offset, 0, sizeof (mbr), &mbr))
+      if (grub_disk_read (disk, p.offset, 0, sizeof (mbr), &mbr))
 	goto finish;
 
       /* Check if it is valid.  */
@@ -132,13 +66,10 @@ pc_partition_map_iterate (grub_disk_t disk,
 
 	  p.start = p.offset + grub_le_to_cpu32 (e->start);
 	  p.len = grub_le_to_cpu32 (e->length);
-	  pcdata.bsd_part = -1;
-	  pcdata.dos_type = e->type;
-	  pcdata.bsd_type = -1;
 
 	  grub_dprintf ("partition",
 			"partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n",
-			p.index, e->flag, pcdata.dos_type,
+			p.index, e->flag, e->type,
 			(unsigned long long) p.start,
 			(unsigned long long) p.len);
 
@@ -150,59 +81,15 @@ pc_partition_map_iterate (grub_disk_t disk,
 	  if (! grub_msdos_partition_is_empty (e->type)
 	      && ! grub_msdos_partition_is_extended (e->type))
 	    {
-	      pcdata.dos_part++;
+	      p.number++;
 
 	      if (hook (disk, &p))
-		return 1;
-
-	      /* Check if this is a BSD partition.  */
-	      if (grub_msdos_partition_is_bsd (e->type))
-		{
-		  /* Check if the BSD label is within the DOS partition.  */
-		  if (p.len <= GRUB_PC_PARTITION_BSD_LABEL_SECTOR)
-		    {
-		      grub_dprintf ("partition", "no space for disk label\n");
-		      continue;
-		    }
-		  /* Read the BSD label.  */
-		  if (grub_disk_read (&raw,
-				      (p.start
-				       + GRUB_PC_PARTITION_BSD_LABEL_SECTOR),
-				      0,
-				      sizeof (label),
-				      &label))
-		    goto finish;
-
-		  /* Check if it is valid.  */
-		  if (label.magic
-		      != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
-		    {
-		      grub_dprintf ("partition",
-				    "invalid disk label magic 0x%x on partition %d\n",
-				    label.magic, p.index);
-		      continue;
-		    }
-		  for (pcdata.bsd_part = 0;
-		       pcdata.bsd_part < grub_cpu_to_le16 (label.num_partitions);
-		       pcdata.bsd_part++)
-		    {
-		      struct grub_msdos_partition_bsd_entry *be
-			= label.entries + pcdata.bsd_part;
-
-		      p.start = grub_le_to_cpu32 (be->offset);
-		      p.len = grub_le_to_cpu32 (be->size);
-		      pcdata.bsd_type = be->fs_type;
-
-		      if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED)
-			if (hook (disk, &p))
-			  return 1;
-		    }
-		}
+		return grub_errno;
 	    }
-	  else if (pcdata.dos_part < 4)
+	  else if (p.number < 4)
 	    /* If this partition is a logical one, shouldn't increase the
 	       partition number.  */
-	    pcdata.dos_part++;
+	    p.number++;
 	}
 
       /* Find an extended partition.  */
@@ -212,9 +99,9 @@ pc_partition_map_iterate (grub_disk_t disk,
 
 	  if (grub_msdos_partition_is_extended (e->type))
 	    {
-	      p.offset = pcdata.ext_offset + grub_le_to_cpu32 (e->start);
-	      if (! pcdata.ext_offset)
-		pcdata.ext_offset = p.offset;
+	      p.offset = ext_offset + grub_le_to_cpu32 (e->start);
+	      if (! ext_offset)
+		ext_offset = p.offset;
 
 	      break;
 	    }
@@ -229,84 +116,12 @@ pc_partition_map_iterate (grub_disk_t disk,
   return grub_errno;
 }
 
-
-static grub_partition_t
-pc_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p;
-  struct grub_msdos_partition *pcdata;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      struct grub_msdos_partition *partdata = partition->data;
-
-      if ((pcdata->dos_part == partdata->dos_part || pcdata->dos_part == -1)
-	  && pcdata->bsd_part == partdata->bsd_part)
-	{
-	  grub_memcpy (p, partition, sizeof (*p));
-	  p->data = pcdata;
-	  grub_memcpy (pcdata, partdata, sizeof (*pcdata));
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  p = grub_partition_parse (str);
-  if (! p)
-    return 0;
-
-  pcdata = p->data;
-  pc_partition_map_iterate (disk, find_func);
-  if (grub_errno)
-    goto fail;
-
-  if (p->index < 0)
-    {
-      grub_error (GRUB_ERR_BAD_DEVICE, "no such partition");
-      goto fail;
-    }
-
-  return p;
-
- fail:
-  grub_free (p);
-  grub_free (pcdata);
-  return 0;
-}
-
-
-static char *
-pc_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-  struct grub_msdos_partition *pcdata = p->data;
-
-  name = grub_malloc (13);
-  if (! name)
-    return 0;
-
-  if (pcdata->bsd_part < 0)
-    grub_sprintf (name, "%d", pcdata->dos_part + 1);
-  else if (pcdata->dos_part < 0)
-    grub_sprintf (name, "%c", pcdata->bsd_part + 'a');
-  else
-    grub_sprintf (name, "%d,%c", pcdata->dos_part + 1, pcdata->bsd_part + 'a');
-
-  return name;
-}
-
 \f
 /* Partition map type.  */
 static struct grub_partition_map grub_msdos_partition_map =
   {
     .name = "part_msdos",
     .iterate = pc_partition_map_iterate,
-    .probe = pc_partition_map_probe,
-    .get_name = pc_partition_map_get_name
   };
 
 GRUB_MOD_INIT(pc_partition_map)
diff --git a/partmap/sun.c b/partmap/sun.c
index e816ec1..ff01d10 100644
--- a/partmap/sun.c
+++ b/partmap/sun.c
@@ -88,19 +88,15 @@ sun_partition_map_iterate (grub_disk_t disk,
 					const grub_partition_t partition))
 {
   grub_partition_t p;
-  struct grub_disk raw;
   struct grub_sun_block block;
   int partnum;
 
-  raw = *disk;
-  raw.partition = 0;
-
   p = (grub_partition_t) grub_zalloc (sizeof (struct grub_partition));
   if (! p)
     return grub_errno;
 
   p->partmap = &grub_sun_partition_map;
-  if (grub_disk_read (&raw, 0, 0, sizeof (struct grub_sun_block),
+  if (grub_disk_read (disk, 0, 0, sizeof (struct grub_sun_block),
 		      &block) == GRUB_ERR_NONE)
     {
       if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.magic))
@@ -124,7 +120,7 @@ sun_partition_map_iterate (grub_disk_t disk,
 		      * grub_be_to_cpu16 (block.ntrks)
 		      * grub_be_to_cpu16 (block.nsect));
 	  p->len = grub_be_to_cpu32 (desc->num_sectors);
-	  p->index = partnum;
+	  p->number = p->index = partnum;
 	  if (p->len)
 	    {
 	      if (hook (disk, p))
@@ -138,68 +134,11 @@ sun_partition_map_iterate (grub_disk_t disk,
   return grub_errno;
 }
 
-static grub_partition_t
-sun_partition_map_probe (grub_disk_t disk, const char *str)
-{
-  grub_partition_t p = 0;
-  int partnum = 0;
-  char *s = (char *) str;
-
-  auto int find_func (grub_disk_t d, const grub_partition_t partition);
-
-  int find_func (grub_disk_t d __attribute__ ((unused)),
-		 const grub_partition_t partition)
-    {
-      if (partnum == partition->index)
-        {
-          p = (grub_partition_t) grub_malloc (sizeof (*p));
-          if (p)
-            grub_memcpy (p, partition, sizeof (*p));
-
-          return 1;
-        }
-
-      return 0;
-    }
-
-  grub_errno = GRUB_ERR_NONE;
-  partnum = grub_strtoul (s, 0, 10) - 1;
-  if (grub_errno == GRUB_ERR_NONE)
-    {
-      if (sun_partition_map_iterate (disk, find_func))
-        {
-          grub_free (p);
-          p = 0;
-        }
-    }
-  else
-    {
-      grub_error (GRUB_ERR_BAD_FILENAME, "invalid partition");
-      p = 0;
-    }
-
-  return p;
-}
-
-static char *
-sun_partition_map_get_name (const grub_partition_t p)
-{
-  char *name;
-
-  name = grub_malloc (13);
-  if (name)
-    grub_sprintf (name, "%d", p->index + 1);
-
-  return name;
-}
-
 /* Partition map type.  */
 static struct grub_partition_map grub_sun_partition_map =
   {
     .name = "part_sun",
     .iterate = sun_partition_map_iterate,
-    .probe = sun_partition_map_probe,
-    .get_name = sun_partition_map_get_name
   };
 
 GRUB_MOD_INIT(sun_partition_map)
diff --git a/parttool/msdospart.c b/parttool/msdospart.c
index dbb25bc..b1fe689 100644
--- a/parttool/msdospart.c
+++ b/parttool/msdospart.c
@@ -49,7 +49,7 @@ static grub_err_t grub_pcpart_boot (const grub_device_t dev,
 
   index = dev->disk->partition->index;
   part = dev->disk->partition;
-  dev->disk->partition = 0;
+  dev->disk->partition = part->parent;
 
   /* Read the MBR.  */
   if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), &mbr))
@@ -96,7 +96,7 @@ static grub_err_t grub_pcpart_type (const grub_device_t dev,
 
   index = dev->disk->partition->index;
   part = dev->disk->partition;
-  dev->disk->partition = 0;
+  dev->disk->partition = part->parent;
 
   /* Read the parttable.  */
   if (grub_disk_read (dev->disk, part->offset, 0,
diff --git a/util/grub-probe.c b/util/grub-probe.c
index 1710ec5..d6406ce 100644
--- a/util/grub-probe.c
+++ b/util/grub-probe.c
@@ -79,13 +79,16 @@ grub_refresh (void)
 static void
 probe_partmap (grub_disk_t disk)
 {
+  grub_partition_t part;
+
   if (disk->partition == NULL)
     {
       grub_util_info ("No partition map found for %s", disk->name);
       return;
     }
 
-  printf ("%s\n", disk->partition->partmap->name);
+  for (part = disk->partition; part; part = part->parent)
+    printf ("%s\n", part->partmap->name);
 }
 
 static int
diff --git a/util/hostdisk.c b/util/hostdisk.c
index a06ecca..6e876df 100644
--- a/util/hostdisk.c
+++ b/util/hostdisk.c
@@ -333,10 +333,13 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
   {
     int is_partition = 0;
     char dev[PATH_MAX];
+    grub_disk_addr_t part_start = 0;
+
+    part_start = grub_partition_get_start (disk->partition);
 
     strcpy (dev, map[disk->id].device);
     if (disk->partition && strncmp (map[disk->id].device, "/dev/", 5) == 0)
-      is_partition = linux_find_partition (dev, disk->partition->start);
+      is_partition = linux_find_partition (dev, part_start);
 
     /* Open the partition.  */
     grub_dprintf ("hostdisk", "opening the device `%s' in open_device()", dev);
@@ -351,7 +354,7 @@ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
     ioctl (fd, BLKFLSBUF, 0);
 
     if (is_partition)
-      sector -= disk->partition->start;
+      sector -= part_start;
   }
 #else /* ! __linux__ */
 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -947,39 +950,25 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
     int find_partition (grub_disk_t disk __attribute__ ((unused)),
 			const grub_partition_t partition)
       {
- 	struct grub_msdos_partition *pcdata = NULL;
-
-	if (strcmp (partition->partmap->name, "part_msdos") == 0)
-	  pcdata = partition->data;
+	grub_disk_addr_t part_start = 0;
+	grub_util_info ("Partition %d starts from %lu",
+			partition->number, partition->start);
 
-	if (pcdata)
-	  {
-	    if (pcdata->bsd_part < 0)
-	      grub_util_info ("DOS partition %d starts from %lu",
-			      pcdata->dos_part, partition->start);
-	    else
-	      grub_util_info ("BSD partition %d,%c starts from %lu",
-			      pcdata->dos_part, pcdata->bsd_part + 'a',
-			      partition->start);
-	  }
-	else
-	  {
-	      grub_util_info ("Partition %d starts from %lu",
-			      partition->index, partition->start);
-	  }
+	part_start = grub_partition_get_start (partition);
 
-	if (hdg.start == partition->start)
+	if (hdg.start == part_start)
 	  {
-	    if (pcdata)
+	    if (partition->parent)
 	      {
-		dos_part = pcdata->dos_part;
-		bsd_part = pcdata->bsd_part;
+		dos_part = partition->parent->number;
+		bsd_part = partition->number;
 	      }
 	    else
 	      {
-		dos_part = partition->index;
+		dos_part = partition->number;
 		bsd_part = -1;
 	      }
+
 	    return 1;
 	  }
 
diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c
index ccfbd1d..06add7c 100644
--- a/util/i386/pc/grub-setup.c
+++ b/util/i386/pc/grub-setup.c
@@ -121,15 +121,10 @@ setup (const char *dir,
   int NESTED_FUNC_ATTR find_usable_region_msdos (grub_disk_t disk __attribute__ ((unused)),
 						 const grub_partition_t p)
     {
-      struct grub_msdos_partition *pcdata = p->data;
-
       /* There's always an embed region, and it starts right after the MBR.  */
       embed_region.start = 1;
 
-      /* For its end offset, include as many dummy partitions as we can.  */
-      if (! grub_msdos_partition_is_empty (pcdata->dos_type)
-	  && ! grub_msdos_partition_is_bsd (pcdata->dos_type)
-	  && embed_region.end > p->start)
+      if (embed_region.end > p->start)
 	embed_region.end = p->start;
 
       return 0;
@@ -278,22 +273,19 @@ setup (const char *dir,
       /* Embed information about the installed location.  */
       if (root_dev->disk->partition)
 	{
-	  if (strcmp (root_dev->disk->partition->partmap->name,
-		      "part_msdos") == 0)
+	  if (root_dev->disk->partition->parent)
 	    {
-	      struct grub_msdos_partition *pcdata =
-		root_dev->disk->partition->data;
-	      dos_part = pcdata->dos_part;
-	      bsd_part = pcdata->bsd_part;
+	      if (root_dev->disk->partition->parent->parent)
+		grub_util_error ("Installing on doubly nested partitions is "
+				 "not supported");
+	      dos_part = root_dev->disk->partition->parent->number;
+	      bsd_part = root_dev->disk->partition->number;
 	    }
-	  else if (strcmp (root_dev->disk->partition->partmap->name,
-			   "part_gpt") == 0)
+	  else
 	    {
-	      dos_part = root_dev->disk->partition->index;
+	      dos_part = root_dev->disk->partition->number;
 	      bsd_part = -1;
 	    }
-	  else
-	    grub_util_error ("No PC style partitions found");
 	}
       else
 	dos_part = bsd_part = -1;
@@ -326,6 +318,8 @@ setup (const char *dir,
   int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk __attribute__ ((unused)),
 					 const grub_partition_t p)
     {
+      if (p->parent)
+	return 0;
       dest_partmap = p->partmap->name;
       return 1;
     }

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-25 20:14                       ` Vladimir 'phcoder' Serbinenko
@ 2009-08-25 23:07                         ` Robert Millan
  2009-08-25 23:13                           ` Vladimir 'phcoder' Serbinenko
  0 siblings, 1 reply; 36+ messages in thread
From: Robert Millan @ 2009-08-25 23:07 UTC (permalink / raw)
  To: The development of GRUB 2

On Tue, Aug 25, 2009 at 10:14:45PM +0200, Vladimir 'phcoder' Serbinenko wrote:
> On Robert's request I write about the usage cases I'm aware. It's by
> no means complete
> 
> 1) bsdlabel on PC-style. By most *BSD flavours
> 2) sunpc on PC-style. By Solaris
> 3) Some kind on PC-style on PC-style by Minix. (not sure about this
> one -it was a long time ago)
> I vaguely heard of (I may be completely wrong):
> 4) amiga on PC-style by AROS
> 5) sun on apple. Polaris (?)

Can someone confirm the third one?  It's the only one that breaks the
"contained label inside container label" pattern.

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-25 23:07                         ` Robert Millan
@ 2009-08-25 23:13                           ` Vladimir 'phcoder' Serbinenko
  2009-08-26  0:50                             ` Robert Millan
  0 siblings, 1 reply; 36+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-08-25 23:13 UTC (permalink / raw)
  To: The development of GRUB 2

On Wed, Aug 26, 2009 at 1:07 AM, Robert Millan<rmh@aybabtu.com> wrote:
> On Tue, Aug 25, 2009 at 10:14:45PM +0200, Vladimir 'phcoder' Serbinenko wrote:
>> On Robert's request I write about the usage cases I'm aware. It's by
>> no means complete
>>
>> 1) bsdlabel on PC-style. By most *BSD flavours
>> 2) sunpc on PC-style. By Solaris
>> 3) Some kind on PC-style on PC-style by Minix. (not sure about this
>> one -it was a long time ago)
>> I vaguely heard of (I may be completely wrong):
>> 4) amiga on PC-style by AROS
>> 5) sun on apple. Polaris (?)
>
> Can someone confirm the third one?  It's the only one that breaks the
> "contained label inside container label" pattern.
4 and 5 would break this pattern as well. Amiga and Sun are used
standalone on corresponding systems.
>
> --
> Robert Millan
>
>  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
>  how) you may access your data; but nobody's threatening your freedom: we
>  still allow you to remove your data and not access it at all."
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>



-- 
Regards
Vladimir 'phcoder' Serbinenko

Personal git repository: http://repo.or.cz/w/grub2/phcoder.git



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-25 23:13                           ` Vladimir 'phcoder' Serbinenko
@ 2009-08-26  0:50                             ` Robert Millan
  0 siblings, 0 replies; 36+ messages in thread
From: Robert Millan @ 2009-08-26  0:50 UTC (permalink / raw)
  To: The development of GRUB 2

On Wed, Aug 26, 2009 at 01:13:11AM +0200, Vladimir 'phcoder' Serbinenko wrote:
> On Wed, Aug 26, 2009 at 1:07 AM, Robert Millan<rmh@aybabtu.com> wrote:
> > On Tue, Aug 25, 2009 at 10:14:45PM +0200, Vladimir 'phcoder' Serbinenko wrote:
> >> On Robert's request I write about the usage cases I'm aware. It's by
> >> no means complete
> >>
> >> 1) bsdlabel on PC-style. By most *BSD flavours
> >> 2) sunpc on PC-style. By Solaris
> >> 3) Some kind on PC-style on PC-style by Minix. (not sure about this
> >> one -it was a long time ago)
> >> I vaguely heard of (I may be completely wrong):
> >> 4) amiga on PC-style by AROS
> >> 5) sun on apple. Polaris (?)
> >
> > Can someone confirm the third one?  It's the only one that breaks the
> > "contained label inside container label" pattern.
> 4 and 5 would break this pattern as well. Amiga and Sun are used
> standalone on corresponding systems.

None of them seem to be acting as container and containee at the same time.

For example, amiga can be a containee, but it's never a container for
anything (as far as we know).

In fact, we only know one label that is used as container, possibly two if #5
exists.

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2009-08-25 21:12                         ` Vladimir 'phcoder' Serbinenko
@ 2010-01-22 16:53                           ` Robert Millan
  2010-01-22 18:03                             ` Vladimir 'φ-coder/phcoder' Serbinenko
  2010-01-22 18:43                             ` Seth Goldberg
  0 siblings, 2 replies; 36+ messages in thread
From: Robert Millan @ 2010-01-22 16:53 UTC (permalink / raw)
  To: The development of GRUB 2


I haven't checked the specific details, but I think this approach is fine IF
we only recurse for partition types where this makes sense.  This includes:

  - BSD partition types inside MSDOS labels
  - Solaris partition type inside MSDOS labels

This can be done by extending "has_partitions" to be set to "yes" in those
specific partition types.  The implementation should be the least intrusive
possible, taking into account that this kind of situations are an oddity
rather than the norm.

As for the other situations, the more I think about this, the more convinced
I am that this whole "partition nesting" concept is a broken mess.  I think I
already explained why in this list, but I can rehash the reasons if anyone's
interested.  I don't want to compromise on such part of GRUB core for the sake
of supporting this kind of layouts.

The only reason I'm open to implementing these two cases [1] is that they seem
to be inmensely popular among *BSD systems and Solaris derivatives.

As for *BSD and Solaris who read this, my advice is to step away, ditch the
whole MSDOS label burden and just settle on a clean label without the limits
DOS ones have.  If you strive for compatibility, GPT is a good choice IMO (and
the rest of the free world seems to be moving in this direction thanks to 2 TiB
limit).

[1] I know the first one is already implemented, but your approach makes it
    less ad-hoc and splits code off part_msdos.mod, which is an improvement.

-- 
Robert Millan

  "Be the change you want to see in the world" -- Gandhi



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2010-01-22 16:53                           ` Robert Millan
@ 2010-01-22 18:03                             ` Vladimir 'φ-coder/phcoder' Serbinenko
  2010-01-24 20:41                               ` Robert Millan
  2010-01-22 18:43                             ` Seth Goldberg
  1 sibling, 1 reply; 36+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2010-01-22 18:03 UTC (permalink / raw)
  To: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 2078 bytes --]

Robert Millan wrote:
> I haven't checked the specific details, but I think this approach is fine IF
> we only recurse for partition types where this makes sense.  This includes:
>
>   - BSD partition types inside MSDOS labels
>   - Solaris partition type inside MSDOS labels
>   
What with minix?
> This can be done by extending "has_partitions" to be set to "yes" in those
> specific partition types.  The implementation should be the least intrusive
> possible, taking into account that this kind of situations are an oddity
> rather than the norm.
>
>   
Partition types are easily screwed. Why not just check for the presence
of the label?
> As for the other situations, the more I think about this, the more convinced
> I am that this whole "partition nesting" concept is a broken mess.  I think I
> already explained why in this list, but I can rehash the reasons if anyone's
> interested.  I don't want to compromise on such part of GRUB core for the sake
> of supporting this kind of layouts.
>   
Actually I don't see my patch as of any compromise. On the contrary:
current code is a compromise with a horrible set of functions verbatimly
replicated across all partition modules.
> The only reason I'm open to implementing these two cases [1] is that they seem
> to be inmensely popular among *BSD systems and Solaris derivatives.
>
>   
Solaris nested partition table provides decent embedding region.
FreeBSD supports GPT and doesn't attempt to nest partitions on it.
> As for *BSD and Solaris who read this, my advice is to step away, ditch the
> whole MSDOS label burden and just settle on a clean label without the limits
> DOS ones have.  If you strive for compatibility, GPT is a good choice IMO (and
> the rest of the free world seems to be moving in this direction thanks to 2 TiB
> limit).
>
> [1] I know the first one is already implemented, but your approach makes it
>     less ad-hoc and splits code off part_msdos.mod, which is an improvement.
>
>   


-- 
Regards
Vladimir 'φ-coder/phcoder' Serbinenko



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 293 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2010-01-22 16:53                           ` Robert Millan
  2010-01-22 18:03                             ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2010-01-22 18:43                             ` Seth Goldberg
  2010-01-24 20:44                               ` Robert Millan
  1 sibling, 1 reply; 36+ messages in thread
From: Seth Goldberg @ 2010-01-22 18:43 UTC (permalink / raw)
  To: The development of GNU GRUB

Hi,

Quoting Robert Millan, who wrote the following on Fri, 22 Jan 2010:

>
> I haven't checked the specific details, but I think this approach is fine IF
> we only recurse for partition types where this makes sense.  This includes:
>
>  - BSD partition types inside MSDOS labels
>  - Solaris partition type inside MSDOS labels
>
> This can be done by extending "has_partitions" to be set to "yes" in those
> specific partition types.  The implementation should be the least intrusive
> possible, taking into account that this kind of situations are an oddity
> rather than the norm.
>
> As for the other situations, the more I think about this, the more convinced
> I am that this whole "partition nesting" concept is a broken mess.  I think I
> already explained why in this list, but I can rehash the reasons if anyone's
> interested.  I don't want to compromise on such part of GRUB core for the sake
> of supporting this kind of layouts.

   The UEFI specification specifies support for nested MSDOS labels (MSDOS 
labels that include partitions in which another MSDOS partition table can 
be nested).  This is not talking just about extended partitions, but 
about the ability to arbitrarily nest MSDOS partition tables.  I can't point 
you to a specific implementation that uses that functionality, but the fact 
that it's specified should be enough to allow us to be flexible here.  Why 
limit the nesting if architecturally it's not a problem to support (as 
Vladimir's existing implementation already supports arbitrary nesting).


> The only reason I'm open to implementing these two cases [1] is that they seem
> to be inmensely popular among *BSD systems and Solaris derivatives.

   Not only popular, but essential in the Solaris case, at least.

>
> As for *BSD and Solaris who read this, my advice is to step away, ditch the
> whole MSDOS label burden and just settle on a clean label without the limits
> DOS ones have.  If you strive for compatibility, GPT is a good choice IMO (and
> the rest of the free world seems to be moving in this direction thanks to 2 TiB
> limit).

   We're headed toward GPT, but we MUST continue to support the existing VTOC 
(that's what Solaris labels are called) scheme.

  --S



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2010-01-22 18:03                             ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2010-01-24 20:41                               ` Robert Millan
  2010-01-24 21:20                                 ` Vladimir 'φ-coder/phcoder' Serbinenko
                                                   ` (2 more replies)
  0 siblings, 3 replies; 36+ messages in thread
From: Robert Millan @ 2010-01-24 20:41 UTC (permalink / raw)
  To: The development of GNU GRUB

On Fri, Jan 22, 2010 at 07:03:21PM +0100, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> > This can be done by extending "has_partitions" to be set to "yes" in those
> > specific partition types.  The implementation should be the least intrusive
> > possible, taking into account that this kind of situations are an oddity
> > rather than the norm.
> >
> >   
> Partition types are easily screwed. Why not just check for the presence
> of the label?

I have a feeling I already explained this somewhere.  Doesn't seem to be in
this thread, maybe on IRC?  Anyway, it won't hurt to ellaborate on it...

First of all, the whole label type proliferation problem is inherently
impossible to resolve by technical means.  Labels overlap each other,
they can coexist without any garantee that the user expects them to be
there at all or include meaningful data.

You *can't* reliably check for any partition label.  Partitions include a
set of arbitrary data.  Sometimes they will match one of the probes,
sometimes more than one.  GRUB has no way of determining if any of those
matches is correct, because only the *user* knows that.

This is a problem we already have, but it is bearable because worst case is
detecting a label where there isn't supposed to be one, or detecting a label
type different than the one user expected.  With this proposal, two things
happen:

  - has_partitions stops being useful.  When in top level, it's relatively
    easy to make assumptions about the existance of partitions.  If it is
    a hard disk, chances are it'll be partitioned;  If it's a CDROM, chances
    are it isn't (this is an unreliable check, but its purpose is to paliate
    the effect of using another unreliable check, so overall it's a gain).

  - False positives can be repeated ad nauseam.  It can even be exploited to
    force GRUB into reading several GiBs of data, effectively DoSing it.

If you look around, all approaches at dealing with this imply appliing enough
limit to keep it sane.  For example, they limit the number of label types, the
recursion depth, etc.

If we're going to support *all* possible combinations, I'd rather revisit
and solve our detection problem first.  Not by actually making detection
reliable (that's impossible), but by stop pretending GRUB can hide this mess
from the user.  When GRUB performs guesswork, sooner or later it'll get it
wrong anyway, and the fact that it was guessing creates a false expectation
that it somehow knows the correct result.  Users end up blaming GRUB for that.

So instead of supporting things like:

  (hd0,1)
  (hd0,2)

  (ambigous; what does this mean in an hybrid MSDOS/GPT ?  What about other
  hybrid schemes?  GRUB can't tell!)

... we could support:

  (hd0,msdos1)
  (hd0,gpt1)
  (hd0,msdos2)
  (hd0,gpt2)

whose meaning is pretty clear.  Then the user can nest as much as they like,
but they will also have to deal with the problem of identifiing the labels.

Minix: (hd0,msdos1,msdos1)

Solaris: (hd0,msdos2,sun1)

*BSD: (hd0,msdos3,bsd1)

With this approach, the burden is no longer in GRUB.  Then I don't care
how weird disk layouts can become, because GRUB doesn't have to probe
them.  We can even support things like this if it makes users happy:

  (hd0,bsd2,msdos1,sun1,apple4,msdos1)

-- 
Robert Millan

  "Be the change you want to see in the world" -- Gandhi



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2010-01-22 18:43                             ` Seth Goldberg
@ 2010-01-24 20:44                               ` Robert Millan
  0 siblings, 0 replies; 36+ messages in thread
From: Robert Millan @ 2010-01-24 20:44 UTC (permalink / raw)
  To: The development of GNU GRUB

On Fri, Jan 22, 2010 at 10:43:09AM -0800, Seth Goldberg wrote:
>
>   The UEFI specification specifies support for nested MSDOS labels (MSDOS 
> labels that include partitions in which another MSDOS partition table can 
> be nested).  This is not talking just about extended partitions, but  
> about the ability to arbitrarily nest MSDOS partition tables.  I can't 
> point you to a specific implementation that uses that functionality, but 
> the fact that it's specified should be enough to allow us to be flexible 
> here.  Why limit the nesting if architecturally it's not a problem to 
> support (as Vladimir's existing implementation already supports arbitrary 
> nesting).

Note that it is very easy for Intel to specify and implement that: in their
world there's only one partition label type (plus another one which is
backward compatible with the first).

-- 
Robert Millan

  "Be the change you want to see in the world" -- Gandhi



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2010-01-24 20:41                               ` Robert Millan
@ 2010-01-24 21:20                                 ` Vladimir 'φ-coder/phcoder' Serbinenko
  2010-01-25  7:23                                   ` Robert Millan
  2010-01-25  0:38                                 ` Bruce Dubbs
  2010-01-25  8:25                                 ` Grégoire Sutre
  2 siblings, 1 reply; 36+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2010-01-24 21:20 UTC (permalink / raw)
  To: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 4260 bytes --]

Robert Millan wrote:
> On Fri, Jan 22, 2010 at 07:03:21PM +0100, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>   
>>> This can be done by extending "has_partitions" to be set to "yes" in those
>>> specific partition types.  The implementation should be the least intrusive
>>> possible, taking into account that this kind of situations are an oddity
>>> rather than the norm.
>>>
>>>   
>>>       
>> Partition types are easily screwed. Why not just check for the presence
>> of the label?
>>     
>
> I have a feeling I already explained this somewhere.  Doesn't seem to be in
> this thread, maybe on IRC?  Anyway, it won't hurt to ellaborate on it...
>
> First of all, the whole label type proliferation problem is inherently
> impossible to resolve by technical means.  Labels overlap each other,
> they can coexist without any garantee that the user expects them to be
> there at all or include meaningful data.
>
> You *can't* reliably check for any partition label.  Partitions include a
> set of arbitrary data.  Sometimes they will match one of the probes,
> sometimes more than one.  GRUB has no way of determining if any of those
> matches is correct, because only the *user* knows that.
>
> This is a problem we already have, but it is bearable because worst case is
> detecting a label where there isn't supposed to be one, or detecting a label
> type different than the one user expected.  With this proposal, two things
> happen:
>
>   - has_partitions stops being useful.  When in top level, it's relatively
>     easy to make assumptions about the existance of partitions.  If it is
>     a hard disk, chances are it'll be partitioned;  If it's a CDROM, chances
>     are it isn't (this is an unreliable check, but its purpose is to paliate
>     the effect of using another unreliable check, so overall it's a gain).
>   
I don't see any illness-effects caused by misdetection.
>   - False positives can be repeated ad nauseam.  It can even be exploited to
>     force GRUB into reading several GiBs of data, effectively DoSing it.
>
>   
You don't need nested partitions for that. You can make multi-GiB with
just a single-level GPT, acorn, apple or even msdos (by defining
extended label in every sector). Same goes for filesystems: you can make
a huge fat root directory and put volume pseudo-file at the end of
directory in a way to make *_label inefficient.And if an attacker has
access to local disks why not he just replaces grub with hacked version?
> If you look around, all approaches at dealing with this imply appliing enough
> limit to keep it sane.  For example, they limit the number of label types, the
> recursion depth, etc.
>   
Often limits are result of static resource allocation.
> If we're going to support *all* possible combinations, I'd rather revisit
> and solve our detection problem first.  Not by actually making detection
> reliable (that's impossible), but by stop pretending GRUB can hide this mess
> from the user.  When GRUB performs guesswork, sooner or later it'll get it
> wrong anyway, and the fact that it was guessing creates a false expectation
> that it somehow knows the correct result.  Users end up blaming GRUB for that.
>
> So instead of supporting things like:
>
>   (hd0,1)
>   (hd0,2)
>
>   (ambigous; what does this mean in an hybrid MSDOS/GPT ?  What about other
>   hybrid schemes?  GRUB can't tell!)
>
> ... we could support:
>
>   (hd0,msdos1)
>   (hd0,gpt1)
>   (hd0,msdos2)
>   (hd0,gpt2)
>
> whose meaning is pretty clear.  Then the user can nest as much as they like,
> but they will also have to deal with the problem of identifiing the labels.
>
>   
I like this idea. It also improves some other cases like hybrid GPT.
> Minix: (hd0,msdos1,msdos1)
>
> Solaris: (hd0,msdos2,sun1)
>
> *BSD: (hd0,msdos3,bsd1)
>
> With this approach, the burden is no longer in GRUB.  Then I don't care
> how weird disk layouts can become, because GRUB doesn't have to probe
> them.  
We still have to for partition_iterate.
> We can even support things like this if it makes users happy:
>
>   (hd0,bsd2,msdos1,sun1,apple4,msdos1)
>
>   


-- 
Regards
Vladimir 'φ-coder/phcoder' Serbinenko



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 293 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2010-01-24 20:41                               ` Robert Millan
  2010-01-24 21:20                                 ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2010-01-25  0:38                                 ` Bruce Dubbs
  2010-01-25  4:56                                   ` Michal Suchanek
  2010-01-25  7:31                                   ` Robert Millan
  2010-01-25  8:25                                 ` Grégoire Sutre
  2 siblings, 2 replies; 36+ messages in thread
From: Bruce Dubbs @ 2010-01-25  0:38 UTC (permalink / raw)
  To: The development of GNU GRUB

Robert Millan wrote:
> On Fri, Jan 22, 2010 at 07:03:21PM +0100, Vladimir 'φ-coder/phcoder' Serbinenko wrote:

>> Partition types are easily screwed. Why not just check for the presence
>> of the label?
> 
> I have a feeling I already explained this somewhere.  Doesn't seem to be in
> this thread, maybe on IRC?  Anyway, it won't hurt to ellaborate on it...
> 
> First of all, the whole label type proliferation problem is inherently
> impossible to resolve by technical means.  Labels overlap each other,
> they can coexist without any garantee that the user expects them to be
> there at all or include meaningful data.

There is a fairly long thread at util-linux-ng that discusses this 
problem in the context of very slow and very small devices.  It starts 
approximately at

http://marc.info/?l=util-linux-ng&m=126353611105795&w=2

The ultimate solution was to not search for multiple partition type 
signatures on small devices.

> You *can't* reliably check for any partition label.  

...

> So instead of supporting things like:
> 
>   (hd0,1)
>   (hd0,2)
> 
>   (ambigous; what does this mean in an hybrid MSDOS/GPT ?  What about other
>   hybrid schemes?  GRUB can't tell!)
> 
> ... we could support:
> 
>   (hd0,msdos1)
>   (hd0,gpt1)
>   (hd0,msdos2)
>   (hd0,gpt2)
> 
> whose meaning is pretty clear.  Then the user can nest as much as they like,
> but they will also have to deal with the problem of identifiing the labels.

I like this idea, but wonder if it would be useful to have something 
like (grub drive, partition type, filesystem type) for each partition to 
consider.  For example:

(hd0,gpt1,ext2)

> Minix: (hd0,msdos1,msdos1)
> 
> Solaris: (hd0,msdos2,sun1)
> 
> *BSD: (hd0,msdos3,bsd1)

> With this approach, the burden is no longer in GRUB.  Then I don't care
> how weird disk layouts can become, because GRUB doesn't have to probe
> them.  We can even support things like this if it makes users happy:
> 
>   (hd0,bsd2,msdos1,sun1,apple4,msdos1)

Can you translate that.  I don't understand.

   -- Bruce




^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2010-01-25  0:38                                 ` Bruce Dubbs
@ 2010-01-25  4:56                                   ` Michal Suchanek
  2010-01-25  7:31                                   ` Robert Millan
  1 sibling, 0 replies; 36+ messages in thread
From: Michal Suchanek @ 2010-01-25  4:56 UTC (permalink / raw)
  To: The development of GNU GRUB

2010/1/25 Bruce Dubbs <bruce.dubbs@gmail.com>:
> Robert Millan wrote:
>>
>> On Fri, Jan 22, 2010 at 07:03:21PM +0100, Vladimir 'φ-coder/phcoder'

>> With this approach, the burden is no longer in GRUB.  Then I don't care
>> how weird disk layouts can become, because GRUB doesn't have to probe
>> them.  We can even support things like this if it makes users happy:
>>
>>  (hd0,bsd2,msdos1,sun1,apple4,msdos1)
>
> Can you translate that.  I don't understand.

It's pretty obvious. It's the first msdos partition inside the fourth
apple partition inside the first sun partition inside the first msdos
partition inside second bsd slice of the first harddisk.

Thanks

Michal



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2010-01-24 21:20                                 ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2010-01-25  7:23                                   ` Robert Millan
  0 siblings, 0 replies; 36+ messages in thread
From: Robert Millan @ 2010-01-25  7:23 UTC (permalink / raw)
  To: The development of GNU GRUB

On Sun, Jan 24, 2010 at 10:20:49PM +0100, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> > With this approach, the burden is no longer in GRUB.  Then I don't care
> > how weird disk layouts can become, because GRUB doesn't have to probe
> > them.  
> We still have to for partition_iterate.

partition_iterate itself is no problem.  I mean, even probing itself isn't,
as long as we don't promise that any of it actually works.  Accessing unknown
partition label as "hd0,1" implies we know the label type via probing;  other
facilities that use probing don't necessarily imply that.  For example, GRUB
could do:

  grub> ls (hd0)
  Possible msdos label: 1 2 3
  Possible gpt label: 1 2

etc.

-- 
Robert Millan

  "Be the change you want to see in the world" -- Gandhi



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2010-01-25  0:38                                 ` Bruce Dubbs
  2010-01-25  4:56                                   ` Michal Suchanek
@ 2010-01-25  7:31                                   ` Robert Millan
  2010-01-25  7:52                                     ` Robert Millan
  1 sibling, 1 reply; 36+ messages in thread
From: Robert Millan @ 2010-01-25  7:31 UTC (permalink / raw)
  To: The development of GNU GRUB

On Sun, Jan 24, 2010 at 06:38:40PM -0600, Bruce Dubbs wrote:
> I like this idea, but wonder if it would be useful to have something  
> like (grub drive, partition type, filesystem type) for each partition to  
> consider.  For example:
>
> (hd0,gpt1,ext2)

Filesystems have essentially the same problem, but collision is much less
likely, and "nested filesystems" are already handled like an oddity (via
loop command) for which responsibility is left to the user.

>> With this approach, the burden is no longer in GRUB.  Then I don't care
>> how weird disk layouts can become, because GRUB doesn't have to probe
>> them.  We can even support things like this if it makes users happy:
>>
>>   (hd0,bsd2,msdos1,sun1,apple4,msdos1)
>
> Can you translate that.  I don't understand.

When you hide complexity from the user, the user doesn't generally care or
want to understand what this involves.  When we accept "(hd0,1)" from the
user, it implies we know what's the partition label in hd0, but reality is
that we're just guessing.  User, however, will expect things to "just work",
and if they fail will blame it on GRUB.  This is what I refer to when I
speak of burden.

-- 
Robert Millan

  "Be the change you want to see in the world" -- Gandhi



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2010-01-25  7:31                                   ` Robert Millan
@ 2010-01-25  7:52                                     ` Robert Millan
  0 siblings, 0 replies; 36+ messages in thread
From: Robert Millan @ 2010-01-25  7:52 UTC (permalink / raw)
  To: The development of GNU GRUB

On Mon, Jan 25, 2010 at 08:31:35AM +0100, Robert Millan wrote:
> When you hide complexity from the user, the user doesn't generally care or
> want to understand what this involves.  When we accept "(hd0,1)" from the
> user, it implies we know what's the partition label in hd0, but reality is
> that we're just guessing.  User, however, will expect things to "just work",
> and if they fail will blame it on GRUB.  This is what I refer to when I
> speak of burden.

Btw, I forgot to mention that initially GRUB took a very different approach:
labels were considered arch-specific, so on i386-pc you only had msdos labels,
on powerpc-ieee1275 you only had apple labels, etc.  With this approach, the
probing problem doesn't exist.

-- 
Robert Millan

  "Be the change you want to see in the world" -- Gandhi



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] nested partitions
  2010-01-24 20:41                               ` Robert Millan
  2010-01-24 21:20                                 ` Vladimir 'φ-coder/phcoder' Serbinenko
  2010-01-25  0:38                                 ` Bruce Dubbs
@ 2010-01-25  8:25                                 ` Grégoire Sutre
  2 siblings, 0 replies; 36+ messages in thread
From: Grégoire Sutre @ 2010-01-25  8:25 UTC (permalink / raw)
  To: The development of GNU GRUB

Robert Millan wrote:

> With this approach, the burden is no longer in GRUB.  Then I don't care
> how weird disk layouts can become, because GRUB doesn't have to probe
> them.  We can even support things like this if it makes users happy:
> 
>   (hd0,bsd2,msdos1,sun1,apple4,msdos1)

I like this generic approach very much.  And as you said, in 
non-straightforward disk layouts, the responsibility of finding the 
appropriate path to access a given partition is left to the user.

In all generality, the links between labels is a graph, for instance in 
your example above, the two occurrences of msdos1 could be the same 
partition.  How does the probing code work regarding this?  Does 
partition_iterate terminate if the graph has cycles?

Grégoire



^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2010-01-25  8:26 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-11 15:51 [PATCH] nested partitions Vladimir 'phcoder' Serbinenko
2009-07-16 20:52 ` Vladimir 'phcoder' Serbinenko
2009-07-31  7:58   ` Marco Gerards
2009-07-31  9:39     ` Vladimir 'phcoder' Serbinenko
2009-07-31 19:48       ` Vladimir 'phcoder' Serbinenko
2009-07-31 20:25         ` Vladimir 'phcoder' Serbinenko
2009-08-02 22:17         ` Robert Millan
2009-08-02 22:36           ` Vladimir 'phcoder' Serbinenko
2009-08-02 22:02   ` Robert Millan
2009-08-02 22:09     ` Vladimir 'phcoder' Serbinenko
2009-08-02 22:25       ` Robert Millan
2009-08-02 22:44         ` Vladimir 'phcoder' Serbinenko
2009-08-04 20:15           ` Robert Millan
2009-08-17 13:00             ` Vladimir 'phcoder' Serbinenko
2009-08-17 14:06               ` Robert Millan
2009-08-17 14:34                 ` Vladimir 'phcoder' Serbinenko
2009-08-23 22:57                   ` Vladimir 'phcoder' Serbinenko
2009-08-24 13:39                     ` Vladimir 'phcoder' Serbinenko
2009-08-25 20:14                       ` Vladimir 'phcoder' Serbinenko
2009-08-25 23:07                         ` Robert Millan
2009-08-25 23:13                           ` Vladimir 'phcoder' Serbinenko
2009-08-26  0:50                             ` Robert Millan
2009-08-25 20:35                       ` Seth Goldberg
2009-08-25 21:12                         ` Vladimir 'phcoder' Serbinenko
2010-01-22 16:53                           ` Robert Millan
2010-01-22 18:03                             ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-01-24 20:41                               ` Robert Millan
2010-01-24 21:20                                 ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-01-25  7:23                                   ` Robert Millan
2010-01-25  0:38                                 ` Bruce Dubbs
2010-01-25  4:56                                   ` Michal Suchanek
2010-01-25  7:31                                   ` Robert Millan
2010-01-25  7:52                                     ` Robert Millan
2010-01-25  8:25                                 ` Grégoire Sutre
2010-01-22 18:43                             ` Seth Goldberg
2010-01-24 20:44                               ` Robert Millan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.