Commit 4966a3c5 authored by Richard Russon's avatar Richard Russon Committed by Linus Torvalds

[PATCH] New LDM Driver (Windows Dynamic Disks)

This is a complete rewrite of the LDM driver (support for Windows
Dynamic Disks).  It incorporates Al Viro's recent partition handling
tidy ups.

Details:
  LDM Driver rewritten.  More efficient.  Much smaller memory footprint.

  The old driver was little more than a stopgap.
  The new driver is a complete rewrite
  based on a much better understanding of the database
  based on much more reverse engineering
  more able to spot errors and inconsistancies
  it has a much smaller memory footprint
  no longer considered experimental
  accompanied by brief info: Documentation/ldm.txt
parent f4f65023
...@@ -118,6 +118,8 @@ kernel-parameters.txt ...@@ -118,6 +118,8 @@ kernel-parameters.txt
- summary listing of command line / boot prompt args for the kernel. - summary listing of command line / boot prompt args for the kernel.
kmod.txt kmod.txt
- info on the kernel module loader/unloader (kerneld replacement). - info on the kernel module loader/unloader (kerneld replacement).
ldm.txt
- a brief description of LDM (Windows Dynamic Disks).
locks.txt locks.txt
- info on file locking implementations, flock() vs. fcntl(), etc. - info on file locking implementations, flock() vs. fcntl(), etc.
logo.gif logo.gif
......
LDM - Logical Disk Manager (Dynamic Disks)
------------------------------------------
Overview
--------
Windows 2000 and XP use a new partitioning scheme. It is a complete
replacement for the MSDOS style partitions. It stores its information in a
1MiB journalled database at the end of the physical disk. The size of
partitions is limited only by disk space. The maximum number of partitions is
nearly 2000.
Any partitions created under the LDM are called "Dynamic Disks". There are no
longer any primary or extended partitions. Normal MSDOS style partitions are
now known as Basic Disks.
If you wish to use Spanned, Striped, Mirrored or RAID 5 Volumes, you must use
Dynamic Disks. The journalling allows Windows to make changes to these
partitions and filesystems without the need to reboot.
Once the LDM driver has divided up the disk, you can use the MD driver to
assemble any multi-partition volumes, e.g. Stripes, RAID5.
To prevent legacy applications from repartitioning the disk, the LDM creates a
dummy MSDOS partition containing one disk-sized partition.
Example
-------
Below we have a 50MiB disk, divided into seven partitions.
N.B. The missing 1MiB at the end of the disk is where the LDM database is
stored.
Device | Offset Bytes Sectors MiB | Size Bytes Sectors MiB
-------+----------------------------+---------------------------
hda | 0 0 0 | 52428800 102400 50
hda1 | 51380224 100352 49 | 1048576 2048 1
hda2 | 16384 32 0 | 6979584 13632 6
hda3 | 6995968 13664 6 | 10485760 20480 10
hda4 | 17481728 34144 16 | 4194304 8192 4
hda5 | 21676032 42336 20 | 5242880 10240 5
hda6 | 26918912 52576 25 | 10485760 20480 10
hda7 | 37404672 73056 35 | 13959168 27264 13
The LDM Database may not store the partitions in the order that they appear on
disk, but the driver will sort them.
When Linux boots, you will see something like:
hda: 102400 sectors w/32KiB Cache, CHS=50/64/32
hda: [LDM] hda1 hda2 hda3 hda4 hda5 hda6 hda7
Compiling LDM Support
---------------------
To enable LDM, choose the following two options:
"Advanced partition selection" CONFIG_PARTITION_ADVANCED
"Windows Logical Disk Manager (Dynamic Disk) support" CONFIG_LDM_PARTITION
If you believe the driver isn't working as it should, you can enable the extra
debugging code. This will produce a LOT of output. The option is:
"Windows LDM extra logging" CONFIG_LDM_DEBUG
N.B. The partition code cannot be compiled as a module.
As with all the partition code, if the driver doesn't see signs of its type of
partition, it will pass control to another driver, so there is no harm in
enabling it.
If you have Dynamic Disks but don't enable the driver, then all you will see
is a dummy MSDOS partition filling the whole disk. You won't be able to mount
any of the volumes on the disk.
Booting
-------
If you enable LDM support, then lilo is capable of booting from any of the
discovered partitions. However, grub does not understand the LDM partitioning
and cannot boot from a Dynamic Disk.
More Documentation
------------------
There is an Overview of the LDM online together with complete Technical
Documentation. It can also be downloaded in html.
http://linux-ntfs.sourceforge.net/ldm/index.html
http://linux-ntfs.sourceforge.net/downloads.html
If you have any LDM questions that aren't answered on the website, email me.
Cheers,
FlatCap - Richard Russon
ldm@flatcap.org
...@@ -46,15 +46,14 @@ CONFIG_LDM_PARTITION ...@@ -46,15 +46,14 @@ CONFIG_LDM_PARTITION
Windows 2000 introduced the concept of Dynamic Disks to get around Windows 2000 introduced the concept of Dynamic Disks to get around
the limitations of the PC's partitioning scheme. The Logical Disk the limitations of the PC's partitioning scheme. The Logical Disk
Manager allows the user to repartion a disk and create spanned, Manager allows the user to repartition a disk and create spanned,
mirrored, striped or RAID volumes, all without the need for mirrored, striped or RAID volumes, all without the need for
rebooting. rebooting.
Normal partitions are now called Basic Disks under Windows 2000 and Normal partitions are now called Basic Disks under Windows 2000 and
XP. XP.
Technical documentation to accompany this driver is available from: For a fuller description read <file:Documentation/ldm.txt>.
<http://linux-ntfs.sf.net/ldm/>.
If unsure, say N. If unsure, say N.
......
...@@ -25,7 +25,7 @@ if [ "$CONFIG_PARTITION_ADVANCED" = "y" ]; then ...@@ -25,7 +25,7 @@ if [ "$CONFIG_PARTITION_ADVANCED" = "y" ]; then
bool ' Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION bool ' Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION
bool ' Unixware slices support' CONFIG_UNIXWARE_DISKLABEL bool ' Unixware slices support' CONFIG_UNIXWARE_DISKLABEL
fi fi
dep_bool ' Windows Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL)' CONFIG_LDM_PARTITION $CONFIG_EXPERIMENTAL dep_bool ' Windows Logical Disk Manager (Dynamic Disk) support' CONFIG_LDM_PARTITION
if [ "$CONFIG_LDM_PARTITION" = "y" ]; then if [ "$CONFIG_LDM_PARTITION" = "y" ]; then
bool ' Windows LDM extra logging' CONFIG_LDM_DEBUG bool ' Windows LDM extra logging' CONFIG_LDM_DEBUG
fi fi
......
This diff is collapsed.
#ifndef _FS_PT_LDM_H_ /**
#define _FS_PT_LDM_H_
/*
* ldm - Part of the Linux-NTFS project. * ldm - Part of the Linux-NTFS project.
* *
* Copyright (C) 2001 Richard Russon <ldm@flatcap.org> * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
* Copyright (C) 2001 Anton Altaparmakov * Copyright (C) 2001 Anton Altaparmakov <aia21@cantab.net>
* Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
* *
* Documentation is available at http://linux-ntfs.sf.net/ldm * Documentation is available at http://linux-ntfs.sf.net/ldm
* *
...@@ -23,16 +22,18 @@ ...@@ -23,16 +22,18 @@
* in the file COPYING); if not, write to the Free Software Foundation, * in the file COPYING); if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#ifndef _FS_PT_LDM_H_
#define _FS_PT_LDM_H_
#include <linux/types.h> #include <linux/types.h>
#include <linux/list.h>
#include <linux/genhd.h>
#include <linux/fs.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <linux/genhd.h>
/* Borrowed from kernel.h. */ struct parsed_partitions;
#define LDM_PREFIX "LDM: " /* Prefix our error messages with this. */
#define LDM_CRIT KERN_CRIT LDM_PREFIX /* critical conditions */
#define LDM_ERR KERN_ERR LDM_PREFIX /* error conditions */
#define LDM_DEBUG KERN_DEBUG LDM_PREFIX /* debug-level messages */
/* Magic numbers in CPU format. */ /* Magic numbers in CPU format. */
#define MAGIC_VMDB 0x564D4442 /* VMDB */ #define MAGIC_VMDB 0x564D4442 /* VMDB */
...@@ -41,41 +42,58 @@ ...@@ -41,41 +42,58 @@
#define MAGIC_TOCBLOCK 0x544F43424C4F434B /* TOCBLOCK */ #define MAGIC_TOCBLOCK 0x544F43424C4F434B /* TOCBLOCK */
/* The defined vblk types. */ /* The defined vblk types. */
#define VBLK_COMP 0x32 /* Component */ #define VBLK_VOL5 0x51 /* Volume, version 5 */
#define VBLK_PART 0x33 /* Partition */ #define VBLK_CMP3 0x32 /* Component, version 3 */
#define VBLK_DSK1 0x34 /* Disk */ #define VBLK_PRT3 0x33 /* Partition, version 3 */
#define VBLK_DSK2 0x44 /* Disk */ #define VBLK_DSK3 0x34 /* Disk, version 3 */
#define VBLK_DGR1 0x35 /* Disk Group */ #define VBLK_DSK4 0x44 /* Disk, version 4 */
#define VBLK_DGR2 0x45 /* Disk Group */ #define VBLK_DGR3 0x35 /* Disk Group, version 3 */
#define VBLK_VOLU 0x51 /* Volume */ #define VBLK_DGR4 0x45 /* Disk Group, version 4 */
/* vblk flags indicating extra information will be present */
#define VBLK_FLAG_COMP_STRIPE 0x10
#define VBLK_FLAG_PART_INDEX 0x08
#define VBLK_FLAG_DGR3_IDS 0x08
#define VBLK_FLAG_DGR4_IDS 0x08
#define VBLK_FLAG_VOLU_ID1 0x08
#define VBLK_FLAG_VOLU_ID2 0x20
#define VBLK_FLAG_VOLU_SIZE 0x80
#define VBLK_FLAG_VOLU_DRIVE 0x02
/* size of a vblk's static parts */
#define VBLK_SIZE_HEAD 16
#define VBLK_SIZE_CMP3 22 /* Name and version */
#define VBLK_SIZE_DGR3 12
#define VBLK_SIZE_DGR4 44
#define VBLK_SIZE_DSK3 12
#define VBLK_SIZE_DSK4 45
#define VBLK_SIZE_PRT3 28
#define VBLK_SIZE_VOL5 59
/* component types */
#define COMP_STRIPE 0x01 /* Stripe-set */
#define COMP_BASIC 0x02 /* Basic disk */
#define COMP_RAID 0x03 /* Raid-set */
/* Other constants. */ /* Other constants. */
#define LDM_BLOCKSIZE 1024 /* Size of block in bytes. */
#define LDM_DB_SIZE 2048 /* Size in sectors (= 1MiB). */ #define LDM_DB_SIZE 2048 /* Size in sectors (= 1MiB). */
#define LDM_FIRST_PART_OFFSET 4 /* Add this to first_part_minor
to get to the first data
partition device minor. */
#define OFF_PRIVHEAD1 3 /* Offset of the first privhead #define OFF_PRIV1 6 /* Offset of the first privhead
relative to the start of the relative to the start of the
device in units of device in sectors */
LDM_BLOCKSIZE. */
/* Offsets to structures within the LDM Database in units of LDM_BLOCKSIZE. */ /* Offsets to structures within the LDM Database in sectors. */
#define OFF_PRIVHEAD2 928 /* Backup private headers. */ #define OFF_PRIV2 1856 /* Backup private headers. */
#define OFF_PRIVHEAD3 1023 #define OFF_PRIV3 2047
#define OFF_TOCBLOCK1 0 /* Tables of contents. */ #define OFF_TOCB1 1 /* Tables of contents. */
#define OFF_TOCBLOCK2 1 #define OFF_TOCB2 2
#define OFF_TOCBLOCK3 1022 #define OFF_TOCB3 2045
#define OFF_TOCBLOCK4 1023 #define OFF_TOCB4 2046
#define OFF_VMDB 8 /* List of partitions. */ #define OFF_VMDB 17 /* List of partitions. */
#define OFF_VBLK 9
#define WIN2K_DYNAMIC_PARTITION 0x42 /* Formerly SFS (Landis). */ #define WIN2K_DYNAMIC_PARTITION 0x42 /* Formerly SFS (Landis). */
#define WIN2K_EXTENDED_PARTITION 0x05 /* A standard extended
partition. */
#define TOC_BITMAP1 "config" /* Names of the two defined */ #define TOC_BITMAP1 "config" /* Names of the two defined */
#define TOC_BITMAP2 "log" /* bitmaps in the TOCBLOCK. */ #define TOC_BITMAP2 "log" /* bitmaps in the TOCBLOCK. */
...@@ -85,49 +103,42 @@ ...@@ -85,49 +103,42 @@
#define BE32(x) ((u32)be32_to_cpu(get_unaligned((u32*)(x)))) #define BE32(x) ((u32)be32_to_cpu(get_unaligned((u32*)(x))))
#define BE64(x) ((u64)be64_to_cpu(get_unaligned((u64*)(x)))) #define BE64(x) ((u64)be64_to_cpu(get_unaligned((u64*)(x))))
/* Borrowed from msdos.c. */ /* Borrowed from msdos.c */
#define SYS_IND(p) (get_unaligned(&(p)->sys_ind)) #define SYS_IND(p) (get_unaligned(&(p)->sys_ind))
#define NR_SECTS(p) ({ __typeof__((p)->nr_sects) __a = \
get_unaligned(&(p)->nr_sects); \
le32_to_cpu(__a); \
})
#define START_SECT(p) ({ __typeof__((p)->start_sect) __a = \ struct frag { /* VBLK Fragment handling */
get_unaligned(&(p)->start_sect);\ struct list_head list;
le32_to_cpu(__a); \ u32 group;
}) u8 num; /* Total number of records */
u8 rec; /* This is record number n */
u8 map; /* Which portions are in use */
u8 data[0];
};
/* In memory LDM database structures. */ /* In memory LDM database structures. */
#define DISK_ID_SIZE 64 /* Size in bytes. */ #define GUID_SIZE 16
struct ldmdisk {
u64 obj_id;
u8 disk_id[DISK_ID_SIZE];
};
struct privhead { /* Offsets and sizes are in sectors. */ struct privhead { /* Offsets and sizes are in sectors. */
u16 ver_major; u16 ver_major;
u16 ver_minor; u16 ver_minor;
u64 logical_disk_start; u64 logical_disk_start;
u64 logical_disk_size; u64 logical_disk_size;
u64 config_start; u64 config_start;
u64 config_size; u64 config_size;
u8 disk_id[DISK_ID_SIZE]; u8 disk_id[GUID_SIZE];
}; };
struct tocblock { /* We have exactly two bitmaps. */ struct tocblock { /* We have exactly two bitmaps. */
u8 bitmap1_name[16]; u8 bitmap1_name[16];
u64 bitmap1_start; u64 bitmap1_start;
u64 bitmap1_size; u64 bitmap1_size;
/*u64 bitmap1_flags;*/
u8 bitmap2_name[16]; u8 bitmap2_name[16];
u64 bitmap2_start; u64 bitmap2_start;
u64 bitmap2_size; u64 bitmap2_size;
/*u64 bitmap2_flags;*/
}; };
struct vmdb { struct vmdb { /* VMDB: The database header */
u16 ver_major; u16 ver_major;
u16 ver_minor; u16 ver_minor;
u32 vblk_size; u32 vblk_size;
...@@ -135,22 +146,75 @@ struct vmdb { ...@@ -135,22 +146,75 @@ struct vmdb {
u32 last_vblk_seq; u32 last_vblk_seq;
}; };
struct vblk { struct vblk_comp { /* VBLK Component */
u8 state[16];
u64 parent_id;
u8 type;
u8 children;
u16 chunksize;
};
struct vblk_dgrp { /* VBLK Disk Group */
u8 disk_id[64];
};
struct vblk_disk { /* VBLK Disk */
u8 disk_id[GUID_SIZE];
u8 alt_name[128];
};
struct vblk_part { /* VBLK Partition */
u64 start;
u64 size; /* start, size and vol_off in sectors */
u64 volume_offset;
u64 parent_id;
u64 disk_id;
u8 partnum;
};
struct vblk_volu { /* VBLK Volume */
u8 volume_type[16];
u8 volume_state[16];
u8 guid[16];
u8 drive_hint[4];
u64 size;
u8 partition_type;
};
struct vblk_head { /* VBLK standard header */
u32 group;
u16 rec;
u16 nrec;
};
struct vblk { /* Generalised VBLK */
u8 name[64]; u8 name[64];
u8 vblk_type;
u64 obj_id; u64 obj_id;
u64 disk_id; u32 sequence;
u64 start_sector; u8 flags;
u64 num_sectors; u8 type;
union {
struct vblk_comp comp;
struct vblk_dgrp dgrp;
struct vblk_disk disk;
struct vblk_part part;
struct vblk_volu volu;
} vblk;
struct list_head list;
}; };
struct ldm_part { struct ldmdb { /* Cache of the database */
struct list_head part_list; struct privhead ph;
unsigned long start; struct tocblock toc;
unsigned long size; struct vmdb vm;
struct list_head v_dgrp;
struct list_head v_disk;
struct list_head v_volu;
struct list_head v_comp;
struct list_head v_part;
}; };
int ldm_partition(struct parsed_partitions *state, struct block_device *bdev); int ldm_partition (struct parsed_partitions *state, struct block_device *bdev);
#endif /* _FS_PT_LDM_H_ */ #endif /* _FS_PT_LDM_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment