📄 genhd.c
字号:
/* * Code extracted from * linux/kernel/hd.c * * Copyright (C) 1991, 1992 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 */#include <linux/config.h>#include <linux/fs.h>#include <linux/genhd.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/string.h>#ifdef CONFIG_BLK_DEV_INITRD#include <linux/blk.h>#endif#include <asm/system.h>/* * 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>#ifdef MACH#include <machine/spl.h>#endif#define SYS_IND(p) get_unaligned(&p->sys_ind)#define NR_SECTS(p) get_unaligned(&p->nr_sects)#define START_SECT(p) get_unaligned(&p->start_sect)struct gendisk *gendisk_head = NULL;static int current_minor = 0;extern int *blk_size[];extern void rd_load(void);extern void initrd_load(void);extern int chr_dev_init(void);extern int blk_dev_init(void);extern int scsi_dev_init(void);extern int net_dev_init(void);/* * disk_name() is used by genhd.c and md.c. * It formats the devicename of the indicated disk * into the supplied buffer, and returns a pointer * to that same buffer (for convenience). */char *disk_name (struct gendisk *hd, int minor, char *buf){ unsigned int part; const char *maj = hd->major_name;#ifdef MACH char unit = (minor >> hd->minor_shift) + '0';#else char unit = (minor >> hd->minor_shift) + 'a';#endif#ifdef CONFIG_BLK_DEV_IDE /* * IDE devices use multiple major numbers, but the drives * are named as: {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}.. * This requires special handling here. */ switch (hd->major) { case IDE3_MAJOR: unit += 2; case IDE2_MAJOR: unit += 2; case IDE1_MAJOR: unit += 2; case IDE0_MAJOR: maj = "hd"; }#endif part = minor & ((1 << hd->minor_shift) - 1); if (part)#ifdef MACH sprintf(buf, "%s%cs%d", maj, unit, part);#else sprintf(buf, "%s%c%d", maj, unit, part);#endif else sprintf(buf, "%s%c", maj, unit); return buf;}static void add_partition (struct gendisk *hd, int minor, int start, int size){ char buf[8]; hd->part[minor].start_sect = start; hd->part[minor].nr_sects = size; printk(" %s", disk_name(hd, minor, buf));}#ifdef MACHstatic int mach_minor;static voidadd_bsd_partition (struct gendisk *hd, int minor, int slice, int start, int size){ char buf[16]; hd->part[minor].start_sect = start; hd->part[minor].nr_sects = size; printk (" %s%c", disk_name (hd, mach_minor, buf), slice);}#endifstatic 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);}#ifdef CONFIG_MSDOS_PARTITION/* * 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, kdev_t dev){ struct buffer_head *bh; struct partition *p; unsigned long first_sector, first_size, this_sector, this_size; int mask = (1 << hd->minor_shift) - 1; int i; first_sector = hd->part[MINOR(dev)].start_sect; first_size = hd->part[MINOR(dev)].nr_sects; this_sector = first_sector; while (1) { if ((current_minor & mask) == 0) return; if (!(bh = bread(dev,0,1024))) return; /* * This block is from a device that we're about to stomp on. * So make sure nobody thinks this block is usable. */ bh->b_state = 0; if (*(unsigned short *) (bh->b_data+510) != 0xAA55) goto done; p = (struct partition *) (0x1BE + bh->b_data); this_size = hd->part[MINOR(dev)].nr_sects; /* * 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++) { if (!NR_SECTS(p) || is_extended_partition(p)) continue; /* Check the 3rd and 4th entries - these sometimes contain random garbage */ if (i >= 2 && START_SECT(p) + NR_SECTS(p) > this_size && (this_sector + START_SECT(p) < first_sector || this_sector + START_SECT(p) + NR_SECTS(p) > first_sector + first_size)) continue; add_partition(hd, current_minor, this_sector+START_SECT(p), NR_SECTS(p)); current_minor++; 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 */ hd->part[current_minor].nr_sects = NR_SECTS(p); hd->part[current_minor].start_sect = first_sector + START_SECT(p); this_sector = first_sector + START_SECT(p); dev = MKDEV(hd->major, current_minor); brelse(bh); }done: brelse(bh);}#ifdef CONFIG_BSD_DISKLABEL/* * Create devices for BSD partitions listed in a disklabel, under a * dos-like partition. See extended_partition() for more information. */static void bsd_disklabel_partition(struct gendisk *hd, kdev_t dev){ struct buffer_head *bh; struct bsd_disklabel *l; struct bsd_partition *p; int mask = (1 << hd->minor_shift) - 1; if (!(bh = bread(dev,0,1024))) return; bh->b_state = 0; l = (struct bsd_disklabel *) (bh->b_data+512); if (l->d_magic != BSD_DISKMAGIC) { brelse(bh); return; } p = &l->d_partitions[0]; while (p - &l->d_partitions[0] <= BSD_MAXPARTITIONS) { if ((current_minor & mask) >= (4 + hd->max_p)) break; if (p->p_fstype != BSD_FS_UNUSED) {#ifdef MACH add_bsd_partition (hd, current_minor, p - &l->d_partitions[0] + 'a', p->p_offset, p->p_size);#else add_partition(hd, current_minor, p->p_offset, p->p_size);#endif current_minor++; } p++; } brelse(bh);}#endifstatic int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector){ int i, minor = current_minor; struct buffer_head *bh; struct partition *p; unsigned char *data; int mask = (1 << hd->minor_shift) - 1;#ifdef CONFIG_BLK_DEV_IDE int tested_for_xlate = 0;read_mbr:#endif if (!(bh = bread(dev,0,1024))) { printk(" unable to read partition table\n"); return -1; } data = bh->b_data; /* In some cases we modify the geometry */ /* of the drive (below), so ensure that */ /* nobody else tries to re-use this data. */ bh->b_state = 0;#ifdef CONFIG_BLK_DEV_IDEcheck_table:#endif if (*(unsigned short *) (0x1fe + data) != 0xAA55) { brelse(bh); return 0; } p = (struct partition *) (0x1be + data);#ifdef CONFIG_BLK_DEV_IDE if (!tested_for_xlate++) { /* Do this only once per disk */ /* * Look for various forms of IDE disk geometry translation */ extern int ide_xlate_1024(kdev_t, int, const char *); unsigned int sig = *(unsigned short *)(data + 2); if (SYS_IND(p) == EZD_PARTITION) { /* * The remainder of the disk must be accessed using * a translated geometry that reduces the number of * apparent cylinders to less than 1024 if possible. * * ide_xlate_1024() will take care of the necessary * adjustments to fool fdisk/LILO and partition check. */ if (ide_xlate_1024(dev, -1, " [EZD]")) { data += 512; goto check_table; } } else if (SYS_IND(p) == DM6_PARTITION) { /* * Everything on the disk is offset by 63 sectors, * including a "new" MBR with its own partition table, * and the remainder of the disk must be accessed using * a translated geometry that reduces the number of * apparent cylinders to less than 1024 if possible. * * ide_xlate_1024() will take care of the necessary * adjustments to fool fdisk/LILO and partition check. */ if (ide_xlate_1024(dev, 1, " [DM6:DDO]")) { brelse(bh); goto read_mbr; /* start over with new MBR */ } } else if (sig <= 0x1ae && *(unsigned short *)(data + sig) == 0x55AA && (1 & *(unsigned char *)(data + sig + 2)) ) { /* * DM6 signature in MBR, courtesy of OnTrack */ (void) ide_xlate_1024 (dev, 0, " [DM6:MBR]"); } else if (SYS_IND(p) == DM6_AUX1PARTITION || SYS_IND(p) == DM6_AUX3PARTITION) { /* * DM6 on other than the first (boot) drive */ (void) ide_xlate_1024(dev, 0, " [DM6:AUX]"); } else { /* * Examine the partition table for common translations. * This is necessary for drives for situations where * the translated geometry is unavailable from the BIOS. */ for (i = 0; i < 4 ; i++) { struct partition *q = &p[i]; if (NR_SECTS(q) && (q->sector & 63) == 1 && (q->end_sector & 63) == 63) { unsigned int heads = q->end_head + 1; if (heads == 32 || heads == 64 || heads == 128 || heads == 255) { (void) ide_xlate_1024(dev, heads, " [PTBL]"); break; } } } } }#endif /* CONFIG_BLK_DEV_IDE */ current_minor += 4; /* first "extra" minor (for extended partitions) */ for (i=1 ; i<=4 ; minor++,i++,p++) { if (!NR_SECTS(p)) continue; add_partition(hd, minor, first_sector+START_SECT(p), NR_SECTS(p)); if (is_extended_partition(p)) { printk(" <"); /* * If we are rereading the partition table, we need * to set the size of the partition so that we will * be able to bread the block containing the extended * partition info. */ hd->sizes[minor] = hd->part[minor].nr_sects >> (BLOCK_SIZE_BITS - 9); extended_partition(hd, MKDEV(hd->major, minor)); printk(" >"); /* prevent someone doing mkfs or mkswap on an extended partition, but leave room for LILO */ if (hd->part[minor].nr_sects > 2) hd->part[minor].nr_sects = 2; }#ifdef CONFIG_BSD_DISKLABEL if (SYS_IND(p) == BSD_PARTITION) { printk(" <");#ifdef MACH mach_minor = minor;#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -