blob: a86065daa3d1c9aa9135af1d9e3eb48c15d6952e [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/storage/blobfs/service/health_check.h"
#include <fidl/fuchsia.update.verify/cpp/wire.h>
#include <lib/async/dispatcher.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/channel.h>
#include <fbl/ref_ptr.h>
#include "src/storage/blobfs/blob.h"
#include "src/storage/blobfs/cache_node.h"
#include "src/storage/lib/vfs/cpp/service.h"
#include "zircon/errors.h"
namespace fuv = fuchsia_update_verify;
namespace blobfs {
HealthCheckService::HealthCheckService(async_dispatcher_t* dispatcher, Blobfs& blobfs)
: fs::Service(
[dispatcher, this](fidl::ServerEnd<fuchsia_update_verify::BlobfsVerifier> server_end) {
fidl::BindServer(dispatcher, std::move(server_end), this);
return ZX_OK;
}),
blobfs_(blobfs) {}
void HealthCheckService::Verify(VerifyRequestView request, VerifyCompleter::Sync& completer) {
constexpr size_t kMaxBytesToVerify{static_cast<size_t>(1024) * 1024};
size_t bytes_verified = 0;
zx_status_t status = blobfs_.GetCache().ForAllOpenNodes([&](fbl::RefPtr<CacheNode> node) {
auto blob = fbl::RefPtr<Blob>::Downcast(std::move(node));
if (blob->DeletionQueued()) {
// Skip blobs that are scheduled for deletion.
return ZX_OK;
}
if (blob->FileSize() == 0) {
// Skip the null blob, or blobs which aren't in the readable state.
return ZX_OK;
}
// If we run multithreaded, the blob cound transition to deleted between the above
// DeletionQueued() check and this Verify() call. That should be OK as it only means we check a
// blob that we didn't need to. If we need 100% correctness, we'll need to add a
// Blob::VerifyIfNotDeleted() function that can atomically check and verify.
if (zx_status_t status = blob->Verify(); status != ZX_OK) {
FX_LOGS(ERROR) << "Detected corrupted blob " << blob->digest();
return ZX_ERR_IO_DATA_INTEGRITY;
}
bytes_verified += blob->FileSize();
if (bytes_verified >= kMaxBytesToVerify) {
return ZX_ERR_STOP;
}
return ZX_OK;
});
if (status == ZX_OK) {
completer.ReplySuccess();
} else {
completer.ReplyError(fuv::wire::VerifyError::kInternal);
}
}
} // namespace blobfs