msdos.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:17k
源码类别:

Linux/Unix编程

开发平台:

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