?? msdos.c
字號:
/* * fs/partitions/msdos.c * * Code extracted from drivers/block/genhd.c * Copyright (C) 1991-1998 Linus Torvalds * * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug * in the early extended-partition checks and added DM partitions * * Support for DiskManager v6.0x added by Mark Lord, * with information provided by OnTrack. This now works for linux fdisk * and LILO, as well as loadlin and bootln. Note that disks other than * /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1). * * More flexible handling of extended partitions - aeb, 950831 * * Check partition table on IDE disks for common CHS translations * * Re-organised Feb 1998 Russell King */#include <linux/config.h>#include <linux/fs.h>#include <linux/genhd.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/string.h>#include <linux/blk.h>#ifdef CONFIG_BLK_DEV_IDE#include <linux/ide.h> /* IDE xlate */#endif /* CONFIG_BLK_DEV_IDE */#include <asm/system.h>#include "check.h"#include "msdos.h"#if CONFIG_BLK_DEV_MDextern void md_autodetect_dev(kdev_t dev);#endif/* * Many architectures don't like unaligned accesses, which is * frequently the case with the nr_sects and start_sect partition * table entries. */#include <asm/unaligned.h>#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 = \ get_unaligned(&p->start_sect); \ le32_to_cpu(__a); \ })static inline int is_extended_partition(struct partition *p){ return (SYS_IND(p) == DOS_EXTENDED_PARTITION || SYS_IND(p) == WIN98_EXTENDED_PARTITION || SYS_IND(p) == LINUX_EXTENDED_PARTITION);}/* * partition_name() formats the short partition name into the supplied * buffer, and returns a pointer to that buffer. * Used by several partition types which makes conditional inclusion messy, * use __attribute__ ((unused)) instead. */static char __attribute__ ((unused)) *partition_name (struct gendisk *hd, int minor, char *buf){#ifdef CONFIG_DEVFS_FS sprintf(buf, "p%d", (minor & ((1 << hd->minor_shift) - 1))); return buf;#else return disk_name(hd, minor, buf);#endif}#define MSDOS_LABEL_MAGIC1 0x55#define MSDOS_LABEL_MAGIC2 0xAAstatic inline intmsdos_magic_present(unsigned char *p){ return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);}/* * Create devices for each logical partition in an extended partition. * The logical partitions form a linked list, with each entry being * a partition table with two entries. The first entry * is the real data partition (with a start relative to the partition * table start). The second is a pointer to the next logical partition * (with a start relative to the entire extended partition). * We do not create a Linux partition for the partition tables, but * only for the actual data partitions. */static void extended_partition(struct gendisk *hd, struct block_device *bdev, int minor, unsigned long first_size, int *current_minor){ struct partition *p; Sector sect; unsigned char *data; unsigned long first_sector, this_sector, this_size; int mask = (1 << hd->minor_shift) - 1; int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512; int loopct = 0; /* number of links followed without finding a data partition */ int i; this_sector = first_sector = hd->part[minor].start_sect; this_size = first_size; while (1) { if (++loopct > 100) return; if ((*current_minor & mask) == 0) return; data = read_dev_sector(bdev, this_sector, §); if (!data) return; if (!msdos_magic_present(data + 510)) goto done; p = (struct partition *) (data + 0x1be); /* * Usually, the first entry is the real data partition, * the 2nd entry is the next extended partition, or empty, * and the 3rd and 4th entries are unused. * However, DRDOS sometimes has the extended partition as * the first entry (when the data partition is empty), * and OS/2 seems to use all four entries. */ /* * First process the data partition(s) */ for (i=0; i<4; i++, p++) { unsigned long offs, size, next; if (!NR_SECTS(p) || is_extended_partition(p)) continue; /* Check the 3rd and 4th entries - these sometimes contain random garbage */ offs = START_SECT(p)*sector_size; size = NR_SECTS(p)*sector_size; next = this_sector + offs; if (i >= 2) { if (offs + size > this_size) continue; if (next < first_sector) continue; if (next + size > first_sector + first_size) continue; } add_gd_partition(hd, *current_minor, next, size);#if CONFIG_BLK_DEV_MD if (SYS_IND(p) == LINUX_RAID_PARTITION) { md_autodetect_dev(MKDEV(hd->major,*current_minor)); }#endif (*current_minor)++; loopct = 0; if ((*current_minor & mask) == 0) goto done; } /* * Next, process the (first) extended partition, if present. * (So far, there seems to be no reason to make * extended_partition() recursive and allow a tree * of extended partitions.) * It should be a link to the next logical partition. * Create a minor for this just long enough to get the next * partition table. The minor will be reused for the next * data partition. */ p -= 4; for (i=0; i<4; i++, p++) if (NR_SECTS(p) && is_extended_partition(p)) break; if (i == 4) goto done; /* nothing left to do */ this_sector = first_sector + START_SECT(p) * sector_size; this_size = NR_SECTS(p) * sector_size; minor = *current_minor; put_dev_sector(sect); }done: put_dev_sector(sect);}/* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also indicates linux swap. Be careful before believing this is Solaris. */static voidsolaris_x86_partition(struct gendisk *hd, struct block_device *bdev, int minor, int *current_minor){#ifdef CONFIG_SOLARIS_X86_PARTITION long offset = hd->part[minor].start_sect; Sector sect; struct solaris_x86_vtoc *v; struct solaris_x86_slice *s; int mask = (1 << hd->minor_shift) - 1; int i; char buf[40]; v = (struct solaris_x86_vtoc *)read_dev_sector(bdev, offset+1, §); if (!v) return; if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) { put_dev_sector(sect); return; } printk(" %s: <solaris:", partition_name(hd, minor, buf)); if (le32_to_cpu(v->v_version) != 1) { printk(" cannot handle version %d vtoc>\n", le32_to_cpu(v->v_version)); put_dev_sector(sect); return; } for (i=0; i<SOLARIS_X86_NUMSLICE; i++) { if ((*current_minor & mask) == 0) break; s = &v->v_slice[i]; if (s->s_size == 0) continue; printk(" [s%d]", i); /* solaris partitions are relative to current MS-DOS * one but add_gd_partition starts relative to sector * zero of the disk. Therefore, must add the offset * of the current partition */ add_gd_partition(hd, *current_minor, le32_to_cpu(s->s_start)+offset, le32_to_cpu(s->s_size)); (*current_minor)++; } put_dev_sector(sect); printk(" >\n");#endif}#ifdef CONFIG_BSD_DISKLABELstatic voidcheck_and_add_bsd_partition(struct gendisk *hd, struct bsd_partition *bsd_p, int baseminor, int *current_minor){ int i, bsd_start, bsd_size; bsd_start = le32_to_cpu(bsd_p->p_offset); bsd_size = le32_to_cpu(bsd_p->p_size); /* check relative position of already allocated partitions */ for (i = baseminor+1; i < *current_minor; i++) { int start = hd->part[i].start_sect; int size = hd->part[i].nr_sects; if (start+size <= bsd_start || start >= bsd_start+bsd_size) continue; /* no overlap */ if (start == bsd_start && size == bsd_size) return; /* equal -> no need to add */ if (start <= bsd_start && start+size >= bsd_start+bsd_size) { /* bsd living within dos partition */#ifdef DEBUG_BSD_DISKLABEL printk("w: %d %ld+%ld,%d+%d", i, start, size, bsd_start, bsd_size);#endif break; /* ok */ } /* ouch: bsd and linux overlap */#ifdef DEBUG_BSD_DISKLABEL printk("???: %d %ld+%ld,%d+%d", i, start, size, bsd_start, bsd_size);#endif printk("???"); return; } add_gd_partition(hd, *current_minor, bsd_start, bsd_size); (*current_minor)++;}/* * Create devices for BSD partitions listed in a disklabel, under a * dos-like partition. See extended_partition() for more information. */static void do_bsd_partition(struct gendisk *hd, struct block_device *bdev, int minor, int *current_minor, char *name, int max_partitions){ long offset = hd->part[minor].start_sect; Sector sect; struct bsd_disklabel *l; struct bsd_partition *p; int mask = (1 << hd->minor_shift) - 1; int baseminor = (minor & ~mask); char buf[40]; l = (struct bsd_disklabel *)read_dev_sector(bdev, offset+1, §); if (!l)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -