linux下SD卡mount的问题

最近发现嵌入式开发板上,有的SD卡(8G SDHC)可以mount,有的则失败(2G SD)。
仔细看log信息,发现有如下区别:
mount成功时,
mmc0: host does not support reading read-only switch. assuming write-enable.
mmc0: new high speed SDHC card at address e624
mmcblk0: mmc0:e624 SU08G 7.40 GiB
 mmcblk0: p1
mmc1: Minimum clock frequency too high for identification mode
VFS: Mounted root (yaffs2 filesystem) on device 31:3.

mount失败时,
mmc0: host does not support reading read-only switch. assuming write-enable.
mmc0: new SD card at address ff24
mmcblk0: mmc0:ff24 SU02G 1.84 GiB
 mmcblk0:
mmc1: Minimum clock frequency too high for identification mode

除了容量不一样,卡类型不一样,信息基本上一致,还有一处差异就是:
成功时多了一个p1,貌似识别到了一个分区,失败时没有发现分区信息。

于是,想在源代码中找到打印 mmcblk0: mmc0:xxxx的地方,看看什么情况导致
没有打印p1的。定位还真费了一番功夫:
    首先找到了打印"mmc0: host does not support reading read-only switch. assuming write-enable"的地方,
 drivers/mmc/core/sd.c的函数mmc_sd_init_card().
501         if (!host->ops->get_ro || host->ops->get_ro(host) < 0) {
502             printk(KERN_WARNING "%s: host does not "
503                 "support reading read-only "
504                 "switch. assuming write-enable.\n",
505                 mmc_hostname(host));

   mmc_sd_init_card()是在同文件的 mmc_attach_sd(struct mmc_host *host, u32 ocr)中调用的:
691     err = mmc_sd_init_card(host, host->ocr, NULL);
692     if (err)
693         goto err;
694
695     mmc_release_host(host);
696
697     err = mmc_add_card(host->card);
698     if (err)
699         goto remove_card;

 而drivers/mmc/core/bus.c 文件中的mmc_add_card()函数中如下代码,
253         printk(KERN_INFO "%s: new %s%s card at address %04x\n",
254             mmc_hostname(card->host),
255             mmc_card_highspeed(card) ? "high speed " : "",
256             type, card->rca);
    正是我们看到的后面的打印信息。即
 mmc0: new high speed SDHC card at address e624和
 mmc0: new SD card at address ff24
 
 接着往下看,就很难找到下面的打印在哪里输出了。
 偶然间发现,drivers/mmc/card/block.c文件中mmc_blk_probe()函数有搜索的打印输出:
614     printk(KERN_INFO "%s: %s %s %s %s\n",
615         md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
616         cap_str, md->read_only ? "(ro)" : "");
    正是这个打印输出的
 mmcblk0: mmc0:e624 SU08G 7.40 GiB 和
 mmcblk0: mmc0:ff24 SU02G 1.84 GiB
 
 本以为目标越来越近了,结果看吧:
 
  drivers/mmc/card/block.c:  函数static int mmc_blk_probe(struct mmc_card *card)
614     printk(KERN_INFO "%s: %s %s %s %s\n",
615         md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
616         cap_str, md->read_only ? "(ro)" : "");
617
618     mmc_set_drvdata(card, md);
619     add_disk(md->disk); //这个函数

  block/genhd.c: add_disk()函数中
 544     blk_register_region(disk_devt(disk), disk->minors, NULL,
 545                 exact_match, exact_lock, disk);
 546     register_disk(disk);  //这个函数
 547     blk_register_queue(disk);

  fs/partitions/check.c的register_disk()中:
526     bdev->bd_invalidated = 1;
527     err = blkdev_get(bdev, FMODE_READ);  //这个函数
528     if (err < 0)
529         goto exit;

  fs/block_dev.c 的blkdev_get()调用__blkdev_get(), 而__blkdev_get()中:
1395             if (bdev->bd_invalidated)
1396                 rescan_partitions(disk, bdev); //这个函数

  fs/partitions/check.c的rescan_partitions()中:
586     bdev->bd_invalidated = 0;
587     if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) //这个check_partition()
588         return 0;
  fs/partitions/check.c的check_partition()中:
169     disk_name(hd, 0, state->name);
170     printk(KERN_INFO " %s:", state->name);  //这里才打印 "mmcblk0:", p1在哪里输出的?
171     if (isdigit(state->name[strlen(state->name)-1]))
172         sprintf(state->name, "p");
173
174     state->limit = disk_max_parts(hd);
175     i = res = err = 0;
176     while (!res && check_part[i]) {
177         memset(&state->parts, 0, sizeof(state->parts));
178         res = check_part[i++](state);      //这里将调用到msdos_partion()
179         if (res < 0) {
180             /* We have hit an I/O error which we don't report now.
181             * But record it, and let the others do their job.
182             */
183             err = res;
184             res = 0;
185         }
186
187     }

  fs/partitions/msdos.c 中的msdos_partition()函数中:
432     /*
433      * Now that the 55aa signature is present, this is probably
434      * either the boot sector of a FAT filesystem or a DOS-type
435      * partition table. Reject this in case the boot indicator
436      * is not 0 or 0x80.
437      */
438     p = (struct partition *) (data + 0x1be);
439     for (slot = 1; slot <= 4; slot++, p++) {
440         if (p->boot_ind != 0 && p->boot_ind != 0x80) {
441             /*
442              * Even without a valid boot inidicator value
443              * its still possible this is valid FAT filesystem
444              * without a partition table.
445              */
446             fb = (struct fat_boot_sector *) data;
447             if (slot == 1 && fb->reserved && fb->fats
448                 && fat_valid_media(fb->media)) {
449                 printk("\n");
450                 put_dev_sector(sect);
451                 return 1;  //对于2G卡,从这里退出,无打印p1
452             } else {
453                 put_dev_sector(sect);
454                 return 0;
455             }
456         }
457     }

477     state->next = 5;
478     for (slot = 1 ; slot <= 4 ; slot++, p++) {
479         sector_t start = start_sect(p)*sector_size;
480         sector_t size = nr_sects(p)*sector_size;
481         if (!size)
482             continue;
483         if (is_extended_partition(p)) {
484             /*
485              * prevent someone doing mkfs or mkswap on an
486              * extended partition, but leave room for LILO
487              * FIXME: this uses one logical sector for > 512b
488              * sector, although it may not be enough/proper.
489              */
490             sector_t n = 2;
491             n = min(size, max(sector_size, n));
492             put_partition(state, slot, start, n);
493
494             printk(" <");
495             parse_extended(state, start, size);
496             printk(" >");
497             continue;
498         }
499         put_partition(state, slot, start, size);
500         if (SYS_IND(p) == LINUX_RAID_PARTITION)
501             state->parts[slot].flags = ADDPART_FLAG_RAID;
502         if (SYS_IND(p) == DM6_PARTITION)
503             printk("[DM]");
504         if (SYS_IND(p) == EZD_PARTITION)
505             printk("[EZD]");
506     }

      对于失败的2G卡,451退出,而mount成功的8G卡,在,会运行到499行,进入put_partition(),
 fs/partitions/check.h中的put_partition()函数,打印了p1,如下所示:
  
 31 static inline void
 32 put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size)
 33 {
 34     if (n < p->limit) {
 35         p->parts[n].from = from;
 36         p->parts[n].size = size;
 37         printk(" %s%d", p->name, n);  //对于正常卡打印p1
 38     }
 39 }

    原来,对于2G卡,mount 失败的原因就是该SD卡的分区表损坏。在Win7下重新格式化,也没能修复。
 在linux下查看分区情况(cat /proc/partitions),正如上面结果所说,
 2G卡(异常卡)结果如下:
----------------------------------------
major minor  #blocks  name
 ....
 179        0    1931264 mmcblk0
---------------------------------------
 8G卡(正常卡)结果如下:
----------------------------------------
major minor  #blocks  name
 ....
 179        0    1931264 mmcblk0
 179        1    1930240 mmcblk0p1
---------------------------------------
    异常卡没能找到正确的分区,所以mount失败。

    尝试在linux(Ubuntu)下用fdisk对异常卡进行分区,fdisk也提示找不到合法分区,有4个异常分区。
 删除之,重新分区(FAT16)后,发现在windows下不能识别该卡的新分区,再在Win7下重新格式化,再上
 板子上运行,竟然行了,该卡能正常工作了,执行“cat /proc/partitions”, mmcblk0p1有了。

你可能感兴趣的:(linux下SD卡mount的问题)