msdos.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:17k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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