⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 genhd.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  Code extracted from *  linux/kernel/hd.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 * *  Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl} */#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>#include <linux/init.h>#include <asm/system.h>#include <asm/byteorder.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>#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); \			})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);#ifdef CONFIG_BLK_DEV_DAC960extern void DAC960_Initialize(void);#endifextern int scsi_dev_init(void);extern int net_dev_init(void);#ifdef CONFIG_PPCextern void note_bootable_part(kdev_t dev, int part);#endifstatic char *raid_name (struct gendisk *hd, int minor, int major_base,                        char *buf){        int ctlr = hd->major - major_base;        int disk = minor >> hd->minor_shift;        int part = minor & (( 1 << hd->minor_shift) - 1);        if (part == 0)                sprintf(buf, "%s/c%dd%d", hd->major_name, ctlr, disk);        else                sprintf(buf, "%s/c%dd%dp%d", hd->major_name, ctlr, disk,                        part);        return buf;}/* * 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;	int unit = (minor >> hd->minor_shift) + 'a';	/*	 * 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.	 *	 * MD devices are named md0, md1, ... md15, fix it up here.	 */	switch (hd->major) {		case IDE5_MAJOR:			unit += 2;		case IDE4_MAJOR:			unit += 2;		case IDE3_MAJOR:			unit += 2;		case IDE2_MAJOR:			unit += 2;		case IDE1_MAJOR:			unit += 2;		case IDE0_MAJOR:			maj = "hd";			break;		case MD_MAJOR:			unit -= 'a'-'0';	}	part = minor & ((1 << hd->minor_shift) - 1);	if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) {		unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16;		if (unit > 'z') {			unit -= 'z' + 1;			sprintf(buf, "sd%c%c", 'a' + unit / 26, 'a' + unit % 26);			if (part)				sprintf(buf + 4, "%d", part);			return buf;		}	}	if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <=            COMPAQ_SMART2_MAJOR+7) {          return raid_name (hd, minor, COMPAQ_SMART2_MAJOR, buf); 	}	if (hd->major >= DAC960_MAJOR && hd->major <= DAC960_MAJOR+7) {          return raid_name (hd, minor, DAC960_MAJOR, buf); 	}	if (part)		sprintf(buf, "%s%c%d", maj, unit, part);	else		sprintf(buf, "%s%c", maj, unit);	return buf;}static void add_partition (struct gendisk *hd, int minor,					int start, int size, int type){	char buf[MAX_DISKNAME_LEN];	struct hd_struct *p = hd->part+minor;	p->start_sect = start;	p->nr_sects = size;	p->type = type;	printk(" %s", disk_name(hd, minor, buf));}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);}static int sector_partition_scale(kdev_t dev){       if (hardsect_size[MAJOR(dev)] != NULL)               return (hardsect_size[MAJOR(dev)][MINOR(dev)]/512);       else               return (1);}static unsigned int get_ptable_blocksize(kdev_t dev){	int ret = 1024;	/*	 * See whether the low-level driver has given us a minumum blocksize.	 * If so, check to see whether it is larger than the default of 1024.	 */	if (!blksize_size[MAJOR(dev)])		return ret;	/*	 * Check for certain special power of two sizes that we allow.	 * With anything larger than 1024, we must force the blocksize up to	 * the natural blocksize for the device so that we don't have to try	 * and read partial sectors.  Anything smaller should be just fine.	 */	switch( blksize_size[MAJOR(dev)][MINOR(dev)] ) {	case 2048:		ret = 2048;		break;	case 4096:		ret = 4096;		break;	case 8192:		ret = 8192;		break;	case 1024:	case 512:	case 256:	case 0:		/*		 * These are all OK.		 */		break;	default:		panic("Strange blocksize for partition table\n");	}	return ret;}#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. */#define MSDOS_LABEL_MAGIC		0xAA55static 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 sector_size = sector_partition_scale(dev);	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,get_ptable_blocksize(dev))))			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)) != cpu_to_le16(MSDOS_LABEL_MAGIC))			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)*sector_size, 				      NR_SECTS(p)*sector_size, ptype(SYS_IND(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) * sector_size; /* JSt */		hd->part[current_minor].start_sect = first_sector + START_SECT(p) * sector_size;		this_sector = first_sector + START_SECT(p) * sector_size;		dev = MKDEV(hd->major, current_minor);		brelse(bh);	}done:	brelse(bh);}#ifdef CONFIG_SOLARIS_X86_PARTITIONstatic voidsolaris_x86_partition(struct gendisk *hd, kdev_t dev, long offset) {	struct buffer_head *bh;	struct solaris_x86_vtoc *v;	struct solaris_x86_slice *s;	int i;	if(!(bh = bread(dev, 0, get_ptable_blocksize(dev))))		return;	v = (struct solaris_x86_vtoc *)(bh->b_data + 512);	if(v->v_sanity != SOLARIS_X86_VTOC_SANE) {		brelse(bh);		return;	}	printk(" <solaris:");	if(v->v_version != 1) {		printk("  cannot handle version %ld vtoc>", v->v_version);		brelse(bh);		return;	}	for(i=0; i<SOLARIS_X86_NUMSLICE; i++) {		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_partition starts relative to sector		 * zero of the disk.  Therefore, must add the offset		 * of the current partition */		add_partition(hd, current_minor,					s->s_start+offset, s->s_size, 0);		current_minor++;	}	brelse(bh);	printk(" >");}#endif#ifdef CONFIG_BSD_DISKLABELstatic void check_and_add_bsd_partition(struct gendisk *hd,					struct bsd_partition *bsd_p, kdev_t dev){	struct hd_struct *lin_p;		/* check relative position of partitions.  */	for (lin_p = hd->part + 1 + MINOR(dev);	     lin_p - hd->part - MINOR(dev) < current_minor; lin_p++) {			/* no relationship -> try again */		if (lin_p->start_sect + lin_p->nr_sects <= bsd_p->p_offset 			|| lin_p->start_sect >= bsd_p->p_offset + bsd_p->p_size)			continue;				/* equal -> no need to add */		if (lin_p->start_sect == bsd_p->p_offset && 			lin_p->nr_sects == bsd_p->p_size) 			return;			/* bsd living within dos partition */		if (lin_p->start_sect <= bsd_p->p_offset && lin_p->start_sect 			+ lin_p->nr_sects >= bsd_p->p_offset + bsd_p->p_size) {#ifdef DEBUG_BSD_DISKLABEL			printk("w: %d %ld+%ld,%d+%d", 				lin_p - hd->part, 				lin_p->start_sect, lin_p->nr_sects, 				bsd_p->p_offset, bsd_p->p_size);#endif			break;		}	 /* ouch: bsd and linux overlap. Don't even try for that partition */#ifdef DEBUG_BSD_DISKLABEL		printk("???: %d %ld+%ld,%d+%d",			lin_p - hd->part, lin_p->start_sect, lin_p->nr_sects,			bsd_p->p_offset, bsd_p->p_size);#endif		printk("???");		return;	} /* if the bsd partition is not currently known to linux, we end	   * up here 	   */	add_partition(hd, current_minor, bsd_p->p_offset, bsd_p->p_size, 0);	current_minor++;}/*  * 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,    int max_partitions){	struct buffer_head *bh;	struct bsd_disklabel *l;	struct bsd_partition *p;	int mask = (1 << hd->minor_shift) - 1;	if (!(bh = bread(dev,0,get_ptable_blocksize(dev))))		return;	bh->b_state = 0;	l = (struct bsd_disklabel *) (bh->b_data+512);	if (l->d_magic != BSD_DISKMAGIC) {		brelse(bh);		return;	}	if (l->d_npartitions < max_partitions)		max_partitions = l->d_npartitions;	for (p = l->d_partitions; p - l->d_partitions <  max_partitions; p++) {		if ((current_minor & mask) >= (4 + hd->max_p))			break;		if (p->p_fstype != BSD_FS_UNUSED) 			check_and_add_bsd_partition(hd, p, dev);	}	brelse(bh);}#endif#ifdef CONFIG_UNIXWARE_DISKLABEL/* * Create devices for Unixware partitions listed in a disklabel, under a * dos-like partition. See extended_partition() for more information. */static void unixware_partition(struct gendisk *hd, kdev_t dev){	struct buffer_head *bh;	struct unixware_disklabel *l;	struct unixware_slice *p;	int mask = (1 << hd->minor_shift) - 1;	if (!(bh = bread(dev, 14, get_ptable_blocksize(dev))))		return;	bh->b_state = 0;	l = (struct unixware_disklabel *) (bh->b_data+512);	if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||	    le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {		brelse(bh);		return;	}	printk(" <unixware:");	p = &l->vtoc.v_slice[1];	/* I omit the 0th slice as it is the same as whole disk. */	while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {		if ((current_minor & mask) == 0)			break;		if (p->s_label != UNIXWARE_FS_UNUSED) {			add_partition(hd, current_minor, START_SECT(p), NR_SECTS(p), 0);			current_minor++;		}		p++;	}	brelse(bh);	printk(" >");}#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;	int sector_size = sector_partition_scale(dev);#ifdef CONFIG_BSD_DISKLABEL	/* no bsd disklabel as a default */	kdev_t bsd_kdev = 0;	int bsd_maxpart = BSD_MAXPARTITIONS;#endif#ifdef CONFIG_BLK_DEV_IDE	int tested_for_xlate = 0;read_mbr:#endif	if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -