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