Merge "Ramdisk: add metadata dir in ramdisk"
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 5280121..b3e81b0 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -299,11 +299,8 @@
process_info->abort_msg_address = crash_info->data.s.abort_msg_address;
*siginfo = crash_info->data.s.siginfo;
if (signal_has_si_addr(siginfo)) {
- // Make a copy of the ucontext field because otherwise it is not aligned enough (due to
- // being in a packed struct) and clang complains about that.
- ucontext_t ucontext = crash_info->data.s.ucontext;
process_info->has_fault_address = true;
- process_info->fault_address = get_fault_address(siginfo, &ucontext);
+ process_info->fault_address = reinterpret_cast<uintptr_t>(siginfo->si_addr);
}
regs->reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(),
&crash_info->data.s.ucontext));
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 121a074..85ffc98 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -167,7 +167,7 @@
* mutex is being held, so we don't want to use any libc functions that
* could allocate memory or hold a lock.
*/
-static void log_signal_summary(const siginfo_t* info, const ucontext_t* ucontext) {
+static void log_signal_summary(const siginfo_t* info) {
char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination
if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) {
strcpy(thread_name, "<name unknown>");
@@ -186,8 +186,7 @@
// Many signals don't have an address or sender.
char addr_desc[32] = ""; // ", fault addr 0x1234"
if (signal_has_si_addr(info)) {
- async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p",
- reinterpret_cast<void*>(get_fault_address(info, ucontext)));
+ async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
}
pid_t self_pid = __getpid();
char sender_desc[32] = {}; // " from pid 1234, uid 666"
@@ -544,7 +543,7 @@
return;
}
- log_signal_summary(info, ucontext);
+ log_signal_summary(info);
debugger_thread_info thread_info = {
.crashing_tid = __gettid(),
@@ -638,5 +637,11 @@
// Use the alternate signal stack if available so we can catch stack overflows.
action.sa_flags |= SA_ONSTACK;
+
+#define SA_EXPOSE_TAGBITS 0x00000800
+ // Request that the kernel set tag bits in the fault address. This is necessary for diagnosing MTE
+ // faults.
+ action.sa_flags |= SA_EXPOSE_TAGBITS;
+
debuggerd_register_handlers(&action);
}
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 76155b1..29fb9a4 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -91,6 +91,4 @@
const char* get_signame(const siginfo_t*);
const char* get_sigcode(const siginfo_t*);
-uintptr_t get_fault_address(const siginfo_t* siginfo, const ucontext_t* ucontext);
-
#endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 4e6df09..d7067ca 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -451,40 +451,3 @@
_LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
}
}
-
-#if defined(__aarch64__)
-#define FAR_MAGIC 0x46415201
-
-struct far_context {
- struct _aarch64_ctx head;
- __u64 far;
-};
-#endif
-
-uintptr_t get_fault_address(const siginfo_t* siginfo, const ucontext_t* ucontext) {
- (void)ucontext;
-#if defined(__aarch64__)
- // This relies on a kernel patch:
- // https://patchwork.kernel.org/patch/11435077/
- // that hasn't been accepted into the kernel yet. TODO(pcc): Update this to
- // use the official interface once it lands.
- auto* begin = reinterpret_cast<const char*>(ucontext->uc_mcontext.__reserved);
- auto* end = begin + sizeof(ucontext->uc_mcontext.__reserved);
- auto* ptr = begin;
- while (1) {
- auto* ctx = reinterpret_cast<const _aarch64_ctx*>(ptr);
- if (ctx->magic == 0) {
- break;
- }
- if (ctx->magic == FAR_MAGIC) {
- auto* far_ctx = reinterpret_cast<const far_context*>(ctx);
- return far_ctx->far;
- }
- ptr += ctx->size;
- if (ctx->size % sizeof(void*) != 0 || ptr < begin || ptr >= end) {
- break;
- }
- }
-#endif
- return reinterpret_cast<uintptr_t>(siginfo->si_addr);
-}
diff --git a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
index 7eddf8c..5483fd0 100644
--- a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
@@ -288,20 +288,20 @@
}
void SnapuserdTest::InitCowDevices() {
- system_blksize_ = client_->InitDmUserCow(cow_system_->path);
+ system_blksize_ = client_->InitDmUserCow(system_device_ctrl_name_, cow_system_->path,
+ system_a_loop_->device());
ASSERT_NE(system_blksize_, 0);
- product_blksize_ = client_->InitDmUserCow(cow_product_->path);
+ product_blksize_ = client_->InitDmUserCow(product_device_ctrl_name_, cow_product_->path,
+ product_a_loop_->device());
ASSERT_NE(product_blksize_, 0);
}
void SnapuserdTest::InitDaemon() {
- bool ok = client_->InitializeSnapuserd(cow_system_->path, system_a_loop_->device(),
- GetSystemControlPath());
+ bool ok = client_->AttachDmUser(system_device_ctrl_name_);
ASSERT_TRUE(ok);
- ok = client_->InitializeSnapuserd(cow_product_->path, product_a_loop_->device(),
- GetProductControlPath());
+ ok = client_->AttachDmUser(product_device_ctrl_name_);
ASSERT_TRUE(ok);
}
diff --git a/fs_mgr/libsnapshot/device_info.cpp b/fs_mgr/libsnapshot/device_info.cpp
index 0e90100..8770255 100644
--- a/fs_mgr/libsnapshot/device_info.cpp
+++ b/fs_mgr/libsnapshot/device_info.cpp
@@ -120,5 +120,9 @@
#endif
}
+std::string DeviceInfo::GetSnapuserdFirstStagePidVar() const {
+ return kSnapuserdFirstStagePidVar;
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/device_info.h b/fs_mgr/libsnapshot/device_info.h
index d8d3d91..1f08860 100644
--- a/fs_mgr/libsnapshot/device_info.h
+++ b/fs_mgr/libsnapshot/device_info.h
@@ -39,6 +39,7 @@
bool SetBootControlMergeStatus(MergeStatus status) override;
bool SetSlotAsUnbootable(unsigned int slot) override;
bool IsRecovery() const override;
+ std::string GetSnapuserdFirstStagePidVar() const override;
private:
bool EnsureBootHal();
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h
index ef9d648..d5c263d 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h
@@ -32,6 +32,7 @@
MOCK_METHOD(bool, SetBootControlMergeStatus, (MergeStatus status), (override));
MOCK_METHOD(bool, SetSlotAsUnbootable, (unsigned int slot), (override));
MOCK_METHOD(bool, IsRecovery, (), (const, override));
+ MOCK_METHOD(std::string, GetSnapuserdFirstStagePidVar, (), (const, override));
};
} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 8bed1b9..351dce7 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -107,6 +107,7 @@
virtual bool SetSlotAsUnbootable(unsigned int slot) = 0;
virtual bool IsRecovery() const = 0;
virtual bool IsTestDevice() const { return false; }
+ virtual std::string GetSnapuserdFirstStagePidVar() const = 0;
};
virtual ~ISnapshotManager() = default;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h
index cd8b080..24b44fa 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h
@@ -61,28 +61,31 @@
class Snapuserd final {
public:
- bool InitBackingAndControlDevice(std::string& backing_device, std::string& control_device);
- bool InitCowDevice(std::string& cow_device);
- int Run();
+ Snapuserd(const std::string& misc_name, const std::string& cow_device,
+ const std::string& backing_device);
+ bool InitBackingAndControlDevice();
+ bool InitCowDevice();
+ bool Run();
const std::string& GetControlDevicePath() { return control_device_; }
- const std::string& GetCowDevice() { return cow_device_; }
+ const std::string& GetMiscName() { return misc_name_; }
uint64_t GetNumSectors() { return num_sectors_; }
+ bool IsAttached() const { return ctrl_fd_ >= 0; }
private:
- int ReadDmUserHeader();
+ bool ReadDmUserHeader();
bool ReadDmUserPayload(void* buffer, size_t size);
- int WriteDmUserPayload(size_t size);
- int ConstructKernelCowHeader();
+ bool WriteDmUserPayload(size_t size);
+ void ConstructKernelCowHeader();
bool ReadMetadata();
- int ZerofillDiskExceptions(size_t read_size);
- int ReadDiskExceptions(chunk_t chunk, size_t size);
- int ReadData(chunk_t chunk, size_t size);
+ bool ZerofillDiskExceptions(size_t read_size);
+ bool ReadDiskExceptions(chunk_t chunk, size_t size);
+ bool ReadData(chunk_t chunk, size_t size);
bool IsChunkIdMetadata(chunk_t chunk);
chunk_t GetNextAllocatableChunkId(chunk_t chunk);
- int ProcessReplaceOp(const CowOperation* cow_op);
- int ProcessCopyOp(const CowOperation* cow_op);
- int ProcessZeroOp();
+ bool ProcessReplaceOp(const CowOperation* cow_op);
+ bool ProcessCopyOp(const CowOperation* cow_op);
+ bool ProcessZeroOp();
loff_t GetMergeStartOffset(void* merged_buffer, void* unmerged_buffer,
int* unmerged_exceptions);
@@ -96,6 +99,7 @@
std::string cow_device_;
std::string backing_store_device_;
std::string control_device_;
+ std::string misc_name_;
unique_fd cow_fd_;
unique_fd backing_store_fd_;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
index b5e5a96..0e9ba9e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
@@ -58,9 +58,19 @@
std::chrono::milliseconds timeout_ms);
bool StopSnapuserd();
- uint64_t InitDmUserCow(const std::string& cow_device);
- bool InitializeSnapuserd(const std::string& cow_device, const std::string& backing_device,
- const std::string& control_device);
+
+ // Initializing a snapuserd handler is a three-step process:
+ //
+ // 1. Client invokes InitDmUserCow. This creates the snapuserd handler and validates the
+ // COW. The number of sectors required for the dm-user target is returned.
+ // 2. Client creates the device-mapper device with the dm-user target.
+ // 3. Client calls AttachControlDevice.
+ //
+ // The misc_name must be the "misc_name" given to dm-user in step 2.
+ //
+ uint64_t InitDmUserCow(const std::string& misc_name, const std::string& cow_device,
+ const std::string& backing_device);
+ bool AttachDmUser(const std::string& misc_name);
// Wait for snapuserd to disassociate with a dm-user control device. This
// must ONLY be called if the control device has already been deleted.
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h
index 1037c12..e8dbe6e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h
@@ -17,6 +17,13 @@
namespace android {
namespace snapshot {
+#define DM_USER_REQ_MAP_READ 0
+#define DM_USER_REQ_MAP_WRITE 1
+
+#define DM_USER_RESP_SUCCESS 0
+#define DM_USER_RESP_ERROR 1
+#define DM_USER_RESP_UNSUPPORTED 2
+
// Kernel COW header fields
static constexpr uint32_t SNAP_MAGIC = 0x70416e53;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h
index be48400..cadfd71 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h
@@ -56,7 +56,7 @@
const std::unique_ptr<Snapuserd>& snapuserd() const { return snapuserd_; }
std::thread& thread() { return thread_; }
- const std::string& GetControlDevice() const;
+ const std::string& GetMiscName() const;
};
class Stoppable {
@@ -85,7 +85,9 @@
std::vector<struct pollfd> watched_fds_;
std::mutex lock_;
- std::vector<std::unique_ptr<DmUserHandler>> dm_users_;
+
+ using HandlerList = std::vector<std::shared_ptr<DmUserHandler>>;
+ HandlerList dm_users_;
void AddWatchedFd(android::base::borrowed_fd fd);
void AcceptClient();
@@ -95,7 +97,7 @@
bool Receivemsg(android::base::borrowed_fd fd, const std::string& str);
void ShutdownThreads();
- bool WaitForDelete(const std::string& control_device);
+ bool RemoveHandler(const std::string& control_device, bool wait);
DaemonOperations Resolveop(std::string& input);
std::string GetDaemonStatus();
void Parsemsg(std::string const& msg, const char delim, std::vector<std::string>& out);
@@ -103,11 +105,11 @@
void SetTerminating() { terminating_ = true; }
bool IsTerminating() { return terminating_; }
- void RunThread(DmUserHandler* handler);
+ void RunThread(std::shared_ptr<DmUserHandler> handler);
- // Remove a DmUserHandler from dm_users_, searching by its control device.
- // If none is found, return nullptr.
- std::unique_ptr<DmUserHandler> RemoveHandler(const std::string& control_device);
+ // Find a DmUserHandler within a lock.
+ HandlerList::iterator FindHandler(std::lock_guard<std::mutex>* proof_of_lock,
+ const std::string& misc_name);
public:
SnapuserdServer() { terminating_ = false; }
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index 7aef086..1d1510a 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -96,6 +96,7 @@
return true;
}
bool IsTestDevice() const override { return true; }
+ std::string GetSnapuserdFirstStagePidVar() const override { return {}; }
bool IsSlotUnbootable(uint32_t slot) { return unbootable_slots_.count(slot) != 0; }
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index c4c557e..6595707 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -397,7 +397,7 @@
return false;
}
- uint64_t base_sectors = snapuserd_client_->InitDmUserCow(cow_file);
+ uint64_t base_sectors = snapuserd_client_->InitDmUserCow(misc_name, cow_file, base_device);
if (base_sectors == 0) {
LOG(ERROR) << "Failed to retrieve base_sectors from Snapuserd";
return false;
@@ -410,7 +410,12 @@
}
auto control_device = "/dev/dm-user/" + misc_name;
- return snapuserd_client_->InitializeSnapuserd(cow_file, base_device, control_device);
+ if (!android::fs_mgr::WaitForFile(control_device, timeout_ms)) {
+ LOG(ERROR) << "Timed out waiting for dm-user misc device: " << control_device;
+ return false;
+ }
+
+ return snapuserd_client_->AttachDmUser(misc_name);
}
bool SnapshotManager::MapSnapshot(LockedFile* lock, const std::string& name,
@@ -1310,28 +1315,34 @@
size_t num_cows = 0;
size_t ok_cows = 0;
for (const auto& snapshot : snapshots) {
- std::string cow_name = GetDmUserCowName(snapshot);
- if (dm.GetState(cow_name) == DmDeviceState::INVALID) {
+ std::string user_cow_name = GetDmUserCowName(snapshot);
+ if (dm.GetState(user_cow_name) == DmDeviceState::INVALID) {
continue;
}
DeviceMapper::TargetInfo target;
- if (!GetSingleTarget(cow_name, TableQuery::Table, &target)) {
+ if (!GetSingleTarget(user_cow_name, TableQuery::Table, &target)) {
continue;
}
auto target_type = DeviceMapper::GetTargetType(target.spec);
if (target_type != "user") {
- LOG(ERROR) << "Unexpected target type for " << cow_name << ": " << target_type;
+ LOG(ERROR) << "Unexpected target type for " << user_cow_name << ": " << target_type;
continue;
}
num_cows++;
+ SnapshotStatus snapshot_status;
+ if (!ReadSnapshotStatus(lock.get(), snapshot, &snapshot_status)) {
+ LOG(ERROR) << "Unable to read snapshot status: " << snapshot;
+ continue;
+ }
+
DmTable table;
- table.Emplace<DmTargetUser>(0, target.spec.length, cow_name);
- if (!dm.LoadTableAndActivate(cow_name, table)) {
- LOG(ERROR) << "Unable to swap tables for " << cow_name;
+ table.Emplace<DmTargetUser>(0, target.spec.length, user_cow_name);
+ if (!dm.LoadTableAndActivate(user_cow_name, table)) {
+ LOG(ERROR) << "Unable to swap tables for " << user_cow_name;
continue;
}
@@ -1341,20 +1352,30 @@
continue;
}
- std::string cow_device;
- if (!dm.GetDmDevicePathByName(GetCowName(snapshot), &cow_device)) {
- LOG(ERROR) << "Could not get device path for " << GetCowName(snapshot);
+ // If no partition was created (the COW exists entirely on /data), the
+ // device-mapper layering is different than if we had a partition.
+ std::string cow_image_name;
+ if (snapshot_status.cow_partition_size() == 0) {
+ cow_image_name = GetCowImageDeviceName(snapshot);
+ } else {
+ cow_image_name = GetCowName(snapshot);
+ }
+
+ std::string cow_image_device;
+ if (!dm.GetDmDevicePathByName(cow_image_name, &cow_image_device)) {
+ LOG(ERROR) << "Could not get device path for " << cow_image_name;
continue;
}
// Wait for ueventd to acknowledge and create the control device node.
- std::string control_device = "/dev/dm-user/" + cow_name;
+ std::string control_device = "/dev/dm-user/" + user_cow_name;
if (!android::fs_mgr::WaitForFile(control_device, 10s)) {
LOG(ERROR) << "Could not find control device: " << control_device;
continue;
}
- uint64_t base_sectors = snapuserd_client_->InitDmUserCow(cow_device);
+ uint64_t base_sectors =
+ snapuserd_client_->InitDmUserCow(user_cow_name, cow_image_device, backing_device);
if (base_sectors == 0) {
// Unrecoverable as metadata reads from cow device failed
LOG(FATAL) << "Failed to retrieve base_sectors from Snapuserd";
@@ -1363,10 +1384,10 @@
CHECK(base_sectors == target.spec.length);
- if (!snapuserd_client_->InitializeSnapuserd(cow_device, backing_device, control_device)) {
+ if (!snapuserd_client_->AttachDmUser(user_cow_name)) {
// This error is unrecoverable. We cannot proceed because reads to
// the underlying device will fail.
- LOG(FATAL) << "Could not initialize snapuserd for " << cow_name;
+ LOG(FATAL) << "Could not initialize snapuserd for " << user_cow_name;
return false;
}
@@ -1378,8 +1399,13 @@
return false;
}
+ std::string pid_var = device_->GetSnapuserdFirstStagePidVar();
+ if (pid_var.empty()) {
+ return true;
+ }
+
int pid;
- const char* pid_str = getenv(kSnapuserdFirstStagePidVar);
+ const char* pid_str = getenv(pid_var.c_str());
if (pid_str && android::base::ParseInt(pid_str, &pid)) {
if (kill(pid, SIGTERM) < 0 && errno != ESRCH) {
LOG(ERROR) << "kill snapuserd failed";
@@ -2048,13 +2074,13 @@
return false;
}
- auto control_device = "/dev/dm-user/" + dm_user_name;
- if (!snapuserd_client_->WaitForDeviceDelete(control_device)) {
+ if (!snapuserd_client_->WaitForDeviceDelete(dm_user_name)) {
LOG(ERROR) << "Failed to wait for " << dm_user_name << " control device to delete";
return false;
}
// Ensure the control device is gone so we don't run into ABA problems.
+ auto control_device = "/dev/dm-user/" + dm_user_name;
if (!android::fs_mgr::WaitForFileDeleted(control_device, 10s)) {
LOG(ERROR) << "Timed out waiting for " << control_device << " to unlink";
return false;
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
index 5319e69..092ee0b 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
+++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
@@ -124,6 +124,7 @@
return data_->allow_set_slot_as_unbootable();
}
bool IsRecovery() const override { return data_->is_recovery(); }
+ std::string GetSnapuserdFirstStagePidVar() const override { return {}; }
void SwitchSlot() { switched_slot_ = !switched_slot_; }
diff --git a/fs_mgr/libsnapshot/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd.cpp
index 7c393fc..954699c 100644
--- a/fs_mgr/libsnapshot/snapuserd.cpp
+++ b/fs_mgr/libsnapshot/snapuserd.cpp
@@ -28,9 +28,6 @@
using namespace android::dm;
using android::base::unique_fd;
-#define DM_USER_MAP_READ 0
-#define DM_USER_MAP_WRITE 1
-
static constexpr size_t PAYLOAD_SIZE = (1UL << 16);
static_assert(PAYLOAD_SIZE >= BLOCK_SIZE);
@@ -66,11 +63,19 @@
return header;
}
+Snapuserd::Snapuserd(const std::string& misc_name, const std::string& cow_device,
+ const std::string& backing_device) {
+ misc_name_ = misc_name;
+ cow_device_ = cow_device;
+ backing_store_device_ = backing_device;
+ control_device_ = "/dev/dm-user/" + misc_name;
+}
+
// Construct kernel COW header in memory
// This header will be in sector 0. The IO
// request will always be 4k. After constructing
// the header, zero out the remaining block.
-int Snapuserd::ConstructKernelCowHeader() {
+void Snapuserd::ConstructKernelCowHeader() {
void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SIZE);
CHECK(buffer != nullptr);
@@ -82,25 +87,23 @@
dh->valid = SNAPSHOT_VALID;
dh->version = SNAPSHOT_DISK_VERSION;
dh->chunk_size = CHUNK_SIZE;
-
- return BLOCK_SIZE;
}
// Start the replace operation. This will read the
// internal COW format and if the block is compressed,
// it will be de-compressed.
-int Snapuserd::ProcessReplaceOp(const CowOperation* cow_op) {
+bool Snapuserd::ProcessReplaceOp(const CowOperation* cow_op) {
if (!reader_->ReadData(*cow_op, &bufsink_)) {
LOG(ERROR) << "ReadData failed for chunk: " << cow_op->new_block;
- return -EIO;
+ return false;
}
- return BLOCK_SIZE;
+ return true;
}
// Start the copy operation. This will read the backing
// block device which is represented by cow_op->source.
-int Snapuserd::ProcessCopyOp(const CowOperation* cow_op) {
+bool Snapuserd::ProcessCopyOp(const CowOperation* cow_op) {
void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SIZE);
CHECK(buffer != nullptr);
@@ -109,19 +112,19 @@
if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SIZE,
cow_op->source * BLOCK_SIZE)) {
LOG(ERROR) << "Copy-op failed. Read from backing store at: " << cow_op->source;
- return -1;
+ return false;
}
- return BLOCK_SIZE;
+ return true;
}
-int Snapuserd::ProcessZeroOp() {
+bool Snapuserd::ProcessZeroOp() {
// Zero out the entire block
void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SIZE);
CHECK(buffer != nullptr);
memset(buffer, 0, BLOCK_SIZE);
- return BLOCK_SIZE;
+ return true;
}
/*
@@ -146,11 +149,9 @@
* 3: Zero operation
*
*/
-int Snapuserd::ReadData(chunk_t chunk, size_t size) {
- int ret = 0;
-
+bool Snapuserd::ReadData(chunk_t chunk, size_t size) {
size_t read_size = size;
-
+ bool ret = true;
chunk_t chunk_key = chunk;
uint32_t stride;
lldiv_t divresult;
@@ -161,41 +162,39 @@
while (read_size > 0) {
const CowOperation* cow_op = chunk_map_[chunk_key];
CHECK(cow_op != nullptr);
- int result;
switch (cow_op->type) {
case kCowReplaceOp: {
- result = ProcessReplaceOp(cow_op);
+ ret = ProcessReplaceOp(cow_op);
break;
}
case kCowZeroOp: {
- result = ProcessZeroOp();
+ ret = ProcessZeroOp();
break;
}
case kCowCopyOp: {
- result = ProcessCopyOp(cow_op);
+ ret = ProcessCopyOp(cow_op);
break;
}
default: {
LOG(ERROR) << "Unknown operation-type found: " << cow_op->type;
- ret = -EIO;
- goto done;
+ ret = false;
+ break;
}
}
- if (result < 0) {
- ret = result;
- goto done;
+ if (!ret) {
+ LOG(ERROR) << "ReadData failed for operation: " << cow_op->type;
+ return false;
}
// Update the buffer offset
bufsink_.UpdateBufferOffset(BLOCK_SIZE);
read_size -= BLOCK_SIZE;
- ret += BLOCK_SIZE;
// Start iterating the chunk incrementally; Since while
// constructing the metadata, we know that the chunk IDs
@@ -223,8 +222,6 @@
}
}
-done:
-
// Reset the buffer offset
bufsink_.ResetBufferOffset();
return ret;
@@ -241,16 +238,18 @@
* When dm-snap starts parsing the buffer, it will stop
* reading metadata page once the buffer content is zero.
*/
-int Snapuserd::ZerofillDiskExceptions(size_t read_size) {
+bool Snapuserd::ZerofillDiskExceptions(size_t read_size) {
size_t size = exceptions_per_area_ * sizeof(struct disk_exception);
- if (read_size > size) return -EINVAL;
+ if (read_size > size) {
+ return false;
+ }
void* buffer = bufsink_.GetPayloadBuffer(size);
CHECK(buffer != nullptr);
memset(buffer, 0, size);
- return size;
+ return true;
}
/*
@@ -266,7 +265,7 @@
* Convert the chunk ID to index into the vector which gives us
* the metadata page.
*/
-int Snapuserd::ReadDiskExceptions(chunk_t chunk, size_t read_size) {
+bool Snapuserd::ReadDiskExceptions(chunk_t chunk, size_t read_size) {
uint32_t stride = exceptions_per_area_ + 1;
size_t size;
@@ -276,17 +275,19 @@
if (divresult.quot < vec_.size()) {
size = exceptions_per_area_ * sizeof(struct disk_exception);
- if (read_size > size) return -EINVAL;
+ if (read_size > size) {
+ return false;
+ }
void* buffer = bufsink_.GetPayloadBuffer(size);
CHECK(buffer != nullptr);
memcpy(buffer, vec_[divresult.quot].get(), size);
} else {
- size = ZerofillDiskExceptions(read_size);
+ return ZerofillDiskExceptions(read_size);
}
- return size;
+ return true;
}
loff_t Snapuserd::GetMergeStartOffset(void* merged_buffer, void* unmerged_buffer,
@@ -640,27 +641,24 @@
// Read Header from dm-user misc device. This gives
// us the sector number for which IO is issued by dm-snapshot device
-int Snapuserd::ReadDmUserHeader() {
- int ret;
-
- ret = read(ctrl_fd_, bufsink_.GetBufPtr(), sizeof(struct dm_user_header));
- if (ret < 0) {
- PLOG(ERROR) << "Control-read failed with: " << ret;
- return ret;
+bool Snapuserd::ReadDmUserHeader() {
+ if (!android::base::ReadFully(ctrl_fd_, bufsink_.GetBufPtr(), sizeof(struct dm_user_header))) {
+ PLOG(ERROR) << "ReadDmUserHeader failed";
+ return false;
}
- return sizeof(struct dm_user_header);
+ return true;
}
// Send the payload/data back to dm-user misc device.
-int Snapuserd::WriteDmUserPayload(size_t size) {
+bool Snapuserd::WriteDmUserPayload(size_t size) {
if (!android::base::WriteFully(ctrl_fd_, bufsink_.GetBufPtr(),
sizeof(struct dm_user_header) + size)) {
PLOG(ERROR) << "Write to dm-user failed";
- return -1;
+ return false;
}
- return sizeof(struct dm_user_header) + size;
+ return true;
}
bool Snapuserd::ReadDmUserPayload(void* buffer, size_t size) {
@@ -672,9 +670,7 @@
return true;
}
-bool Snapuserd::InitCowDevice(std::string& cow_device) {
- cow_device_ = cow_device;
-
+bool Snapuserd::InitCowDevice() {
cow_fd_.reset(open(cow_device_.c_str(), O_RDWR));
if (cow_fd_ < 0) {
PLOG(ERROR) << "Open Failed: " << cow_device_;
@@ -691,11 +687,7 @@
return ReadMetadata();
}
-bool Snapuserd::InitBackingAndControlDevice(std::string& backing_device,
- std::string& control_device) {
- backing_store_device_ = backing_device;
- control_device_ = control_device;
-
+bool Snapuserd::InitBackingAndControlDevice() {
backing_store_fd_.reset(open(backing_store_device_.c_str(), O_RDONLY));
if (backing_store_fd_ < 0) {
PLOG(ERROR) << "Open Failed: " << backing_store_device_;
@@ -711,17 +703,15 @@
return true;
}
-int Snapuserd::Run() {
- int ret = 0;
-
+bool Snapuserd::Run() {
struct dm_user_header* header = bufsink_.GetHeaderPtr();
bufsink_.Clear();
- ret = ReadDmUserHeader();
- if (ret < 0) return ret;
-
- LOG(DEBUG) << "dm-user returned " << ret << " bytes";
+ if (!ReadDmUserHeader()) {
+ LOG(ERROR) << "ReadDmUserHeader failed";
+ return false;
+ }
LOG(DEBUG) << "msg->seq: " << std::hex << header->seq;
LOG(DEBUG) << "msg->type: " << std::hex << header->type;
@@ -730,12 +720,12 @@
LOG(DEBUG) << "msg->len: " << std::hex << header->len;
switch (header->type) {
- case DM_USER_MAP_READ: {
+ case DM_USER_REQ_MAP_READ: {
size_t remaining_size = header->len;
loff_t offset = 0;
- ret = 0;
do {
size_t read_size = std::min(PAYLOAD_SIZE, remaining_size);
+ header->type = DM_USER_RESP_SUCCESS;
// Request to sector 0 is always for kernel
// representation of COW header. This IO should be only
@@ -745,8 +735,8 @@
if (header->sector == 0) {
CHECK(metadata_read_done_ == true);
CHECK(read_size == BLOCK_SIZE);
- ret = ConstructKernelCowHeader();
- if (ret < 0) return ret;
+ ConstructKernelCowHeader();
+ LOG(DEBUG) << "Kernel header constructed";
} else {
// Convert the sector number to a chunk ID.
//
@@ -756,71 +746,100 @@
chunk_t chunk = SectorToChunk(header->sector);
if (chunk_map_.find(chunk) == chunk_map_.end()) {
- ret = ReadDiskExceptions(chunk, read_size);
- if (ret < 0) {
- LOG(ERROR) << "ReadDiskExceptions failed";
- return ret;
+ if (!ReadDiskExceptions(chunk, read_size)) {
+ LOG(ERROR) << "ReadDiskExceptions failed for chunk id: " << chunk
+ << "Sector: " << header->sector;
+ header->type = DM_USER_RESP_ERROR;
+ } else {
+ LOG(DEBUG) << "ReadDiskExceptions success for chunk id: " << chunk
+ << "Sector: " << header->sector;
}
} else {
chunk_t num_chunks_read = (offset >> BLOCK_SHIFT);
- ret = ReadData(chunk + num_chunks_read, read_size);
- if (ret < 0) {
- LOG(ERROR) << "ReadData failed";
- // TODO: Bug 168259959: All the error paths from this function
- // should send error code to dm-user thereby IO
- // terminates with an error from dm-user. Returning
- // here without sending error code will block the
- // IO.
- return ret;
+ if (!ReadData(chunk + num_chunks_read, read_size)) {
+ LOG(ERROR) << "ReadData failed for chunk id: " << chunk
+ << "Sector: " << header->sector;
+ header->type = DM_USER_RESP_ERROR;
+ } else {
+ LOG(DEBUG) << "ReadData success for chunk id: " << chunk
+ << "Sector: " << header->sector;
}
}
}
- ssize_t written = WriteDmUserPayload(ret);
- if (written < 0) return written;
-
- remaining_size -= ret;
- offset += ret;
- if (remaining_size) {
- LOG(DEBUG) << "Write done ret: " << ret
- << " remaining size: " << remaining_size;
+ // Daemon will not be terminated if there is any error. We will
+ // just send the error back to dm-user.
+ if (!WriteDmUserPayload(read_size)) {
+ return false;
}
+
+ remaining_size -= read_size;
+ offset += read_size;
} while (remaining_size);
break;
}
- case DM_USER_MAP_WRITE: {
+ case DM_USER_REQ_MAP_WRITE: {
+ // device mapper has the capability to allow
+ // targets to flush the cache when writes are completed. This
+ // is controlled by each target by a flag "flush_supported".
+ // This flag is set by dm-user. When flush is supported,
+ // a number of zero-length bio's will be submitted to
+ // the target for the purpose of flushing cache. It is the
+ // responsibility of the target driver - which is dm-user in this
+ // case, to remap these bio's to the underlying device. Since,
+ // there is no underlying device for dm-user, this zero length
+ // bio's gets routed to daemon.
+ //
+ // Flush operations are generated post merge by dm-snap by having
+ // REQ_PREFLUSH flag set. Snapuser daemon doesn't have anything
+ // to flush per se; hence, just respond back with a success message.
+ if (header->sector == 0) {
+ CHECK(header->len == 0);
+ header->type = DM_USER_RESP_SUCCESS;
+ if (!WriteDmUserPayload(0)) {
+ return false;
+ }
+ break;
+ }
+
size_t remaining_size = header->len;
size_t read_size = std::min(PAYLOAD_SIZE, remaining_size);
CHECK(read_size == BLOCK_SIZE);
+
CHECK(header->sector > 0);
chunk_t chunk = SectorToChunk(header->sector);
CHECK(chunk_map_.find(chunk) == chunk_map_.end());
void* buffer = bufsink_.GetPayloadBuffer(read_size);
CHECK(buffer != nullptr);
+ header->type = DM_USER_RESP_SUCCESS;
if (!ReadDmUserPayload(buffer, read_size)) {
- return 1;
+ LOG(ERROR) << "ReadDmUserPayload failed for chunk id: " << chunk
+ << "Sector: " << header->sector;
+ header->type = DM_USER_RESP_ERROR;
}
- if (!ProcessMergeComplete(chunk, buffer)) {
- LOG(ERROR) << "ProcessMergeComplete failed...";
- return 1;
+ if (header->type == DM_USER_RESP_SUCCESS && !ProcessMergeComplete(chunk, buffer)) {
+ LOG(ERROR) << "ProcessMergeComplete failed for chunk id: " << chunk
+ << "Sector: " << header->sector;
+ header->type = DM_USER_RESP_ERROR;
+ } else {
+ LOG(DEBUG) << "ProcessMergeComplete success for chunk id: " << chunk
+ << "Sector: " << header->sector;
}
- // Write the header only.
- ssize_t written = WriteDmUserPayload(0);
- if (written < 0) return written;
+ if (!WriteDmUserPayload(0)) {
+ return false;
+ }
break;
}
}
- LOG(DEBUG) << "read() finished, next message";
-
- return 0;
+ return true;
}
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapuserd_client.cpp b/fs_mgr/libsnapshot/snapuserd_client.cpp
index d7fdb43..a5d2061 100644
--- a/fs_mgr/libsnapshot/snapuserd_client.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_client.cpp
@@ -183,10 +183,8 @@
return true;
}
-bool SnapuserdClient::InitializeSnapuserd(const std::string& cow_device,
- const std::string& backing_device,
- const std::string& control_device) {
- std::string msg = "start," + cow_device + "," + backing_device + "," + control_device;
+bool SnapuserdClient::AttachDmUser(const std::string& misc_name) {
+ std::string msg = "start," + misc_name;
if (!Sendmsg(msg)) {
LOG(ERROR) << "Failed to send message " << msg << " to snapuserd daemon";
return false;
@@ -202,8 +200,10 @@
return true;
}
-uint64_t SnapuserdClient::InitDmUserCow(const std::string& cow_device) {
- std::string msg = "init," + cow_device;
+uint64_t SnapuserdClient::InitDmUserCow(const std::string& misc_name, const std::string& cow_device,
+ const std::string& backing_device) {
+ std::vector<std::string> parts = {"init", misc_name, cow_device, backing_device};
+ std::string msg = android::base::Join(parts, ",");
if (!Sendmsg(msg)) {
LOG(ERROR) << "Failed to send message " << msg << " to snapuserd daemon";
return 0;
@@ -213,7 +213,7 @@
std::vector<std::string> input = android::base::Split(str, ",");
- if (input[0] != "success") {
+ if (input.empty() || input[0] != "success") {
LOG(ERROR) << "Failed to receive number of sectors for " << msg << " from snapuserd daemon";
return 0;
}
diff --git a/fs_mgr/libsnapshot/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd_server.cpp
index 3aa6136..9d57ab0 100644
--- a/fs_mgr/libsnapshot/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_server.cpp
@@ -74,7 +74,7 @@
StopThreads();
// Acquire the thread list within the lock.
- std::vector<std::unique_ptr<DmUserHandler>> dm_users;
+ std::vector<std::shared_ptr<DmUserHandler>> dm_users;
{
std::lock_guard<std::mutex> guard(lock_);
dm_users = std::move(dm_users_);
@@ -87,8 +87,8 @@
}
}
-const std::string& DmUserHandler::GetControlDevice() const {
- return snapuserd_->GetControlDevicePath();
+const std::string& DmUserHandler::GetMiscName() const {
+ return snapuserd_->GetMiscName();
}
bool SnapuserdServer::Sendmsg(android::base::borrowed_fd fd, const std::string& msg) {
@@ -126,16 +126,16 @@
switch (op) {
case DaemonOperations::INIT: {
// Message format:
- // init,<cow_device_path>
+ // init,<misc_name>,<cow_device_path>,<control_device>
//
// Reads the metadata and send the number of sectors
- if (out.size() != 2) {
+ if (out.size() != 4) {
LOG(ERROR) << "Malformed init message, " << out.size() << " parts";
return Sendmsg(fd, "fail");
}
- auto snapuserd = std::make_unique<Snapuserd>();
- if (!snapuserd->InitCowDevice(out[1])) {
+ auto snapuserd = std::make_unique<Snapuserd>(out[1], out[2], out[3]);
+ if (!snapuserd->InitCowDevice()) {
LOG(ERROR) << "Failed to initialize Snapuserd";
return Sendmsg(fd, "fail");
}
@@ -145,6 +145,10 @@
auto handler = std::make_unique<DmUserHandler>(std::move(snapuserd));
{
std::lock_guard<std::mutex> lock(lock_);
+ if (FindHandler(&lock, out[1]) != dm_users_.end()) {
+ LOG(ERROR) << "Handler already exists: " << out[1];
+ return Sendmsg(fd, "fail");
+ }
dm_users_.push_back(std::move(handler));
}
@@ -152,37 +156,30 @@
}
case DaemonOperations::START: {
// Message format:
- // start,<cow_device_path>,<source_device_path>,<control_device>
+ // start,<misc_name>
//
// Start the new thread which binds to dm-user misc device
- if (out.size() != 4) {
+ if (out.size() != 2) {
LOG(ERROR) << "Malformed start message, " << out.size() << " parts";
return Sendmsg(fd, "fail");
}
- bool found = false;
- {
- std::lock_guard<std::mutex> lock(lock_);
- auto iter = dm_users_.begin();
- while (iter != dm_users_.end()) {
- if ((*iter)->snapuserd()->GetCowDevice() == out[1]) {
- if (!((*iter)->snapuserd()->InitBackingAndControlDevice(out[2], out[3]))) {
- LOG(ERROR) << "Failed to initialize control device: " << out[3];
- break;
- }
- (*iter)->thread() = std::thread(
- std::bind(&SnapuserdServer::RunThread, this, (*iter).get()));
- found = true;
- break;
- }
- iter++;
- }
- }
- if (found) {
- return Sendmsg(fd, "success");
- } else {
+ std::lock_guard<std::mutex> lock(lock_);
+ auto iter = FindHandler(&lock, out[1]);
+ if (iter == dm_users_.end()) {
+ LOG(ERROR) << "Could not find handler: " << out[1];
return Sendmsg(fd, "fail");
}
+ if ((*iter)->snapuserd()->IsAttached()) {
+ LOG(ERROR) << "Tried to re-attach control device: " << out[1];
+ return Sendmsg(fd, "fail");
+ }
+ if (!((*iter)->snapuserd()->InitBackingAndControlDevice())) {
+ LOG(ERROR) << "Failed to initialize control device: " << out[1];
+ return Sendmsg(fd, "fail");
+ }
+ (*iter)->thread() = std::thread(std::bind(&SnapuserdServer::RunThread, this, *iter));
+ return Sendmsg(fd, "success");
}
case DaemonOperations::STOP: {
// Message format: stop
@@ -207,12 +204,12 @@
}
case DaemonOperations::DELETE: {
// Message format:
- // delete,<control_device_path>
+ // delete,<misc_name>
if (out.size() != 2) {
LOG(ERROR) << "Malformed delete message, " << out.size() << " parts";
return Sendmsg(fd, "fail");
}
- if (!WaitForDelete(out[1])) {
+ if (!RemoveHandler(out[1], true)) {
return Sendmsg(fd, "fail");
}
return Sendmsg(fd, "success");
@@ -225,25 +222,21 @@
}
}
-void SnapuserdServer::RunThread(DmUserHandler* handler) {
- LOG(INFO) << "Entering thread for handler: " << handler->GetControlDevice();
+void SnapuserdServer::RunThread(std::shared_ptr<DmUserHandler> handler) {
+ LOG(INFO) << "Entering thread for handler: " << handler->GetMiscName();
while (!StopRequested()) {
- if (handler->snapuserd()->Run() < 0) {
- LOG(INFO) << "Snapuserd: Thread terminating as control device is de-registered";
+ if (!handler->snapuserd()->Run()) {
+ LOG(INFO) << "Snapuserd: Thread terminating";
break;
}
}
- LOG(INFO) << "Exiting thread for handler: " << handler->GetControlDevice();
+ LOG(INFO) << "Exiting thread for handler: " << handler->GetMiscName();
- if (auto client = RemoveHandler(handler->GetControlDevice())) {
- // The main thread did not receive a WaitForDelete request for this
- // control device. Since we transferred ownership within the lock,
- // we know join() was never called, and will never be called. We can
- // safely detach here.
- client->thread().detach();
- }
+ // If the main thread called /emoveHandler, the handler was already removed
+ // from within the lock, and calling RemoveHandler again has no effect.
+ RemoveHandler(handler->GetMiscName(), false);
}
bool SnapuserdServer::Start(const std::string& socketname) {
@@ -336,34 +329,37 @@
SetTerminating();
}
-std::unique_ptr<DmUserHandler> SnapuserdServer::RemoveHandler(const std::string& control_device) {
- std::unique_ptr<DmUserHandler> client;
- {
- std::lock_guard<std::mutex> lock(lock_);
- auto iter = dm_users_.begin();
- while (iter != dm_users_.end()) {
- if ((*iter)->GetControlDevice() == control_device) {
- client = std::move(*iter);
- iter = dm_users_.erase(iter);
- break;
- }
- iter++;
+auto SnapuserdServer::FindHandler(std::lock_guard<std::mutex>* proof_of_lock,
+ const std::string& misc_name) -> HandlerList::iterator {
+ CHECK(proof_of_lock);
+
+ for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) {
+ if ((*iter)->GetMiscName() == misc_name) {
+ return iter;
}
}
- return client;
+ return dm_users_.end();
}
-bool SnapuserdServer::WaitForDelete(const std::string& control_device) {
- auto client = RemoveHandler(control_device);
+bool SnapuserdServer::RemoveHandler(const std::string& misc_name, bool wait) {
+ std::shared_ptr<DmUserHandler> handler;
+ {
+ std::lock_guard<std::mutex> lock(lock_);
- // Client already deleted.
- if (!client) {
- return true;
+ auto iter = FindHandler(&lock, misc_name);
+ if (iter == dm_users_.end()) {
+ // Client already deleted.
+ return true;
+ }
+ handler = std::move(*iter);
+ dm_users_.erase(iter);
}
- auto& th = client->thread();
- if (th.joinable()) {
+ auto& th = handler->thread();
+ if (th.joinable() && wait) {
th.join();
+ } else if (handler->snapuserd()->IsAttached()) {
+ th.detach();
}
return true;
}
diff --git a/fs_mgr/tools/Android.bp b/fs_mgr/tools/Android.bp
index 4d4aae4..d6ccc4b 100644
--- a/fs_mgr/tools/Android.bp
+++ b/fs_mgr/tools/Android.bp
@@ -29,3 +29,15 @@
cflags: ["-Werror"],
}
+
+cc_binary {
+ name: "dmuserd",
+ srcs: ["dmuserd.cpp"],
+
+ shared_libs: [
+ "libbase",
+ "liblog",
+ ],
+
+ cflags: ["-Werror"],
+}
diff --git a/fs_mgr/tools/dmuserd.cpp b/fs_mgr/tools/dmuserd.cpp
new file mode 100644
index 0000000..92f5878
--- /dev/null
+++ b/fs_mgr/tools/dmuserd.cpp
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#define _LARGEFILE64_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+#include <iostream>
+
+#define SECTOR_SIZE ((__u64)512)
+#define BUFFER_BYTES 4096
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+/* This should be replaced with linux/dm-user.h. */
+#ifndef _LINUX_DM_USER_H
+#define _LINUX_DM_USER_H
+
+#include <linux/types.h>
+
+#define DM_USER_REQ_MAP_READ 0
+#define DM_USER_REQ_MAP_WRITE 1
+#define DM_USER_REQ_MAP_FLUSH 2
+#define DM_USER_REQ_MAP_DISCARD 3
+#define DM_USER_REQ_MAP_SECURE_ERASE 4
+#define DM_USER_REQ_MAP_WRITE_SAME 5
+#define DM_USER_REQ_MAP_WRITE_ZEROES 6
+#define DM_USER_REQ_MAP_ZONE_OPEN 7
+#define DM_USER_REQ_MAP_ZONE_CLOSE 8
+#define DM_USER_REQ_MAP_ZONE_FINISH 9
+#define DM_USER_REQ_MAP_ZONE_APPEND 10
+#define DM_USER_REQ_MAP_ZONE_RESET 11
+#define DM_USER_REQ_MAP_ZONE_RESET_ALL 12
+
+#define DM_USER_REQ_MAP_FLAG_FAILFAST_DEV 0x00001
+#define DM_USER_REQ_MAP_FLAG_FAILFAST_TRANSPORT 0x00002
+#define DM_USER_REQ_MAP_FLAG_FAILFAST_DRIVER 0x00004
+#define DM_USER_REQ_MAP_FLAG_SYNC 0x00008
+#define DM_USER_REQ_MAP_FLAG_META 0x00010
+#define DM_USER_REQ_MAP_FLAG_PRIO 0x00020
+#define DM_USER_REQ_MAP_FLAG_NOMERGE 0x00040
+#define DM_USER_REQ_MAP_FLAG_IDLE 0x00080
+#define DM_USER_REQ_MAP_FLAG_INTEGRITY 0x00100
+#define DM_USER_REQ_MAP_FLAG_FUA 0x00200
+#define DM_USER_REQ_MAP_FLAG_PREFLUSH 0x00400
+#define DM_USER_REQ_MAP_FLAG_RAHEAD 0x00800
+#define DM_USER_REQ_MAP_FLAG_BACKGROUND 0x01000
+#define DM_USER_REQ_MAP_FLAG_NOWAIT 0x02000
+#define DM_USER_REQ_MAP_FLAG_CGROUP_PUNT 0x04000
+#define DM_USER_REQ_MAP_FLAG_NOUNMAP 0x08000
+#define DM_USER_REQ_MAP_FLAG_HIPRI 0x10000
+#define DM_USER_REQ_MAP_FLAG_DRV 0x20000
+#define DM_USER_REQ_MAP_FLAG_SWAP 0x40000
+
+#define DM_USER_RESP_SUCCESS 0
+#define DM_USER_RESP_ERROR 1
+#define DM_USER_RESP_UNSUPPORTED 2
+
+struct dm_user_message {
+ __u64 seq;
+ __u64 type;
+ __u64 flags;
+ __u64 sector;
+ __u64 len;
+ __u8 buf[];
+};
+
+#endif
+
+static bool verbose = false;
+
+size_t write_all(int fd, void* buf, size_t len) {
+ char* buf_c = (char*)buf;
+ ssize_t total = 0;
+ ssize_t once;
+
+ while (total < len) {
+ once = write(fd, buf_c + total, len - total);
+ if (once < 0) return once;
+ if (once == 0) {
+ errno = ENOSPC;
+ return 0;
+ }
+ total += once;
+ }
+
+ return total;
+}
+
+size_t read_all(int fd, void* buf, size_t len) {
+ char* buf_c = (char*)buf;
+ ssize_t total = 0;
+ ssize_t once;
+
+ while (total < len) {
+ once = read(fd, buf_c + total, len - total);
+ if (once < 0) return once;
+ if (once == 0) {
+ errno = ENOSPC;
+ return 0;
+ }
+ total += once;
+ }
+
+ return total;
+}
+
+int not_splice(int from, int to, __u64 count) {
+ while (count > 0) {
+ char buf[BUFFER_BYTES];
+ __u64 max = count > BUFFER_BYTES ? BUFFER_BYTES : count;
+
+ if (read_all(from, buf, max) <= 0) {
+ perror("Unable to read");
+ return -EIO;
+ }
+
+ if (write_all(to, buf, max) <= 0) {
+ perror("Unable to write");
+ return -EIO;
+ }
+
+ count -= max;
+ }
+
+ return 0;
+}
+
+int simple_daemon(char* control_path, char* backing_path) {
+ int control_fd = open(control_path, O_RDWR);
+ if (control_fd < 0) {
+ fprintf(stderr, "Unable to open control device %s\n", control_path);
+ return -1;
+ }
+
+ int backing_fd = open(backing_path, O_RDWR);
+ if (backing_fd < 0) {
+ fprintf(stderr, "Unable to open backing device %s\n", backing_path);
+ return -1;
+ }
+
+ while (1) {
+ struct dm_user_message msg;
+ char* base;
+ __u64 type;
+
+ if (verbose) std::cerr << "dmuserd: Waiting for message...\n";
+
+ if (read_all(control_fd, &msg, sizeof(msg)) < 0) {
+ if (errno == ENOTBLK) return 0;
+
+ perror("unable to read msg");
+ return -1;
+ }
+
+ if (verbose) {
+ std::string type;
+ switch (msg.type) {
+ case DM_USER_REQ_MAP_WRITE:
+ type = "write";
+ break;
+ case DM_USER_REQ_MAP_READ:
+ type = "read";
+ break;
+ case DM_USER_REQ_MAP_FLUSH:
+ type = "flush";
+ break;
+ default:
+ /*
+ * FIXME: Can't I do "whatever"s here rather that
+ * std::string("whatever")?
+ */
+ type = std::string("(unknown, id=") + std::to_string(msg.type) + ")";
+ break;
+ }
+
+ std::string flags;
+ if (msg.flags & DM_USER_REQ_MAP_FLAG_SYNC) {
+ if (!flags.empty()) flags += "|";
+ flags += "S";
+ }
+ if (msg.flags & DM_USER_REQ_MAP_FLAG_META) {
+ if (!flags.empty()) flags += "|";
+ flags += "M";
+ }
+ if (msg.flags & DM_USER_REQ_MAP_FLAG_FUA) {
+ if (!flags.empty()) flags += "|";
+ flags += "FUA";
+ }
+ if (msg.flags & DM_USER_REQ_MAP_FLAG_PREFLUSH) {
+ if (!flags.empty()) flags += "|";
+ flags += "F";
+ }
+
+ std::cerr << "dmuserd: Got " << type << " request " << flags << " for sector "
+ << std::to_string(msg.sector) << " with length " << std::to_string(msg.len)
+ << "\n";
+ }
+
+ type = msg.type;
+ switch (type) {
+ case DM_USER_REQ_MAP_READ:
+ msg.type = DM_USER_RESP_SUCCESS;
+ break;
+ case DM_USER_REQ_MAP_WRITE:
+ if (msg.flags & DM_USER_REQ_MAP_FLAG_PREFLUSH ||
+ msg.flags & DM_USER_REQ_MAP_FLAG_FUA) {
+ if (fsync(backing_fd) < 0) {
+ perror("Unable to fsync(), just sync()ing instead");
+ sync();
+ }
+ }
+ msg.type = DM_USER_RESP_SUCCESS;
+ if (lseek64(backing_fd, msg.sector * SECTOR_SIZE, SEEK_SET) < 0) {
+ perror("Unable to seek");
+ return -1;
+ }
+ if (not_splice(control_fd, backing_fd, msg.len) < 0) {
+ if (errno == ENOTBLK) return 0;
+ std::cerr << "unable to handle write data\n";
+ return -1;
+ }
+ if (msg.flags & DM_USER_REQ_MAP_FLAG_FUA) {
+ if (fsync(backing_fd) < 0) {
+ perror("Unable to fsync(), just sync()ing instead");
+ sync();
+ }
+ }
+ break;
+ case DM_USER_REQ_MAP_FLUSH:
+ msg.type = DM_USER_RESP_SUCCESS;
+ if (fsync(backing_fd) < 0) {
+ perror("Unable to fsync(), just sync()ing instead");
+ sync();
+ }
+ break;
+ default:
+ std::cerr << "dmuserd: unsupported op " << std::to_string(msg.type) << "\n";
+ msg.type = DM_USER_RESP_UNSUPPORTED;
+ break;
+ }
+
+ if (verbose) std::cerr << "dmuserd: Responding to message\n";
+
+ if (write_all(control_fd, &msg, sizeof(msg)) < 0) {
+ if (errno == ENOTBLK) return 0;
+ perror("unable to write msg");
+ return -1;
+ }
+
+ switch (type) {
+ case DM_USER_REQ_MAP_READ:
+ if (verbose) std::cerr << "dmuserd: Sending read data\n";
+ if (lseek64(backing_fd, msg.sector * SECTOR_SIZE, SEEK_SET) < 0) {
+ perror("Unable to seek");
+ return -1;
+ }
+ if (not_splice(backing_fd, control_fd, msg.len) < 0) {
+ if (errno == ENOTBLK) return 0;
+ std::cerr << "unable to handle read data\n";
+ return -1;
+ }
+ break;
+ }
+ }
+
+ /* The daemon doesn't actully terminate for this test. */
+ perror("Unable to read from control device");
+ return -1;
+}
+
+void usage(char* prog) {
+ printf("Usage: %s\n", prog);
+ printf(" Handles block requests in userspace, backed by memory\n");
+ printf(" -h Display this help message\n");
+ printf(" -c <control dev> Control device to use for the test\n");
+ printf(" -b <store path> The file to use as a backing store, otherwise memory\n");
+ printf(" -v Enable verbose mode\n");
+}
+
+int main(int argc, char* argv[]) {
+ char* control_path = NULL;
+ char* backing_path = NULL;
+ char* store;
+ int c;
+
+ prctl(PR_SET_IO_FLUSHER, 0, 0, 0, 0);
+
+ while ((c = getopt(argc, argv, "h:c:s:b:v")) != -1) {
+ switch (c) {
+ case 'h':
+ usage(basename(argv[0]));
+ exit(0);
+ case 'c':
+ control_path = strdup(optarg);
+ break;
+ case 'b':
+ backing_path = strdup(optarg);
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ default:
+ usage(basename(argv[0]));
+ exit(1);
+ }
+ }
+
+ int r = simple_daemon(control_path, backing_path);
+ if (r) fprintf(stderr, "simple_daemon() errored out\n");
+ return r;
+}
diff --git a/init/devices.cpp b/init/devices.cpp
index f8eb16a..5888c06 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -440,13 +440,6 @@
}
}
unlink(devpath.c_str());
-
- if (android::base::StartsWith(devpath, "/dev/dm-user/")) {
- std::error_code ec;
- if (std::filesystem::is_empty("/dev/dm-user/", ec)) {
- rmdir("/dev/dm-user");
- }
- }
}
}
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index 843ac5c..91aaffd 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -221,6 +221,7 @@
CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
CHECKCALL(mkdir("/dev/pts", 0755));
CHECKCALL(mkdir("/dev/socket", 0755));
+ CHECKCALL(mkdir("/dev/dm-user", 0755));
CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
#define MAKE_STR(x) __STRING(x)
CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 5a0255a..f03ca6b 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -534,6 +534,7 @@
selinux_android_restorecon("/dev/__properties__", 0);
selinux_android_restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
+ selinux_android_restorecon("/dev/dm-user", SELINUX_ANDROID_RESTORECON_RECURSE);
selinux_android_restorecon("/dev/device-mapper", 0);
selinux_android_restorecon("/apex", 0);
diff --git a/rootdir/avb/Android.mk b/rootdir/avb/Android.mk
index 9892ae7..c8fc1d6 100644
--- a/rootdir/avb/Android.mk
+++ b/rootdir/avb/Android.mk
@@ -1,11 +1,17 @@
LOCAL_PATH:= $(call my-dir)
-ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
- my_gsi_avb_keys_path := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/avb
-else ifeq ($(BOARD_MOVE_GSI_AVB_KEYS_TO_VENDOR_BOOT),true)
- my_gsi_avb_keys_path := $(TARGET_VENDOR_RAMDISK_OUT)/avb
+ifeq ($(BOARD_MOVE_GSI_AVB_KEYS_TO_VENDOR_BOOT),true) # AVB keys are installed to vendor ramdisk
+ ifeq ($(BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT),true) # no dedicated recovery partition
+ my_gsi_avb_keys_path := $(TARGET_VENDOR_RAMDISK_OUT)/first_stage_ramdisk/avb
+ else # device has a dedicated recovery partition
+ my_gsi_avb_keys_path := $(TARGET_VENDOR_RAMDISK_OUT)/avb
+ endif
else
- my_gsi_avb_keys_path := $(TARGET_RAMDISK_OUT)/avb
+ ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true) # no dedicated recovery partition
+ my_gsi_avb_keys_path := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/avb
+ else # device has a dedicated recovery partition
+ my_gsi_avb_keys_path := $(TARGET_RAMDISK_OUT)/avb
+ endif
endif
#######################################
diff --git a/toolbox/start.cpp b/toolbox/start.cpp
index cffb89c..46314cf 100644
--- a/toolbox/start.cpp
+++ b/toolbox/start.cpp
@@ -37,7 +37,6 @@
static void ControlDefaultServices(bool start) {
std::vector<std::string> services = {
- "iorapd",
"netd",
"surfaceflinger",
"audioserver",
@@ -92,4 +91,4 @@
extern "C" int stop_main(int argc, char** argv) {
return StartStop(argc, argv, false);
-}
\ No newline at end of file
+}