Merge changes Iae25434a,I13fd6699

* changes:
  libdm: Add LoopControl helpers for enabling direct IO.
  libdm: Add helpers for getting the device number of a dm device.
This commit is contained in:
David Anderson 2019-06-20 19:06:32 +00:00 committed by Gerrit Code Review
commit 71b3afe620
6 changed files with 65 additions and 3 deletions

View file

@ -46,6 +46,7 @@ cc_test {
static_libs: [
"libdm",
"libbase",
"libfs_mgr",
"liblog",
],
srcs: [

View file

@ -302,6 +302,26 @@ bool DeviceMapper::GetDmDevicePathByName(const std::string& name, std::string* p
return true;
}
bool DeviceMapper::GetDeviceNumber(const std::string& name, dev_t* dev) {
struct dm_ioctl io;
InitIo(&io, name);
if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
return false;
}
*dev = io.dev;
return true;
}
bool DeviceMapper::GetDeviceString(const std::string& name, std::string* dev) {
dev_t num;
if (!GetDeviceNumber(name, &num)) {
return false;
}
*dev = std::to_string(major(num)) + ":" + std::to_string(minor(num));
return true;
}
bool DeviceMapper::GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) {
return GetTable(name, 0, table);
}

View file

@ -132,8 +132,8 @@ TEST(libdm, DmLinear) {
// Define a 2-sector device, with each sector mapping to the first sector
// of one of our loop devices.
DmTable table;
ASSERT_TRUE(table.AddTarget(make_unique<DmTargetLinear>(0, 1, loop_a.device(), 0)));
ASSERT_TRUE(table.AddTarget(make_unique<DmTargetLinear>(1, 1, loop_b.device(), 0)));
ASSERT_TRUE(table.Emplace<DmTargetLinear>(0, 1, loop_a.device(), 0));
ASSERT_TRUE(table.Emplace<DmTargetLinear>(1, 1, loop_b.device(), 0));
ASSERT_TRUE(table.valid());
TempDevice dev("libdm-test-dm-linear", table);
@ -141,6 +141,16 @@ TEST(libdm, DmLinear) {
ASSERT_FALSE(dev.path().empty());
ASSERT_TRUE(dev.WaitForUdev());
auto& dm = DeviceMapper::Instance();
dev_t dev_number;
ASSERT_TRUE(dm.GetDeviceNumber(dev.name(), &dev_number));
ASSERT_NE(dev_number, 0);
std::string dev_string;
ASSERT_TRUE(dm.GetDeviceString(dev.name(), &dev_string));
ASSERT_FALSE(dev_string.empty());
// Note: a scope is needed to ensure that there are no open descriptors
// when we go to close the device.
{
@ -157,7 +167,6 @@ TEST(libdm, DmLinear) {
}
// Test GetTableStatus.
DeviceMapper& dm = DeviceMapper::Instance();
vector<DeviceMapper::TargetInfo> targets;
ASSERT_TRUE(dm.GetTableStatus(dev.name(), &targets));
ASSERT_EQ(targets.size(), 2);

View file

@ -20,6 +20,7 @@
#include <fcntl.h>
#include <linux/dm-ioctl.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <stdint.h>
#include <sys/sysmacros.h>
#include <unistd.h>
@ -111,6 +112,13 @@ class DeviceMapper final {
// parameter is not set.
bool GetDmDevicePathByName(const std::string& name, std::string* path);
// Returns the dev_t for the named device-mapper node.
bool GetDeviceNumber(const std::string& name, dev_t* dev);
// Returns a major:minor string for the named device-mapper node, that can
// be used as inputs to DmTargets that take a block device.
bool GetDeviceString(const std::string& name, std::string* dev);
// The only way to create a DeviceMapper object.
static DeviceMapper& Instance();

View file

@ -35,6 +35,9 @@ class LoopControl final {
// Detach the loop device given by 'loopdev' from the attached backing file.
bool Detach(const std::string& loopdev) const;
// Enable Direct I/O on a loop device. This requires kernel 4.9+.
static bool EnableDirectIo(int fd);
LoopControl(const LoopControl&) = delete;
LoopControl& operator=(const LoopControl&) = delete;
LoopControl& operator=(LoopControl&&) = default;

View file

@ -91,6 +91,27 @@ bool LoopControl::FindFreeLoopDevice(std::string* loopdev) const {
return true;
}
bool LoopControl::EnableDirectIo(int fd) {
#if !defined(LOOP_SET_BLOCK_SIZE)
static constexpr int LOOP_SET_BLOCK_SIZE = 0x4C09;
#endif
#if !defined(LOOP_SET_DIRECT_IO)
static constexpr int LOOP_SET_DIRECT_IO = 0x4C08;
#endif
// Note: the block size has to be >= the logical block size of the underlying
// block device, *not* the filesystem block size.
if (ioctl(fd, LOOP_SET_BLOCK_SIZE, 4096)) {
PLOG(ERROR) << "Could not set loop device block size";
return false;
}
if (ioctl(fd, LOOP_SET_DIRECT_IO, 1)) {
PLOG(ERROR) << "Could not set loop direct IO";
return false;
}
return true;
}
LoopDevice::LoopDevice(int fd, bool auto_close) : fd_(fd), owns_fd_(auto_close) {
Init();
}