snapuserd: API to query snapshot and merge status

Add new API to query the snapshot and merge status.
This will be used by libsnapshot.

Bug: 193863443
Test: Full OTA on CF
Signed-off-by: Akilesh Kailash <akailash@google.com>
Change-Id: I86cffff6a979e2e2bf1d8d1a1770e209eeb4a47d
This commit is contained in:
Akilesh Kailash 2021-10-02 11:24:36 +00:00
parent ff590a806c
commit b94353cae0
6 changed files with 95 additions and 0 deletions

View file

@ -85,6 +85,9 @@ class SnapuserdClient {
// Returns Merge completion percentage
double GetMergePercent();
// Return the status of the snapshot
std::string QuerySnapshotStatus(const std::string& misc_name);
};
} // namespace snapshot

View file

@ -252,5 +252,14 @@ double SnapuserdClient::GetMergePercent() {
return std::stod(response);
}
std::string SnapuserdClient::QuerySnapshotStatus(const std::string& misc_name) {
std::string msg = "getstatus," + misc_name;
if (!Sendmsg(msg)) {
LOG(ERROR) << "Failed to send message " << msg << " to snapuserd";
return "snapshot-merge-failed";
}
return Receivemsg();
}
} // namespace snapshot
} // namespace android

View file

@ -268,6 +268,8 @@ class SnapshotHandler : public std::enable_shared_from_this<SnapshotHandler> {
bool ShouldReconstructDataFromCow() { return populate_data_from_cow_; }
void FinishReconstructDataFromCow() { populate_data_from_cow_ = false; }
// Return the snapshot status
std::string GetMergeStatus();
// RA related functions
uint64_t GetBufferMetadataOffset();

View file

@ -54,6 +54,7 @@ DaemonOps SnapuserServer::Resolveop(std::string& input) {
if (input == "supports") return DaemonOps::SUPPORTS;
if (input == "initiate_merge") return DaemonOps::INITIATE;
if (input == "merge_percent") return DaemonOps::PERCENTAGE;
if (input == "getstatus") return DaemonOps::GETSTATUS;
return DaemonOps::INVALID;
}
@ -262,6 +263,25 @@ bool SnapuserServer::Receivemsg(android::base::borrowed_fd fd, const std::string
return Sendmsg(fd, std::to_string(percentage));
}
case DaemonOps::GETSTATUS: {
// Message format:
// getstatus,<misc_name>
if (out.size() != 2) {
LOG(ERROR) << "Malformed delete message, " << out.size() << " parts";
return Sendmsg(fd, "snapshot-merge-failed");
}
{
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, "snapshot-merge-failed");
}
std::string merge_status = GetMergeStatus(*iter);
return Sendmsg(fd, merge_status);
}
}
default: {
LOG(ERROR) << "Received unknown message type from client";
Sendmsg(fd, "fail");
@ -513,6 +533,10 @@ void SnapuserServer::TerminateMergeThreads(std::lock_guard<std::mutex>* proof_of
}
}
std::string SnapuserServer::GetMergeStatus(const std::shared_ptr<DmUserHandler>& handler) {
return handler->snapuserd()->GetMergeStatus();
}
double SnapuserServer::GetMergePercentage(std::lock_guard<std::mutex>* proof_of_lock) {
CHECK(proof_of_lock);
double percentage = 0.0;

View file

@ -45,6 +45,7 @@ enum class DaemonOps {
SUPPORTS,
INITIATE,
PERCENTAGE,
GETSTATUS,
INVALID,
};
@ -131,6 +132,7 @@ class SnapuserServer {
const std::string& base_path_merge);
bool StartHandler(const std::shared_ptr<DmUserHandler>& handler);
bool StartMerge(const std::shared_ptr<DmUserHandler>& handler);
std::string GetMergeStatus(const std::shared_ptr<DmUserHandler>& handler);
void SetTerminating() { terminating_ = true; }
void ReceivedSocketSignal() { received_socket_signal_ = true; }

View file

@ -359,6 +359,61 @@ void SnapshotHandler::WaitForMergeComplete() {
}
}
std::string SnapshotHandler::GetMergeStatus() {
bool merge_not_initiated = false;
bool merge_failed = false;
{
std::lock_guard<std::mutex> lock(lock_);
if (!MergeInitiated()) {
merge_not_initiated = true;
}
if (io_state_ == MERGE_IO_TRANSITION::MERGE_FAILED) {
merge_failed = true;
}
}
struct CowHeader* ch = reinterpret_cast<struct CowHeader*>(mapped_addr_);
bool merge_complete = (ch->num_merge_ops == reader_->get_num_total_data_ops());
if (merge_not_initiated) {
// Merge was not initiated yet; however, we have merge completion
// recorded in the COW Header. This can happen if the device was
// rebooted during merge. During next reboot, libsnapshot will
// query the status and if the merge is completed, then snapshot-status
// file will be deleted
if (merge_complete) {
return "snapshot-merge-complete";
}
// Return the state as "snapshot". If the device was rebooted during
// merge, we will return the status as "snapshot". This is ok, as
// libsnapshot will explicitly resume the merge. This is slightly
// different from kernel snapshot wherein once the snapshot was switched
// to merge target, during next boot, we immediately switch to merge
// target. We don't do that here because, during first stage init, we
// don't want to initiate the merge. The problem is that we have daemon
// transition between first and second stage init. If the merge was
// started, then we will have to quiesce the merge before switching
// the dm tables. Instead, we just wait until second stage daemon is up
// before resuming the merge.
return "snapshot";
}
if (merge_failed) {
return "snapshot-merge-failed";
}
// Merge complete
if (merge_complete) {
return "snapshot-merge-complete";
}
// Merge is in-progress
return "snapshot-merge";
}
//========== End of Read-ahead state transition functions ====================
/*