Support emulator's virtio-blk based SD card

Currently, vold only supports MMC (for SD cards) and SCSI (for USB
drives) devices. It does not recognize any device whose major number is
not one of those used by MMC and SCSI. Unfortunately, virtio-blk is one
such device. It is used by the new Android emulator (a.k.a. qemu2,
featuring the "ranchu" virtual board) for SD card emulation.

In order to make this virtio-blk based SD card device appear in Android
and appear as an SD card (rather than a USB drive), changes have to be
made to both vold (wherever the device major number is checked) and
ranchu's storage configuration. This CL implements former.

This is a stop-gap solution for emulator in nyc.
A longer term solution in-tune with upstream kernel is in the pipes.

Updated from aosp/master version.

BUG:27431753

Change-Id: I5014edec73be7c5b565d91542464c82cbe58992c
Signed-off-by: Yu Ning <yu.ning@intel.com>
(cherry picked from commit 5b1d1c7dfa13b4dca75213581dc8351b841b76c8)
gugelfrei
Yu Ning 9 years ago committed by Prathmesh Prabhu
parent ad8e26297b
commit 942d4e830b

@ -65,6 +65,8 @@ 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;
static const char* kGptBasicData = "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7";
static const char* kGptAndroidMeta = "19A710A2-B3CA-11E4-B026-10604B889DCF";
@ -76,6 +78,33 @@ enum class Table {
kGpt,
};
static bool isVirtioBlkDevice(unsigned int major) {
/*
* The new emulator's "ranchu" virtual board no longer includes a goldfish
* MMC-based SD card device; instead, it emulates SD cards with virtio-blk,
* which has been supported by upstream kernel and QEMU for quite a while.
* Unfortunately, the virtio-blk block device driver does not use a fixed
* major number, but relies on the kernel to assign one from a specific
* range of block majors, which are allocated for "LOCAL/EXPERIMENAL USE"
* per Documentation/devices.txt. This is true even for the latest Linux
* kernel (4.4; see init() in drivers/block/virtio_blk.c).
*
* This makes it difficult for vold to detect a virtio-blk based SD card.
* The current solution checks two conditions (both must be met):
*
* a) If the running environment is the emulator;
* b) If the major number is an experimental block device major number (for
* x86/x86_64 3.10 ranchu kernels, virtio-blk always gets major number
* 253, but it is safer to match the range than just one value).
*
* Other conditions could be used, too, e.g. the hardware name should be
* "ranchu", the device's sysfs path should end with "/block/vd[d-z]", etc.
* But just having a) and b) is enough for now.
*/
return IsRunningInEmulator() && major >= kMajorBlockExperimentalMin
&& major <= kMajorBlockExperimentalMax;
}
Disk::Disk(const std::string& eventPath, dev_t device,
const std::string& nickname, int flags) :
mDevice(device), mSize(-1), mNickname(nickname), mFlags(flags), mCreated(
@ -197,7 +226,8 @@ status_t Disk::readMetadata() {
close(fd);
}
switch (major(mDevice)) {
unsigned int majorId = major(mDevice);
switch (majorId) {
case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC: case kMajorBlockScsiD:
case kMajorBlockScsiE: case kMajorBlockScsiF: case kMajorBlockScsiG: case kMajorBlockScsiH:
case kMajorBlockScsiI: case kMajorBlockScsiJ: case kMajorBlockScsiK: case kMajorBlockScsiL:
@ -231,7 +261,13 @@ status_t Disk::readMetadata() {
break;
}
default: {
LOG(WARNING) << "Unsupported block major type" << major(mDevice);
if (isVirtioBlkDevice(majorId)) {
LOG(DEBUG) << "Recognized experimental block major ID " << majorId
<< " as virtio-blk (emulator's virtual SD card device)";
mLabel = "Virtual";
break;
}
LOG(WARNING) << "Unsupported block major type " << majorId;
return -ENOTSUP;
}
}
@ -490,7 +526,8 @@ void Disk::notifyEvent(int event, const std::string& value) {
int Disk::getMaxMinors() {
// Figure out maximum partition devices supported
switch (major(mDevice)) {
unsigned int majorId = major(mDevice);
switch (majorId) {
case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC: case kMajorBlockScsiD:
case kMajorBlockScsiE: case kMajorBlockScsiF: case kMajorBlockScsiG: case kMajorBlockScsiH:
case kMajorBlockScsiI: case kMajorBlockScsiJ: case kMajorBlockScsiK: case kMajorBlockScsiL:
@ -507,9 +544,16 @@ int Disk::getMaxMinors() {
}
return atoi(tmp.c_str());
}
default: {
if (isVirtioBlkDevice(majorId)) {
// drivers/block/virtio_blk.c has "#define PART_BITS 4", so max is
// 2^4 - 1 = 15
return 15;
}
}
}
LOG(ERROR) << "Unsupported block major type " << major(mDevice);
LOG(ERROR) << "Unsupported block major type " << majorId;
return -ENOTSUP;
}

@ -664,5 +664,9 @@ ScopedDir::~ScopedDir() {
}
}
bool IsRunningInEmulator() {
return property_get_bool("ro.kernel.qemu", 0);
}
} // namespace vold
} // namespace android

@ -134,6 +134,9 @@ public:
DISALLOW_COPY_AND_ASSIGN(ScopedDir);
};
/* Checks if Android is running in QEMU */
bool IsRunningInEmulator();
} // namespace vold
} // namespace android

@ -91,6 +91,8 @@ const char *VolumeManager::LOOPDIR = "/mnt/obb";
static const char* kUserMountPath = "/mnt/user";
static const unsigned int kMajorBlockMmc = 179;
static const unsigned int kMajorBlockExperimentalMin = 240;
static const unsigned int kMajorBlockExperimentalMax = 254;
/* writes superblock at end of file or device given by name */
static int writeSuperBlock(const char* name, struct asec_superblock *sb, unsigned int numImgSectors) {
@ -296,10 +298,14 @@ void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
case NetlinkEvent::Action::kAdd: {
for (auto source : mDiskSources) {
if (source->matches(eventPath)) {
// For now, assume that MMC devices are SD, and that
// everything else is USB
// 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) {
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;

Loading…
Cancel
Save