File: /usr/src/linux/fs/partitions/msdos.c

1     /*
2      *  fs/partitions/msdos.c
3      *
4      *  Code extracted from drivers/block/genhd.c
5      *  Copyright (C) 1991-1998  Linus Torvalds
6      *
7      *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
8      *  in the early extended-partition checks and added DM partitions
9      *
10      *  Support for DiskManager v6.0x added by Mark Lord,
11      *  with information provided by OnTrack.  This now works for linux fdisk
12      *  and LILO, as well as loadlin and bootln.  Note that disks other than
13      *  /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
14      *
15      *  More flexible handling of extended partitions - aeb, 950831
16      *
17      *  Check partition table on IDE disks for common CHS translations
18      *
19      *  Re-organised Feb 1998 Russell King
20      */
21     
22     #include <linux/config.h>
23     #include <linux/fs.h>
24     #include <linux/genhd.h>
25     #include <linux/kernel.h>
26     #include <linux/major.h>
27     #include <linux/string.h>
28     #include <linux/blk.h>
29     
30     #ifdef CONFIG_BLK_DEV_IDE
31     #include <linux/ide.h>	/* IDE xlate */
32     #endif /* CONFIG_BLK_DEV_IDE */
33     
34     #include <asm/system.h>
35     
36     #include "check.h"
37     #include "msdos.h"
38     
39     #if CONFIG_BLK_DEV_MD
40     extern void md_autodetect_dev(kdev_t dev);
41     #endif
42     
43     static int current_minor;
44     
45     /*
46      * Many architectures don't like unaligned accesses, which is
47      * frequently the case with the nr_sects and start_sect partition
48      * table entries.
49      */
50     #include <asm/unaligned.h>
51     
52     #define SYS_IND(p)	(get_unaligned(&p->sys_ind))
53     #define NR_SECTS(p)	({ __typeof__(p->nr_sects) __a =	\
54     				get_unaligned(&p->nr_sects);	\
55     				le32_to_cpu(__a); \
56     			})
57     
58     #define START_SECT(p)	({ __typeof__(p->start_sect) __a =	\
59     				get_unaligned(&p->start_sect);	\
60     				le32_to_cpu(__a); \
61     			})
62     
63     static inline int is_extended_partition(struct partition *p)
64     {
65     	return (SYS_IND(p) == DOS_EXTENDED_PARTITION ||
66     		SYS_IND(p) == WIN98_EXTENDED_PARTITION ||
67     		SYS_IND(p) == LINUX_EXTENDED_PARTITION);
68     }
69     
70     /*
71      * partition_name() formats the short partition name into the supplied
72      * buffer, and returns a pointer to that buffer.
73      * Used by several partition types which makes conditional inclusion messy,
74      * use __attribute__ ((unused)) instead.
75      */
76     static char __attribute__ ((unused))
77     	*partition_name (struct gendisk *hd, int minor, char *buf)
78     {
79     #ifdef CONFIG_DEVFS_FS
80     	sprintf(buf, "p%d", (minor & ((1 << hd->minor_shift) - 1)));
81     	return buf;
82     #else
83     	return disk_name(hd, minor, buf);
84     #endif
85     }
86     
87     #define MSDOS_LABEL_MAGIC1	0x55
88     #define MSDOS_LABEL_MAGIC2	0xAA
89     
90     static inline int
91     msdos_magic_present(unsigned char *p) {
92     	return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);
93     }
94     
95     /*
96      * Create devices for each logical partition in an extended partition.
97      * The logical partitions form a linked list, with each entry being
98      * a partition table with two entries.  The first entry
99      * is the real data partition (with a start relative to the partition
100      * table start).  The second is a pointer to the next logical partition
101      * (with a start relative to the entire extended partition).
102      * We do not create a Linux partition for the partition tables, but
103      * only for the actual data partitions.
104      */
105     
106     static void extended_partition(struct gendisk *hd, kdev_t dev)
107     {
108     	struct buffer_head *bh;
109     	struct partition *p;
110     	unsigned long first_sector, first_size, this_sector, this_size;
111     	int mask = (1 << hd->minor_shift) - 1;
112     	int sector_size = get_hardsect_size(dev) / 512;
113     	int loopct = 0;		/* number of links followed
114     				   without finding a data partition */
115     	int i;
116     
117     	first_sector = hd->part[MINOR(dev)].start_sect;
118     	first_size = hd->part[MINOR(dev)].nr_sects;
119     	this_sector = first_sector;
120     
121     	while (1) {
122     		if (++loopct > 100)
123     			return;
124     		if ((current_minor & mask) == 0)
125     			return;
126     		if (!(bh = bread(dev,0,get_ptable_blocksize(dev))))
127     			return;
128     
129     		if (!msdos_magic_present(bh->b_data + 510))
130     			goto done;
131     
132     		p = (struct partition *) (bh->b_data + 0x1be);
133     
134     		this_size = hd->part[MINOR(dev)].nr_sects;
135     
136     		/*
137     		 * Usually, the first entry is the real data partition,
138     		 * the 2nd entry is the next extended partition, or empty,
139     		 * and the 3rd and 4th entries are unused.
140     		 * However, DRDOS sometimes has the extended partition as
141     		 * the first entry (when the data partition is empty),
142     		 * and OS/2 seems to use all four entries.
143     		 */
144     
145     		/* 
146     		 * First process the data partition(s)
147     		 */
148     		for (i=0; i<4; i++, p++) {
149     			if (!NR_SECTS(p) || is_extended_partition(p))
150     				continue;
151     
152     			/* Check the 3rd and 4th entries -
153     			   these sometimes contain random garbage */
154     			if (i >= 2
155     				&& START_SECT(p) + NR_SECTS(p) > this_size
156     				&& (this_sector + START_SECT(p) < first_sector ||
157     				    this_sector + START_SECT(p) + NR_SECTS(p) >
158     				     first_sector + first_size))
159     				continue;
160     
161     			add_gd_partition(hd, current_minor,
162     					 this_sector+START_SECT(p)*sector_size,
163     					 NR_SECTS(p)*sector_size);
164     #if CONFIG_BLK_DEV_MD
165     			if (SYS_IND(p) == LINUX_RAID_PARTITION) {
166     			    md_autodetect_dev(MKDEV(hd->major,current_minor));
167     			}
168     #endif
169     
170     			current_minor++;
171     			loopct = 0;
172     			if ((current_minor & mask) == 0)
173     				goto done;
174     		}
175     		/*
176     		 * Next, process the (first) extended partition, if present.
177     		 * (So far, there seems to be no reason to make
178     		 *  extended_partition()  recursive and allow a tree
179     		 *  of extended partitions.)
180     		 * It should be a link to the next logical partition.
181     		 * Create a minor for this just long enough to get the next
182     		 * partition table.  The minor will be reused for the next
183     		 * data partition.
184     		 */
185     		p -= 4;
186     		for (i=0; i<4; i++, p++)
187     			if(NR_SECTS(p) && is_extended_partition(p))
188     				break;
189     		if (i == 4)
190     			goto done;	 /* nothing left to do */
191     
192     		hd->part[current_minor].nr_sects = NR_SECTS(p) * sector_size; /* JSt */
193     		hd->part[current_minor].start_sect = first_sector + START_SECT(p) * sector_size;
194     		this_sector = first_sector + START_SECT(p) * sector_size;
195     		dev = MKDEV(hd->major, current_minor);
196     
197     		/* Use bforget(), as we have changed the disk geometry */
198     		bforget(bh);
199     	}
200     done:
201     	bforget(bh);
202     }
203     
204     static inline struct buffer_head *
205     get_partition_table_block(struct gendisk *hd, int minor, int blocknr) {
206     	kdev_t dev = MKDEV(hd->major, minor);
207     	return bread(dev, blocknr, get_ptable_blocksize(dev));
208     }
209     
210     #ifdef CONFIG_SOLARIS_X86_PARTITION
211     
212     /* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also
213        indicates linux swap.  Be careful before believing this is Solaris. */
214     
215     static void
216     solaris_x86_partition(struct gendisk *hd, int minor) {
217     	long offset = hd->part[minor].start_sect;
218     
219     	struct buffer_head *bh;
220     	struct solaris_x86_vtoc *v;
221     	struct solaris_x86_slice *s;
222     	int mask = (1 << hd->minor_shift) - 1;
223     	int i;
224     	char buf[40];
225     
226     	if(!(bh = get_partition_table_block(hd, minor, 0)))
227     		return;
228     	v = (struct solaris_x86_vtoc *)(bh->b_data + 512);
229     	if(le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) {
230     		brelse(bh);
231     		return;
232     	}
233     	printk(" %s: <solaris:", partition_name(hd, minor, buf));
234     	if(le32_to_cpu(v->v_version) != 1) {
235     		printk("  cannot handle version %d vtoc>\n",
236     			le32_to_cpu(v->v_version));
237     		brelse(bh);
238     		return;
239     	}
240     	for(i=0; i<SOLARIS_X86_NUMSLICE; i++) {
241     		if ((current_minor & mask) == 0)
242     			break;
243     		s = &v->v_slice[i];
244     
245     		if (s->s_size == 0)
246     			continue;
247     		printk(" [s%d]", i);
248     		/* solaris partitions are relative to current MS-DOS
249     		 * one but add_gd_partition starts relative to sector
250     		 * zero of the disk.  Therefore, must add the offset
251     		 * of the current partition */
252     		add_gd_partition(hd, current_minor, le32_to_cpu(s->s_start)+offset,
253     				 le32_to_cpu(s->s_size));
254     		current_minor++;
255     	}
256     	brelse(bh);
257     	printk(" >\n");
258     }
259     #endif
260     
261     #ifdef CONFIG_BSD_DISKLABEL
262     static void
263     check_and_add_bsd_partition(struct gendisk *hd,
264     			    struct bsd_partition *bsd_p, int minor) {
265     	struct hd_struct *lin_p;
266     		/* check relative position of partitions.  */
267     	for (lin_p = hd->part + 1 + minor;
268     	     lin_p - hd->part - minor < current_minor; lin_p++) {
269     			/* no relationship -> try again */
270     		if (lin_p->start_sect + lin_p->nr_sects <= le32_to_cpu(bsd_p->p_offset) ||
271     		    lin_p->start_sect >= le32_to_cpu(bsd_p->p_offset) + le32_to_cpu(bsd_p->p_size))
272     			continue;	
273     			/* equal -> no need to add */
274     		if (lin_p->start_sect == le32_to_cpu(bsd_p->p_offset) && 
275     			lin_p->nr_sects == le32_to_cpu(bsd_p->p_size)) 
276     			return;
277     			/* bsd living within dos partition */
278     		if (lin_p->start_sect <= le32_to_cpu(bsd_p->p_offset) && lin_p->start_sect 
279     			+ lin_p->nr_sects >= le32_to_cpu(bsd_p->p_offset) + le32_to_cpu(bsd_p->p_size)) {
280     #ifdef DEBUG_BSD_DISKLABEL
281     			printk("w: %d %ld+%ld,%d+%d", 
282     				lin_p - hd->part, 
283     				lin_p->start_sect, lin_p->nr_sects, 
284     				le32_to_cpu(bsd_p->p_offset),
285     				le32_to_cpu(bsd_p->p_size));
286     #endif
287     			break;
288     		}
289     	 /* ouch: bsd and linux overlap. Don't even try for that partition */
290     #ifdef DEBUG_BSD_DISKLABEL
291     		printk("???: %d %ld+%ld,%d+%d",
292     			lin_p - hd->part, lin_p->start_sect, lin_p->nr_sects,
293     			le32_to_cpu(bsd_p->p_offset), le32_to_cpu(bsd_p->p_size));
294     #endif
295     		printk("???");
296     		return;
297     	} /* if the bsd partition is not currently known to linux, we end
298     	   * up here 
299     	   */
300     	add_gd_partition(hd, current_minor, le32_to_cpu(bsd_p->p_offset),
301     			 le32_to_cpu(bsd_p->p_size));
302     	current_minor++;
303     }
304     
305     /* 
306      * Create devices for BSD partitions listed in a disklabel, under a
307      * dos-like partition. See extended_partition() for more information.
308      */
309     static void bsd_disklabel_partition(struct gendisk *hd, int minor, int type) {
310     	struct buffer_head *bh;
311     	struct bsd_disklabel *l;
312     	struct bsd_partition *p;
313     	int max_partitions;
314     	int mask = (1 << hd->minor_shift) - 1;
315     	char buf[40];
316     
317     	if (!(bh = get_partition_table_block(hd, minor, 0)))
318     		return;
319     	l = (struct bsd_disklabel *) (bh->b_data+512);
320     	if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) {
321     		brelse(bh);
322     		return;
323     	}
324     	printk(" %s:", partition_name(hd, minor, buf));
325     	printk((type == OPENBSD_PARTITION) ? " <openbsd:" :
326     	       (type == NETBSD_PARTITION) ? " <netbsd:" : " <bsd:");
327     
328     	max_partitions = ((type == OPENBSD_PARTITION) ? OPENBSD_MAXPARTITIONS
329     			                              : BSD_MAXPARTITIONS);
330     	if (le16_to_cpu(l->d_npartitions) < max_partitions)
331     		max_partitions = le16_to_cpu(l->d_npartitions);
332     	for (p = l->d_partitions; p - l->d_partitions <  max_partitions; p++) {
333     		if ((current_minor & mask) == 0)
334     			break;
335     
336     		if (p->p_fstype != BSD_FS_UNUSED) 
337     			check_and_add_bsd_partition(hd, p, minor);
338     	}
339     
340     	/* Use bforget(), as we have changed the disk setup */
341     	bforget(bh);
342     
343     	printk(" >\n");
344     }
345     #endif
346     
347     #ifdef CONFIG_UNIXWARE_DISKLABEL
348     /*
349      * Create devices for Unixware partitions listed in a disklabel, under a
350      * dos-like partition. See extended_partition() for more information.
351      */
352     static void unixware_partition(struct gendisk *hd, int minor) {
353     	struct buffer_head *bh;
354     	struct unixware_disklabel *l;
355     	struct unixware_slice *p;
356     	int mask = (1 << hd->minor_shift) - 1;
357     	char buf[40];
358     
359     	if (!(bh = get_partition_table_block(hd, minor, 14)))
360     		return;
361     	l = (struct unixware_disklabel *) (bh->b_data+512);
362     	if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
363     	    le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {
364     		brelse(bh);
365     		return;
366     	}
367     	printk(" %s: <unixware:", partition_name(hd, minor, buf));
368     	p = &l->vtoc.v_slice[1];
369     	/* I omit the 0th slice as it is the same as whole disk. */
370     	while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
371     		if ((current_minor & mask) == 0)
372     			break;
373     
374     		if (p->s_label != UNIXWARE_FS_UNUSED) {
375     			add_gd_partition(hd, current_minor, START_SECT(p),
376     					 NR_SECTS(p));
377     			current_minor++;
378     		}
379     		p++;
380     	}
381     	/* Use bforget, as we have changed the disk setup */
382     	bforget(bh);
383     	printk(" >\n");
384     }
385     #endif
386     
387     #ifdef CONFIG_MINIX_SUBPARTITION
388     /*
389      * Minix 2.0.0/2.0.2 subpartition support.
390      * Anand Krishnamurthy <anandk@wiproge.med.ge.com>
391      * Rajeev V. Pillai    <rajeevvp@yahoo.com>
392      */
393     static void minix_partition(struct gendisk *hd, int minor)
394     {
395     	struct buffer_head *bh;
396     	struct partition *p;
397     	int mask = (1 << hd->minor_shift) - 1;
398     	int i;
399     	char buf[40];
400     
401     	if (!(bh = get_partition_table_block(hd, minor, 0)))
402     		return;
403     	bh->b_state = 0;
404     
405     	p = (struct partition *)(bh->b_data + 0x1be);
406     
407     	/* The first sector of a Minix partition can have either
408     	 * a secondary MBR describing its subpartitions, or
409     	 * the normal boot sector. */
410     	if (msdos_magic_present (bh->b_data + 510) &&
411     	    SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */
412     
413     		printk(" %s: <minix:", partition_name(hd, minor, buf));
414     		for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) {
415     			if ((current_minor & mask) == 0)
416     				break;
417     			/* add each partition in use */
418     			if (SYS_IND(p) == MINIX_PARTITION) {
419     				add_gd_partition(hd, current_minor,
420     					      START_SECT(p), NR_SECTS(p));
421     				current_minor++;
422     			}
423     		}
424     		printk(" >\n");
425     	}
426     	brelse(bh);
427     }
428     #endif /* CONFIG_MINIX_SUBPARTITION */
429      
430     int msdos_partition(struct gendisk *hd, kdev_t dev,
431     		    unsigned long first_sector, int first_part_minor) {
432     	int i, minor = current_minor = first_part_minor;
433     	struct buffer_head *bh;
434     	struct partition *p;
435     	unsigned char *data;
436     	int mask = (1 << hd->minor_shift) - 1;
437     	int sector_size = get_hardsect_size(dev) / 512;
438     #ifdef CONFIG_BLK_DEV_IDE
439     	int tested_for_xlate = 0;
440     
441     read_mbr:
442     #endif /* CONFIG_BLK_DEV_IDE */
443     	if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) {
444     		if (warn_no_part) printk(" unable to read partition table\n");
445     		return -1;
446     	}
447     	data = bh->b_data;
448     #ifdef CONFIG_BLK_DEV_IDE
449     check_table:
450     #endif /* CONFIG_BLK_DEV_IDE */
451     	/* Use bforget(), because we may have changed the disk geometry */
452     	if (!msdos_magic_present(data + 510)) {
453     		bforget(bh);
454     		return 0;
455     	}
456     	p = (struct partition *) (data + 0x1be);
457     
458     #ifdef CONFIG_BLK_DEV_IDE
459     	if (!tested_for_xlate++) {	/* Do this only once per disk */
460     		/*
461     		 * Look for various forms of IDE disk geometry translation
462     		 */
463     		unsigned int sig = le16_to_cpu(*(unsigned short *)(data + 2));
464     		int heads = 0;
465     		/*
466     		 * The i386 partition handling programs very often
467     		 * make partitions end on cylinder boundaries.
468     		 * There is no need to do so, and Linux fdisk doesnt always
469     		 * do this, and Windows NT on Alpha doesnt do this either,
470     		 * but still, this helps to guess #heads.
471     		 */
472     		for (i = 0; i < 4; i++) {
473     			struct partition *q = &p[i];
474     			if (NR_SECTS(q)) {
475     				if ((q->sector & 63) == 1 &&
476     				    (q->end_sector & 63) == 63)
477     					heads = q->end_head + 1;
478     				break;
479     			}
480     		}
481     		if (SYS_IND(p) == EZD_PARTITION) {
482     			/*
483     			 * Accesses to sector 0 must go to sector 1 instead.
484     			 */
485     			if (ide_xlate_1024(dev, -1, heads, " [EZD]")) {
486     				data += 512;
487     				goto check_table;
488     			}
489     		} else if (SYS_IND(p) == DM6_PARTITION) {
490     
491     			/*
492     			 * Everything on the disk is offset by 63 sectors,
493     			 * including a "new" MBR with its own partition table.
494     			 */
495     			if (ide_xlate_1024(dev, 1, heads, " [DM6:DDO]")) {
496     				bforget(bh);
497     				goto read_mbr;	/* start over with new MBR */
498     			}
499     		} else if (sig <= 0x1ae &&
500     			   data[sig] == 0xAA && data[sig+1] == 0x55 &&
501     			   (data[sig+2] & 1)) {
502     			/* DM6 signature in MBR, courtesy of OnTrack */
503     			(void) ide_xlate_1024 (dev, 0, heads, " [DM6:MBR]");
504     		} else if (SYS_IND(p) == DM6_AUX1PARTITION ||
505     			   SYS_IND(p) == DM6_AUX3PARTITION) {
506     			/*
507     			 * DM6 on other than the first (boot) drive
508     			 */
509     			(void) ide_xlate_1024(dev, 0, heads, " [DM6:AUX]");
510     		} else {
511     			(void) ide_xlate_1024(dev, 2, heads, " [PTBL]");
512     		}
513     	}
514     #endif /* CONFIG_BLK_DEV_IDE */
515     
516     	/* Look for partitions in two passes:
517     	   First find the primary partitions, and the DOS-type extended partitions.
518     	   On the second pass look inside *BSD and Unixware and Solaris partitions. */
519     
520     	current_minor += 4;  /* first "extra" minor (for extended partitions) */
521     	for (i=1 ; i<=4 ; minor++,i++,p++) {
522     		if (!NR_SECTS(p))
523     			continue;
524     		add_gd_partition(hd, minor, first_sector+START_SECT(p)*sector_size,
525     				 NR_SECTS(p)*sector_size);
526     #if CONFIG_BLK_DEV_MD
527     		if (SYS_IND(p) == LINUX_RAID_PARTITION) {
528     			md_autodetect_dev(MKDEV(hd->major,minor));
529     		}
530     #endif
531     		if (is_extended_partition(p)) {
532     			printk(" <");
533     			/*
534     			 * If we are rereading the partition table, we need
535     			 * to set the size of the partition so that we will
536     			 * be able to bread the block containing the extended
537     			 * partition info.
538     			 */
539     			hd->sizes[minor] = hd->part[minor].nr_sects 
540     			  	>> (BLOCK_SIZE_BITS - 9);
541     			extended_partition(hd, MKDEV(hd->major, minor));
542     			printk(" >");
543     			/* prevent someone doing mkfs or mkswap on an
544     			   extended partition, but leave room for LILO */
545     			if (hd->part[minor].nr_sects > 2)
546     				hd->part[minor].nr_sects = 2;
547     		}
548     	}
549     
550     	/*
551     	 *  Check for old-style Disk Manager partition table
552     	 */
553     	if (msdos_magic_present(data + 0xfc)) {
554     		p = (struct partition *) (0x1be + data);
555     		for (i = 4 ; i < 16 ; i++, current_minor++) {
556     			p--;
557     			if ((current_minor & mask) == 0)
558     				break;
559     			if (!(START_SECT(p) && NR_SECTS(p)))
560     				continue;
561     			add_gd_partition(hd, current_minor, START_SECT(p), NR_SECTS(p));
562     		}
563     	}
564     	printk("\n");
565     
566     	/* second pass - output for each on a separate line */
567     	minor -= 4;
568     	p = (struct partition *) (0x1be + data);
569     	for (i=1 ; i<=4 ; minor++,i++,p++) {
570     		if (!NR_SECTS(p))
571     			continue;
572     #ifdef CONFIG_BSD_DISKLABEL
573     		if (SYS_IND(p) == BSD_PARTITION ||
574     		    SYS_IND(p) == NETBSD_PARTITION ||
575     		    SYS_IND(p) == OPENBSD_PARTITION)
576     			bsd_disklabel_partition(hd, minor, SYS_IND(p));
577     #endif
578     #ifdef CONFIG_MINIX_SUBPARTITION
579     		if (SYS_IND(p) == MINIX_PARTITION) {
580     			minix_partition(hd, minor);
581     		}
582     #endif
583     #ifdef CONFIG_UNIXWARE_DISKLABEL
584     		if (SYS_IND(p) == UNIXWARE_PARTITION)
585     			unixware_partition(hd, minor);
586     #endif
587     #ifdef CONFIG_SOLARIS_X86_PARTITION
588     		if(SYS_IND(p) == SOLARIS_X86_PARTITION)
589     			solaris_x86_partition(hd, minor);
590     #endif
591     	}
592     
593     	bforget(bh);
594     	return 1;
595     }
596