zoukankan      html  css  js  c++  java
  • 记一次U盘挂载无法出现uuid

    起因:客户出现一个u盘挂载后不能正确显示名字label。

    现象

    U盘插入后,目录挂载到/mnt/media_rw/public:8,0

    流程

    插上U盘看打印信息

    • blkid 信息
    /dev/block/zram0: UUID="1499340a-1634-496b-9ddb-38a8a6535458" TYPE="swap" 
    /dev/block/mmcblk0p13: LABEL="/" UUID="d3e293f6-a2d6-49d1-9a6b-b9d39184a993" TYPE="ext4" 
    /dev/block/mmcblk0p14: UUID="6f7f0cca-8d3b-4139-afeb-91ff2bb7b60e" TYPE="ext4" 
    /dev/block/mmcblk0p15: LABEL="vendor" UUID="bcfdbf10-7971-4308-941a-d9674961f0cd" TYPE="ext4" 
    /dev/block/mmcblk0p22: LABEL="ta" UUID="77ee8b5c-cbf1-4e67-859b-1bbff2017aa8" TYPE="ext4" 
    /dev/block/mmcblk0p24: UUID="19e65932-22a2-4fc2-93de-15e9a76f6547" TYPE="ext4" 
    /dev/block/sda1: UUID="64B4E1BAB4E18EBC" TYPE="ntfs" 
    

    可以看到我们新加U盘的UUID和TYPE都是正常的

    • mount信息
    /dev/block/vold/public:8,0 on /mnt/media_rw/public:8,0 type iso9660 (ro,dirsync,nosuid,nodev,noexec,relatime,utf8,uid=1023,gid=1023)
    /mnt/media_rw/public:8,0 on /mnt/runtime/default/public:8,0 type sdcardfs (rw,nosuid,nodev,noexec,noatime,fsuid=1023,fsgid=1023,gid=1015,mask=6)
    /mnt/media_rw/public:8,0 on /storage/public:8,0 type sdcardfs (rw,nosuid,nodev,noexec,noatime,fsuid=1023,fsgid=1023,gid=1015,mask=6)
    /mnt/media_rw/public:8,0 on /mnt/runtime/read/public:8,0 type sdcardfs (rw,nosuid,nodev,noexec,noatime,fsuid=1023,fsgid=1023,gid=9997,mask=23)
    /mnt/media_rw/public:8,0 on /mnt/runtime/write/public:8,0 type sdcardfs (rw,nosuid,nodev,noexec,noatime,fsuid=1023,fsgid=1023,gid=9997,mask=7)
    
    • dmesg信息
    [ 7589.270312] usb 2-1: New USB device found, idVendor=0781, idProduct=55a3
    [ 7589.270329] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
    [ 7589.270340] usb 2-1: Product: Ultra Luxe
    [ 7589.270351] usb 2-1: Manufacturer: SanDisk
    [ 7589.270363] usb 2-1: SerialNumber: 01010687dee090f0d29a7ab260abf035b88a5808637ee88e1c80bcb00545f452a214000000000000000000003e1f827e009b5400a3558107b7a74c9a
    [ 7589.273065] usb-storage 2-1:1.0: USB Mass Storage device detected
    [ 7589.277763] scsi host0: usb-storage 2-1:1.0
    [ 7590.286713] scsi 0:0:0:0: Direct-Access     SanDisk  Ultra Luxe       1.00 PQ: 0 ANSI: 6
    [ 7590.290039] sd 0:0:0:0: Attached scsi generic sg0 type 0
    [ 7590.290603] sd 0:0:0:0: [sda] 60088320 512-byte logical blocks: (30.8 GB/28.7 GiB)
    [ 7590.291664] sd 0:0:0:0: [sda] Write Protect is off
    [ 7590.291684] sd 0:0:0:0: [sda] Mode Sense: 43 00 00 00
    [ 7590.292238] sd 0:0:0:0: [sda] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
    [ 7590.314122] sda: sda1
    [ 7590.320675] sd 0:0:0:0: [sda] Attached SCSI removable disk
    [ 7590.455314] ISO 9660 Extensions: RRIP_1991A
    [ 7590.475735] sdcardfs version 2.0
    [ 7590.475742] sdcardfs: dev_name -> /mnt/media_rw/public:8,0
    [ 7590.475744] sdcardfs: options -> fsuid=1023,fsgid=1023,mask=6,userid=0,gid=1015
    [ 7590.475748] sdcardfs: mnt -> ecaddc10
    [ 7590.475796] sdcardfs: mounted on top of /mnt/media_rw/public:8,0 type iso9660
    [ 7590.476645] Remount options were mask=23,gid=9997 for vfsmnt e9e9ec10.
    [ 7590.476653] sdcardfs : options - debug:1
    [ 7590.476656] sdcardfs : options - gid:9997
    [ 7590.476658] sdcardfs : options - mask:23
    [ 7590.477475] Remount options were mask=7,gid=9997 for vfsmnt c79cf210.
    [ 7590.477483] sdcardfs : options - debug:1
    [ 7590.477486] sdcardfs : options - gid:9997
    [ 7590.477488] sdcardfs : options - mask:7
    
    

    具体流程 是先由vold 的节点/dev/block/vold/public:8,0 通过sdcardfs执行mount 到 /mnt/media_rw/public:8,0

    使用blkid 查看 /dev/block/vold/public:8,0 块设备的信息

    console:/system/bin # blkid /dev/block/vold/public:8,0                     
    /dev/block/vold/public:8,0: LABEL="PVE" TYPE="iso9660"
    

    这里出来的怎么和上面blkid的不一致呢? 所以可能是vold出现创建设备出现问题

    • 问题结果
      我们查看U盘产生的设备节点
    console:/dev/block # ls -l sd*                                                 
    brw------- 1 root root 8,   0 2020-08-20 14:12 sda
    brw------- 1 root root 8,   1 2020-08-20 14:12 sda1
    

    sda是U盘的磁盘节点
    sda1是u盘的分区节点
    分别使用blkid看设备节点信息

    console:/dev/block # blkid sda                                                 
    sda: LABEL="PVE" TYPE="iso9660" 
    console:/dev/block # blkid sda1                                                
    sda1: UUID="64B4E1BAB4E18EBC" TYPE="ntfs" 
    

    所以可以得到vold 只创建了磁盘节点的public节点,而不是像正常U盘那样创建的是分区节点的public节点
    (我不知道这样的表诉是否正确......)

    • vold 流程 android/system/vlod
      1.在插入U盘时,usb驱动会通过uevent事件NetlinkEvent通知 volumeManager
    //system/vlod/VolumeManager.cpp
    void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
        std::lock_guard<std::mutex> lock(mLock);
    
        if (mDebug) {
            LOG(VERBOSE) << "----------------";
            LOG(VERBOSE) << "handleBlockEvent with action " << (int) evt->getAction();
            evt->dump();
        }
    
        std::string eventPath(evt->findParam("DEVPATH")?evt->findParam("DEVPATH"):"");
        std::string devType(evt->findParam("DEVTYPE")?evt->findParam("DEVTYPE"):"");
    
        if (devType != "disk") return;
    
        int major = std::stoi(evt->findParam("MAJOR"));
        int minor = std::stoi(evt->findParam("MINOR"));
        dev_t device = makedev(major, minor);  //即 /dev/block/sda设备
        switch (evt->getAction()) {
        case NetlinkEvent::Action::kAdd: {
            for (const auto& source : mDiskSources) {
                if (source->matches(eventPath)) {
                    // For now, assume that MMC and virtio-blk (the latter is
                    // emulator-specific; see Disk.cpp for details) devices are SD,
                    // and that everything else is USB
                    int flags = source->getFlags();
                    if (major == kMajorBlockMmc
                        || (android::vold::IsRunningInEmulator()
                        && major >= (int) kMajorBlockExperimentalMin
                        && major <= (int) kMajorBlockExperimentalMax)) {
                        flags |= android::vold::Disk::Flags::kSd;
                    } else {
                        flags |= android::vold::Disk::Flags::kUsb;
                    }
                      //创建磁盘节点
                    auto disk = new android::vold::Disk(eventPath, device, 
                            source->getNickname(), flags);
                    handleDiskAdded(std::shared_ptr<android::vold::Disk>(disk));
                    break;
                }
            }
            break;
          ...
          ...
    }
    }
    
    1. 把device当作disk设备处理

    创建 /dev/block/vold/disk:8,0

    Disk::Disk(const std::string& eventPath, dev_t device,
            const std::string& nickname, int flags) :
            mDevice(device), mSize(-1), mNickname(nickname), mFlags(flags), mCreated(
                    false), mJustPartitioned(false) {
        mId = StringPrintf("disk:%u,%u", major(device), minor(device));
        mEventPath = eventPath;
        mSysPath = StringPrintf("/sys/%s", eventPath.c_str());
        mDevPath = StringPrintf("/dev/block/vold/%s", mId.c_str());
        CreateDeviceNode(mDevPath, mDevice);
    }
    
    status_t Disk::create() {
        CHECK(!mCreated);
        mCreated = true;
    
        auto listener = VolumeManager::Instance()->getListener();
        if (listener) listener->onDiskCreated(getId(), mFlags);
    
        bool read = true;
        
        if (read) {
            readMetadata();  
            readPartitions(); //读分区信息
        }
        return OK;
    }
    

    使用命令读分区信息sgdisk --android-dump /dev/block/vold/disk:8,0

    status_t Disk::readPartitions() {
        int maxMinors = getMaxMinors();
        if (maxMinors < 0) {
            return -ENOTSUP;
        }
    
        destroyAllVolumes();
    
        // Parse partition table
    
        std::vector<std::string> cmd; //使用命令读取分区信息 
        cmd.push_back(kSgdiskPath);
        cmd.push_back("--android-dump");
        cmd.push_back(mDevPath);
    
        std::vector<std::string> output;
        status_t res = ForkExecvp(cmd, output);
    
        if (res != OK) {
            std::string fsType;
            std::string unused;
            if (ReadMetadataUntrusted(mDevPath, &fsType, &unused, &unused) != OK) {
                LOG(WARNING) << "sgdisk failed to scan " << mDevPath;
                auto listener = VolumeManager::Instance()->getListener();
                if (listener) listener->onDiskScanned(getId());
    
                mJustPartitioned = false;
                return res;
            }
            LOG(WARNING) << "sgdisk failed to scan " << mDevPath << ", ReadMetadataUntrusted OK";
        }
    
        std::string fsType;
        std::string unused;
        if (ReadMetadataUntrusted(mDevPath, &fsType, &unused, &unused) == OK && fsType.length() > 0 && unused.length() > 0) //使用blkid读取信息,如果有type uuid 就创建 /dev/block/vold/public:8,0
        {
            LOG(WARNING) << mId << " fsType :: " << fsType << " unused :: " << unused;
            createPublicVolume(mDevice);
        }
        else
        { //否者就读取分区信息
    
        Table table = Table::kUnknown;
        bool foundParts = false;
        for (const auto& line : output) {
            auto split = android::base::Split(line, kSgdiskToken);
            auto it = split.begin();
            if (it == split.end()) continue;
    
            if (*it == "DISK") {
                ......
            } else if (*it == "PART") {
                ......
                dev_t partDevice = makedev(major(mDevice), minor(mDevice) + i); // 次设备+1 即代表/dev/block/sda*
    
                if (table == Table::kMbr) {
                    if (++it == split.end()) continue;
                    int type = 0;
                    if (!android::base::ParseInt("0x" + *it, &type)) {
                        LOG(WARNING) << "Invalid partition type " << *it;
                        continue;
                    }
    
                    switch (type) {
                        case 0x06:  // FAT16
                        case 0x07:  // HPFS/NTFS/exFAT
                        case 0x0b:  // W95 FAT32 (LBA)
                        case 0x0c:  // W95 FAT32 (LBA)
                        case 0x0e:  // W95 FAT16 (LBA)
                            createPublicVolume(partDevice); //创建vold的分区节点
                            break;
                        default:
                            createPublicVolume(partDevice);
                            break;
                    }
          ......
                } 
       ......
        return OK;
    }
    
    static status_t readMetadata(const std::string& path, std::string* fsType,
            std::string* fsUuid, std::string* fsLabel, bool untrusted) {
        ...
    
        std::vector<std::string> cmd;
        cmd.push_back(kBlkidPath);
        cmd.push_back("-c");
        cmd.push_back("/dev/null");
        cmd.push_back("-s");
        cmd.push_back("TYPE");
        cmd.push_back("-s");
        cmd.push_back("UUID");
        cmd.push_back("-s");
        cmd.push_back("LABEL");
        cmd.push_back(path);
    
        std::vector<std::string> output;
        status_t res = ForkExecvp(cmd, output, untrusted ? sBlkidUntrustedContext : sBlkidContext);
        if (res != OK) {
            LOG(WARNING) << "blkid failed to identify " << path;
            return res;
        }
    ...
    }
    

    总结

    由上面就可以知道 VolumeManager 首先会传入/dev/block/sda 设备节点当作 disk设备的参数传入。
    在disk 中每个磁盘节点都会生成 /dev/block/vold/disk8,0 的节点 ;如果该disk的vold磁盘节点由数据则不会继续读取分区节点。
    也不会生成其他分区的public节点。
    解决方法 将两者顺序调反,在sgdisk读取分区后,先创建分区vold的节点

    问题

    • makedev的工作原理?
    • vold如何通知文件系统来mount节点 ?
    • kernel usb 驱动和VolumeManager如何工作?

    本文有许多地方是自己的猜测,不对的地方请指出。

    note

    主设备号代表类型
    major(device) 查看主设备号

    static const unsigned int kMajorBlockLoop = 7;
    static const unsigned int kMajorBlockScsiA = 8;
    static const unsigned int kMajorBlockScsiB = 65;
    static const unsigned int kMajorBlockScsiC = 66;
    static const unsigned int kMajorBlockScsiD = 67;
    static const unsigned int kMajorBlockScsiE = 68;
    static const unsigned int kMajorBlockScsiF = 69;
    static const unsigned int kMajorBlockScsiG = 70;
    static const unsigned int kMajorBlockScsiH = 71;
    static const unsigned int kMajorBlockScsiI = 128;
    static const unsigned int kMajorBlockScsiJ = 129;
    static const unsigned int kMajorBlockScsiK = 130;
    static const unsigned int kMajorBlockScsiL = 131;
    static const unsigned int kMajorBlockScsiM = 132;
    static const unsigned int kMajorBlockScsiN = 133;
    static const unsigned int kMajorBlockScsiO = 134;
    static const unsigned int kMajorBlockScsiP = 135;
    static const unsigned int kMajorBlockMmc = 179;
    static const unsigned int kMajorBlockExperimentalMin = 240;
    static const unsigned int kMajorBlockExperimentalMax = 254;
    

    参考

    __Shadow:Vold工作流程分析学习

  • 相关阅读:
    hdu 1272 小希的迷宫
    hdu 1318 Palindromes
    ANR traces中内存占用情况解读
    请教会linux shell脚本的=~是什么意思?
    kernel struct definition location
    SecureCRT sysrq键设置
    sysrq
    Linux中断管理 (1)Linux中断管理机制【转】
    Linux suspend 流程介绍(2)之 freeze task
    Linux进程状态解析 之 R、S、D、T、Z、X (主要有三个状态)
  • 原文地址:https://www.cnblogs.com/rootshaw/p/13534194.html
Copyright © 2011-2022 走看看