Merge "Support sysfs changes in the Linux 5.15 kernel." am: 95cfb31bd2
Original change: https://android-review.googlesource.com/c/platform/system/core/+/2336159 Change-Id: I85c5e735f2c65e1039f39a35ef3023d3ddf098bb Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
13a5c158ce
8 changed files with 100 additions and 25 deletions
|
|
@ -289,7 +289,7 @@ bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeviceMapper::LoadTableAndActivate(const std::string& name, const DmTable& table) {
|
bool DeviceMapper::LoadTable(const std::string& name, const DmTable& table) {
|
||||||
std::string ioctl_buffer(sizeof(struct dm_ioctl), 0);
|
std::string ioctl_buffer(sizeof(struct dm_ioctl), 0);
|
||||||
ioctl_buffer += table.Serialize();
|
ioctl_buffer += table.Serialize();
|
||||||
|
|
||||||
|
|
@ -305,9 +305,17 @@ bool DeviceMapper::LoadTableAndActivate(const std::string& name, const DmTable&
|
||||||
PLOG(ERROR) << "DM_TABLE_LOAD failed";
|
PLOG(ERROR) << "DM_TABLE_LOAD failed";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
InitIo(io, name);
|
bool DeviceMapper::LoadTableAndActivate(const std::string& name, const DmTable& table) {
|
||||||
if (ioctl(fd_, DM_DEV_SUSPEND, io)) {
|
if (!LoadTable(name, table)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dm_ioctl io;
|
||||||
|
InitIo(&io, name);
|
||||||
|
if (ioctl(fd_, DM_DEV_SUSPEND, &io)) {
|
||||||
PLOG(ERROR) << "DM_TABLE_SUSPEND resume failed";
|
PLOG(ERROR) << "DM_TABLE_SUSPEND resume failed";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -690,3 +690,23 @@ TEST(libdm, CreateEmptyDevice) {
|
||||||
// Empty device should be in suspended state.
|
// Empty device should be in suspended state.
|
||||||
ASSERT_EQ(DmDeviceState::SUSPENDED, dm.GetState("empty-device"));
|
ASSERT_EQ(DmDeviceState::SUSPENDED, dm.GetState("empty-device"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(libdm, UeventAfterLoadTable) {
|
||||||
|
static const char* kDeviceName = "libmd-test-uevent-load-table";
|
||||||
|
|
||||||
|
DeviceMapper& dm = DeviceMapper::Instance();
|
||||||
|
ASSERT_TRUE(dm.CreateEmptyDevice(kDeviceName));
|
||||||
|
|
||||||
|
DmTable table;
|
||||||
|
table.Emplace<DmTargetError>(0, 1);
|
||||||
|
ASSERT_TRUE(dm.LoadTable(kDeviceName, table));
|
||||||
|
|
||||||
|
std::string ignore_path;
|
||||||
|
ASSERT_TRUE(dm.WaitForDevice(kDeviceName, 5s, &ignore_path));
|
||||||
|
|
||||||
|
auto info = dm.GetDetailedInfo(kDeviceName);
|
||||||
|
ASSERT_TRUE(info.has_value());
|
||||||
|
ASSERT_TRUE(info->IsSuspended());
|
||||||
|
|
||||||
|
ASSERT_TRUE(dm.DeleteDevice(kDeviceName));
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ class IDeviceMapper {
|
||||||
const std::chrono::milliseconds& timeout_ms) = 0;
|
const std::chrono::milliseconds& timeout_ms) = 0;
|
||||||
virtual DmDeviceState GetState(const std::string& name) const = 0;
|
virtual DmDeviceState GetState(const std::string& name) const = 0;
|
||||||
virtual bool LoadTableAndActivate(const std::string& name, const DmTable& table) = 0;
|
virtual bool LoadTableAndActivate(const std::string& name, const DmTable& table) = 0;
|
||||||
|
virtual bool LoadTable(const std::string& name, const DmTable& table) = 0;
|
||||||
virtual bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) = 0;
|
virtual bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) = 0;
|
||||||
virtual bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) = 0;
|
virtual bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) = 0;
|
||||||
virtual bool GetDmDevicePathByName(const std::string& name, std::string* path) = 0;
|
virtual bool GetDmDevicePathByName(const std::string& name, std::string* path) = 0;
|
||||||
|
|
@ -116,7 +117,7 @@ class DeviceMapper final : public IDeviceMapper {
|
||||||
bool IsBufferFull() const { return flags_ & DM_BUFFER_FULL_FLAG; }
|
bool IsBufferFull() const { return flags_ & DM_BUFFER_FULL_FLAG; }
|
||||||
bool IsInactiveTablePresent() const { return flags_ & DM_INACTIVE_PRESENT_FLAG; }
|
bool IsInactiveTablePresent() const { return flags_ & DM_INACTIVE_PRESENT_FLAG; }
|
||||||
bool IsReadOnly() const { return flags_ & DM_READONLY_FLAG; }
|
bool IsReadOnly() const { return flags_ & DM_READONLY_FLAG; }
|
||||||
bool IsSuspended() const { return flags_ & DM_SUSPEND_FLAG; }
|
bool IsSuspended() const { return !IsActiveTablePresent() || (flags_ & DM_SUSPEND_FLAG); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Removes a device mapper device with the given name.
|
// Removes a device mapper device with the given name.
|
||||||
|
|
@ -199,6 +200,12 @@ class DeviceMapper final : public IDeviceMapper {
|
||||||
// Returns 'true' on success, false otherwise.
|
// Returns 'true' on success, false otherwise.
|
||||||
bool LoadTableAndActivate(const std::string& name, const DmTable& table) override;
|
bool LoadTableAndActivate(const std::string& name, const DmTable& table) override;
|
||||||
|
|
||||||
|
// Same as LoadTableAndActivate, but there is no resume step. This puts the
|
||||||
|
// new table in the inactive slot.
|
||||||
|
//
|
||||||
|
// Returns 'true' on success, false otherwise.
|
||||||
|
bool LoadTable(const std::string& name, const DmTable& table) override;
|
||||||
|
|
||||||
// Returns true if a list of available device mapper targets registered in the kernel was
|
// Returns true if a list of available device mapper targets registered in the kernel was
|
||||||
// successfully read and stored in 'targets'. Returns 'false' otherwise.
|
// successfully read and stored in 'targets'. Returns 'false' otherwise.
|
||||||
bool GetAvailableTargets(std::vector<DmTargetTypeInfo>* targets);
|
bool GetAvailableTargets(std::vector<DmTargetTypeInfo>* targets);
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ namespace dm {
|
||||||
class DmTable {
|
class DmTable {
|
||||||
public:
|
public:
|
||||||
DmTable() : num_sectors_(0), readonly_(false) {}
|
DmTable() : num_sectors_(0), readonly_(false) {}
|
||||||
|
DmTable(DmTable&& other) = default;
|
||||||
|
|
||||||
// Adds a target to the device mapper table for a range specified in the target object.
|
// Adds a target to the device mapper table for a range specified in the target object.
|
||||||
// The function will return 'true' if the target was successfully added and doesn't overlap with
|
// The function will return 'true' if the target was successfully added and doesn't overlap with
|
||||||
|
|
@ -70,6 +71,8 @@ class DmTable {
|
||||||
void set_readonly(bool readonly) { readonly_ = readonly; }
|
void set_readonly(bool readonly) { readonly_ = readonly; }
|
||||||
bool readonly() const { return readonly_; }
|
bool readonly() const { return readonly_; }
|
||||||
|
|
||||||
|
DmTable& operator=(DmTable&& other) = default;
|
||||||
|
|
||||||
~DmTable() = default;
|
~DmTable() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -323,6 +323,14 @@ class DmTargetUser final : public DmTarget {
|
||||||
std::string control_device_;
|
std::string control_device_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DmTargetError final : public DmTarget {
|
||||||
|
public:
|
||||||
|
DmTargetError(uint64_t start, uint64_t length) : DmTarget(start, length) {}
|
||||||
|
|
||||||
|
std::string name() const override { return "error"; }
|
||||||
|
std::string GetParameterString() const override { return ""; }
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace dm
|
} // namespace dm
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,9 @@ class DeviceMapperWrapper : public android::dm::IDeviceMapper {
|
||||||
virtual DmDeviceState GetState(const std::string& name) const override {
|
virtual DmDeviceState GetState(const std::string& name) const override {
|
||||||
return impl_.GetState(name);
|
return impl_.GetState(name);
|
||||||
}
|
}
|
||||||
|
virtual bool LoadTable(const std::string& name, const DmTable& table) {
|
||||||
|
return impl_.LoadTable(name, table);
|
||||||
|
}
|
||||||
virtual bool LoadTableAndActivate(const std::string& name, const DmTable& table) {
|
virtual bool LoadTableAndActivate(const std::string& name, const DmTable& table) {
|
||||||
return impl_.LoadTableAndActivate(name, table);
|
return impl_.LoadTableAndActivate(name, table);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -183,6 +184,8 @@ class TargetParser final {
|
||||||
}
|
}
|
||||||
std::string control_device = NextArg();
|
std::string control_device = NextArg();
|
||||||
return std::make_unique<DmTargetUser>(start_sector, num_sectors, control_device);
|
return std::make_unique<DmTargetUser>(start_sector, num_sectors, control_device);
|
||||||
|
} else if (target_type == "error") {
|
||||||
|
return std::make_unique<DmTargetError>(start_sector, num_sectors);
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Unrecognized target type: " << target_type << std::endl;
|
std::cerr << "Unrecognized target type: " << target_type << std::endl;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -206,16 +209,26 @@ class TargetParser final {
|
||||||
char** argv_;
|
char** argv_;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool parse_table_args(DmTable* table, int argc, char** argv) {
|
struct TableArgs {
|
||||||
|
DmTable table;
|
||||||
|
bool suspended = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::optional<TableArgs> parse_table_args(int argc, char** argv) {
|
||||||
|
TableArgs out;
|
||||||
|
|
||||||
// Parse extended options first.
|
// Parse extended options first.
|
||||||
int arg_index = 1;
|
int arg_index = 1;
|
||||||
while (arg_index < argc && argv[arg_index][0] == '-') {
|
while (arg_index < argc && argv[arg_index][0] == '-') {
|
||||||
if (strcmp(argv[arg_index], "-ro") == 0) {
|
if (strcmp(argv[arg_index], "-ro") == 0) {
|
||||||
table->set_readonly(true);
|
out.table.set_readonly(true);
|
||||||
|
arg_index++;
|
||||||
|
} else if (strcmp(argv[arg_index], "-suspended") == 0) {
|
||||||
|
out.suspended = true;
|
||||||
arg_index++;
|
arg_index++;
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Unrecognized option: " << argv[arg_index] << std::endl;
|
std::cerr << "Unrecognized option: " << argv[arg_index] << std::endl;
|
||||||
return -EINVAL;
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,37 +236,44 @@ static bool parse_table_args(DmTable* table, int argc, char** argv) {
|
||||||
TargetParser parser(argc - arg_index, argv + arg_index);
|
TargetParser parser(argc - arg_index, argv + arg_index);
|
||||||
while (parser.More()) {
|
while (parser.More()) {
|
||||||
std::unique_ptr<DmTarget> target = parser.Next();
|
std::unique_ptr<DmTarget> target = parser.Next();
|
||||||
if (!target || !table->AddTarget(std::move(target))) {
|
if (!target || !out.table.AddTarget(std::move(target))) {
|
||||||
return -EINVAL;
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (table->num_targets() == 0) {
|
if (out.table.num_targets() == 0) {
|
||||||
std::cerr << "Must define at least one target." << std::endl;
|
std::cerr << "Must define at least one target." << std::endl;
|
||||||
return -EINVAL;
|
return {};
|
||||||
}
|
}
|
||||||
return 0;
|
return {std::move(out)};
|
||||||
}
|
}
|
||||||
|
|
||||||
static int DmCreateCmdHandler(int argc, char** argv) {
|
static int DmCreateCmdHandler(int argc, char** argv) {
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
std::cerr << "Usage: dmctl create <dm-name> [-ro] <targets...>" << std::endl;
|
std::cerr << "Usage: dmctl create <dm-name> [--suspended] [-ro] <targets...>" << std::endl;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
std::string name = argv[0];
|
std::string name = argv[0];
|
||||||
|
|
||||||
DmTable table;
|
auto table_args = parse_table_args(argc, argv);
|
||||||
int ret = parse_table_args(&table, argc, argv);
|
if (!table_args) {
|
||||||
if (ret) {
|
return -EINVAL;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ignore_path;
|
std::string ignore_path;
|
||||||
DeviceMapper& dm = DeviceMapper::Instance();
|
DeviceMapper& dm = DeviceMapper::Instance();
|
||||||
if (!dm.CreateDevice(name, table, &ignore_path, 5s)) {
|
if (!dm.CreateEmptyDevice(name)) {
|
||||||
std::cerr << "Failed to create device-mapper device with name: " << name << std::endl;
|
std::cerr << "Failed to create device-mapper device with name: " << name << std::endl;
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
if (!dm.LoadTable(name, table_args->table)) {
|
||||||
|
std::cerr << "Failed to load table for dm device: " << name << std::endl;
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
if (!table_args->suspended && !dm.ChangeState(name, DmDeviceState::ACTIVE)) {
|
||||||
|
std::cerr << "Failed to activate table for " << name << std::endl;
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -269,7 +289,6 @@ static int DmDeleteCmdHandler(int argc, char** argv) {
|
||||||
std::cerr << "Failed to delete [" << name << "]" << std::endl;
|
std::cerr << "Failed to delete [" << name << "]" << std::endl;
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,17 +299,20 @@ static int DmReplaceCmdHandler(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
std::string name = argv[0];
|
std::string name = argv[0];
|
||||||
|
|
||||||
DmTable table;
|
auto table_args = parse_table_args(argc, argv);
|
||||||
int ret = parse_table_args(&table, argc, argv);
|
if (!table_args) {
|
||||||
if (ret) {
|
return -EINVAL;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceMapper& dm = DeviceMapper::Instance();
|
DeviceMapper& dm = DeviceMapper::Instance();
|
||||||
if (!dm.LoadTableAndActivate(name, table)) {
|
if (!dm.LoadTable(name, table_args->table)) {
|
||||||
std::cerr << "Failed to replace device-mapper table to: " << name << std::endl;
|
std::cerr << "Failed to replace device-mapper table to: " << name << std::endl;
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
if (!table_args->suspended && !dm.ChangeState(name, DmDeviceState::ACTIVE)) {
|
||||||
|
std::cerr << "Failed to activate table for " << name << std::endl;
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -470,7 +470,11 @@ void DeviceHandler::HandleDevice(const std::string& action, const std::string& d
|
||||||
MakeDevice(devpath, block, major, minor, links);
|
MakeDevice(devpath, block, major, minor, links);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't have full device-mapper information until a change event is fired.
|
// Handle device-mapper nodes.
|
||||||
|
// On kernels <= 5.10, the "add" event is fired on DM_DEV_CREATE, but does not contain name
|
||||||
|
// information until DM_TABLE_LOAD - thus, we wait for a "change" event.
|
||||||
|
// On kernels >= 5.15, the "add" event is fired on DM_TABLE_LOAD, followed by a "change"
|
||||||
|
// event.
|
||||||
if (action == "add" || (action == "change" && StartsWith(devpath, "/dev/block/dm-"))) {
|
if (action == "add" || (action == "change" && StartsWith(devpath, "/dev/block/dm-"))) {
|
||||||
for (const auto& link : links) {
|
for (const auto& link : links) {
|
||||||
if (!mkdir_recursive(Dirname(link), 0755)) {
|
if (!mkdir_recursive(Dirname(link), 0755)) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue