Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 77b2555b52a894a2e39a42e43d993df875c46a6a 474 lines 13 kB view raw
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 24#include "check.h" 25#include "msdos.h" 26#include "efi.h" 27 28/* 29 * Many architectures don't like unaligned accesses, while 30 * the nr_sects and start_sect partition table entries are 31 * at a 2 (mod 4) address. 32 */ 33#include <asm/unaligned.h> 34 35#define SYS_IND(p) (get_unaligned(&p->sys_ind)) 36#define NR_SECTS(p) ({ __typeof__(p->nr_sects) __a = \ 37 get_unaligned(&p->nr_sects); \ 38 le32_to_cpu(__a); \ 39 }) 40 41#define START_SECT(p) ({ __typeof__(p->start_sect) __a = \ 42 get_unaligned(&p->start_sect); \ 43 le32_to_cpu(__a); \ 44 }) 45 46static inline int is_extended_partition(struct partition *p) 47{ 48 return (SYS_IND(p) == DOS_EXTENDED_PARTITION || 49 SYS_IND(p) == WIN98_EXTENDED_PARTITION || 50 SYS_IND(p) == LINUX_EXTENDED_PARTITION); 51} 52 53#define MSDOS_LABEL_MAGIC1 0x55 54#define MSDOS_LABEL_MAGIC2 0xAA 55 56static inline int 57msdos_magic_present(unsigned char *p) 58{ 59 return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2); 60} 61 62/* 63 * Create devices for each logical partition in an extended partition. 64 * The logical partitions form a linked list, with each entry being 65 * a partition table with two entries. The first entry 66 * is the real data partition (with a start relative to the partition 67 * table start). The second is a pointer to the next logical partition 68 * (with a start relative to the entire extended partition). 69 * We do not create a Linux partition for the partition tables, but 70 * only for the actual data partitions. 71 */ 72 73static void 74parse_extended(struct parsed_partitions *state, struct block_device *bdev, 75 u32 first_sector, u32 first_size) 76{ 77 struct partition *p; 78 Sector sect; 79 unsigned char *data; 80 u32 this_sector, this_size; 81 int sector_size = bdev_hardsect_size(bdev) / 512; 82 int loopct = 0; /* number of links followed 83 without finding a data partition */ 84 int i; 85 86 this_sector = first_sector; 87 this_size = first_size; 88 89 while (1) { 90 if (++loopct > 100) 91 return; 92 if (state->next == state->limit) 93 return; 94 data = read_dev_sector(bdev, this_sector, &sect); 95 if (!data) 96 return; 97 98 if (!msdos_magic_present(data + 510)) 99 goto done; 100 101 p = (struct partition *) (data + 0x1be); 102 103 /* 104 * Usually, the first entry is the real data partition, 105 * the 2nd entry is the next extended partition, or empty, 106 * and the 3rd and 4th entries are unused. 107 * However, DRDOS sometimes has the extended partition as 108 * the first entry (when the data partition is empty), 109 * and OS/2 seems to use all four entries. 110 */ 111 112 /* 113 * First process the data partition(s) 114 */ 115 for (i=0; i<4; i++, p++) { 116 u32 offs, size, next; 117 if (!NR_SECTS(p) || is_extended_partition(p)) 118 continue; 119 120 /* Check the 3rd and 4th entries - 121 these sometimes contain random garbage */ 122 offs = START_SECT(p)*sector_size; 123 size = NR_SECTS(p)*sector_size; 124 next = this_sector + offs; 125 if (i >= 2) { 126 if (offs + size > this_size) 127 continue; 128 if (next < first_sector) 129 continue; 130 if (next + size > first_sector + first_size) 131 continue; 132 } 133 134 put_partition(state, state->next, next, size); 135 if (SYS_IND(p) == LINUX_RAID_PARTITION) 136 state->parts[state->next].flags = 1; 137 loopct = 0; 138 if (++state->next == state->limit) 139 goto done; 140 } 141 /* 142 * Next, process the (first) extended partition, if present. 143 * (So far, there seems to be no reason to make 144 * parse_extended() recursive and allow a tree 145 * of extended partitions.) 146 * It should be a link to the next logical partition. 147 */ 148 p -= 4; 149 for (i=0; i<4; i++, p++) 150 if (NR_SECTS(p) && is_extended_partition(p)) 151 break; 152 if (i == 4) 153 goto done; /* nothing left to do */ 154 155 this_sector = first_sector + START_SECT(p) * sector_size; 156 this_size = NR_SECTS(p) * sector_size; 157 put_dev_sector(sect); 158 } 159done: 160 put_dev_sector(sect); 161} 162 163/* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also 164 indicates linux swap. Be careful before believing this is Solaris. */ 165 166static void 167parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev, 168 u32 offset, u32 size, int origin) 169{ 170#ifdef CONFIG_SOLARIS_X86_PARTITION 171 Sector sect; 172 struct solaris_x86_vtoc *v; 173 int i; 174 175 v = (struct solaris_x86_vtoc *)read_dev_sector(bdev, offset+1, &sect); 176 if (!v) 177 return; 178 if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) { 179 put_dev_sector(sect); 180 return; 181 } 182 printk(" %s%d: <solaris:", state->name, origin); 183 if (le32_to_cpu(v->v_version) != 1) { 184 printk(" cannot handle version %d vtoc>\n", 185 le32_to_cpu(v->v_version)); 186 put_dev_sector(sect); 187 return; 188 } 189 for (i=0; i<SOLARIS_X86_NUMSLICE && state->next<state->limit; i++) { 190 struct solaris_x86_slice *s = &v->v_slice[i]; 191 if (s->s_size == 0) 192 continue; 193 printk(" [s%d]", i); 194 /* solaris partitions are relative to current MS-DOS 195 * one; must add the offset of the current partition */ 196 put_partition(state, state->next++, 197 le32_to_cpu(s->s_start)+offset, 198 le32_to_cpu(s->s_size)); 199 } 200 put_dev_sector(sect); 201 printk(" >\n"); 202#endif 203} 204 205#if defined(CONFIG_BSD_DISKLABEL) 206/* 207 * Create devices for BSD partitions listed in a disklabel, under a 208 * dos-like partition. See parse_extended() for more information. 209 */ 210static void 211parse_bsd(struct parsed_partitions *state, struct block_device *bdev, 212 u32 offset, u32 size, int origin, char *flavour, 213 int max_partitions) 214{ 215 Sector sect; 216 struct bsd_disklabel *l; 217 struct bsd_partition *p; 218 219 l = (struct bsd_disklabel *)read_dev_sector(bdev, offset+1, &sect); 220 if (!l) 221 return; 222 if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) { 223 put_dev_sector(sect); 224 return; 225 } 226 printk(" %s%d: <%s:", state->name, origin, flavour); 227 228 if (le16_to_cpu(l->d_npartitions) < max_partitions) 229 max_partitions = le16_to_cpu(l->d_npartitions); 230 for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) { 231 u32 bsd_start, bsd_size; 232 233 if (state->next == state->limit) 234 break; 235 if (p->p_fstype == BSD_FS_UNUSED) 236 continue; 237 bsd_start = le32_to_cpu(p->p_offset); 238 bsd_size = le32_to_cpu(p->p_size); 239 if (offset == bsd_start && size == bsd_size) 240 /* full parent partition, we have it already */ 241 continue; 242 if (offset > bsd_start || offset+size < bsd_start+bsd_size) { 243 printk("bad subpartition - ignored\n"); 244 continue; 245 } 246 put_partition(state, state->next++, bsd_start, bsd_size); 247 } 248 put_dev_sector(sect); 249 if (le16_to_cpu(l->d_npartitions) > max_partitions) 250 printk(" (ignored %d more)", 251 le16_to_cpu(l->d_npartitions) - max_partitions); 252 printk(" >\n"); 253} 254#endif 255 256static void 257parse_freebsd(struct parsed_partitions *state, struct block_device *bdev, 258 u32 offset, u32 size, int origin) 259{ 260#ifdef CONFIG_BSD_DISKLABEL 261 parse_bsd(state, bdev, offset, size, origin, 262 "bsd", BSD_MAXPARTITIONS); 263#endif 264} 265 266static void 267parse_netbsd(struct parsed_partitions *state, struct block_device *bdev, 268 u32 offset, u32 size, int origin) 269{ 270#ifdef CONFIG_BSD_DISKLABEL 271 parse_bsd(state, bdev, offset, size, origin, 272 "netbsd", BSD_MAXPARTITIONS); 273#endif 274} 275 276static void 277parse_openbsd(struct parsed_partitions *state, struct block_device *bdev, 278 u32 offset, u32 size, int origin) 279{ 280#ifdef CONFIG_BSD_DISKLABEL 281 parse_bsd(state, bdev, offset, size, origin, 282 "openbsd", OPENBSD_MAXPARTITIONS); 283#endif 284} 285 286/* 287 * Create devices for Unixware partitions listed in a disklabel, under a 288 * dos-like partition. See parse_extended() for more information. 289 */ 290static void 291parse_unixware(struct parsed_partitions *state, struct block_device *bdev, 292 u32 offset, u32 size, int origin) 293{ 294#ifdef CONFIG_UNIXWARE_DISKLABEL 295 Sector sect; 296 struct unixware_disklabel *l; 297 struct unixware_slice *p; 298 299 l = (struct unixware_disklabel *)read_dev_sector(bdev, offset+29, &sect); 300 if (!l) 301 return; 302 if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC || 303 le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) { 304 put_dev_sector(sect); 305 return; 306 } 307 printk(" %s%d: <unixware:", state->name, origin); 308 p = &l->vtoc.v_slice[1]; 309 /* I omit the 0th slice as it is the same as whole disk. */ 310 while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) { 311 if (state->next == state->limit) 312 break; 313 314 if (p->s_label != UNIXWARE_FS_UNUSED) 315 put_partition(state, state->next++, 316 START_SECT(p), NR_SECTS(p)); 317 p++; 318 } 319 put_dev_sector(sect); 320 printk(" >\n"); 321#endif 322} 323 324/* 325 * Minix 2.0.0/2.0.2 subpartition support. 326 * Anand Krishnamurthy <anandk@wiproge.med.ge.com> 327 * Rajeev V. Pillai <rajeevvp@yahoo.com> 328 */ 329static void 330parse_minix(struct parsed_partitions *state, struct block_device *bdev, 331 u32 offset, u32 size, int origin) 332{ 333#ifdef CONFIG_MINIX_SUBPARTITION 334 Sector sect; 335 unsigned char *data; 336 struct partition *p; 337 int i; 338 339 data = read_dev_sector(bdev, offset, &sect); 340 if (!data) 341 return; 342 343 p = (struct partition *)(data + 0x1be); 344 345 /* The first sector of a Minix partition can have either 346 * a secondary MBR describing its subpartitions, or 347 * the normal boot sector. */ 348 if (msdos_magic_present (data + 510) && 349 SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */ 350 351 printk(" %s%d: <minix:", state->name, origin); 352 for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) { 353 if (state->next == state->limit) 354 break; 355 /* add each partition in use */ 356 if (SYS_IND(p) == MINIX_PARTITION) 357 put_partition(state, state->next++, 358 START_SECT(p), NR_SECTS(p)); 359 } 360 printk(" >\n"); 361 } 362 put_dev_sector(sect); 363#endif /* CONFIG_MINIX_SUBPARTITION */ 364} 365 366static struct { 367 unsigned char id; 368 void (*parse)(struct parsed_partitions *, struct block_device *, 369 u32, u32, int); 370} subtypes[] = { 371 {FREEBSD_PARTITION, parse_freebsd}, 372 {NETBSD_PARTITION, parse_netbsd}, 373 {OPENBSD_PARTITION, parse_openbsd}, 374 {MINIX_PARTITION, parse_minix}, 375 {UNIXWARE_PARTITION, parse_unixware}, 376 {SOLARIS_X86_PARTITION, parse_solaris_x86}, 377 {NEW_SOLARIS_X86_PARTITION, parse_solaris_x86}, 378 {0, NULL}, 379}; 380 381int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) 382{ 383 int sector_size = bdev_hardsect_size(bdev) / 512; 384 Sector sect; 385 unsigned char *data; 386 struct partition *p; 387 int slot; 388 389 data = read_dev_sector(bdev, 0, &sect); 390 if (!data) 391 return -1; 392 if (!msdos_magic_present(data + 510)) { 393 put_dev_sector(sect); 394 return 0; 395 } 396 397 /* 398 * Now that the 55aa signature is present, this is probably 399 * either the boot sector of a FAT filesystem or a DOS-type 400 * partition table. Reject this in case the boot indicator 401 * is not 0 or 0x80. 402 */ 403 p = (struct partition *) (data + 0x1be); 404 for (slot = 1; slot <= 4; slot++, p++) { 405 if (p->boot_ind != 0 && p->boot_ind != 0x80) { 406 put_dev_sector(sect); 407 return 0; 408 } 409 } 410 411#ifdef CONFIG_EFI_PARTITION 412 p = (struct partition *) (data + 0x1be); 413 for (slot = 1 ; slot <= 4 ; slot++, p++) { 414 /* If this is an EFI GPT disk, msdos should ignore it. */ 415 if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) { 416 put_dev_sector(sect); 417 return 0; 418 } 419 } 420#endif 421 p = (struct partition *) (data + 0x1be); 422 423 /* 424 * Look for partitions in two passes: 425 * First find the primary and DOS-type extended partitions. 426 * On the second pass look inside *BSD, Unixware and Solaris partitions. 427 */ 428 429 state->next = 5; 430 for (slot = 1 ; slot <= 4 ; slot++, p++) { 431 u32 start = START_SECT(p)*sector_size; 432 u32 size = NR_SECTS(p)*sector_size; 433 if (!size) 434 continue; 435 if (is_extended_partition(p)) { 436 /* prevent someone doing mkfs or mkswap on an 437 extended partition, but leave room for LILO */ 438 put_partition(state, slot, start, size == 1 ? 1 : 2); 439 printk(" <"); 440 parse_extended(state, bdev, start, size); 441 printk(" >"); 442 continue; 443 } 444 put_partition(state, slot, start, size); 445 if (SYS_IND(p) == LINUX_RAID_PARTITION) 446 state->parts[slot].flags = 1; 447 if (SYS_IND(p) == DM6_PARTITION) 448 printk("[DM]"); 449 if (SYS_IND(p) == EZD_PARTITION) 450 printk("[EZD]"); 451 } 452 453 printk("\n"); 454 455 /* second pass - output for each on a separate line */ 456 p = (struct partition *) (0x1be + data); 457 for (slot = 1 ; slot <= 4 ; slot++, p++) { 458 unsigned char id = SYS_IND(p); 459 int n; 460 461 if (!NR_SECTS(p)) 462 continue; 463 464 for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++) 465 ; 466 467 if (!subtypes[n].parse) 468 continue; 469 subtypes[n].parse(state, bdev, START_SECT(p)*sector_size, 470 NR_SECTS(p)*sector_size, slot); 471 } 472 put_dev_sector(sect); 473 return 1; 474}