blob: fecb25d4d21dfbe7e13e2090ea028e7b14033e5f [file] [log] [blame]
// Copyright 2018 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 <blobfs/journal.h>
#include <fbl/unique_ptr.h>
#include <lib/cksum.h>
#include <zircon/types.h>
#include <utility>
namespace blobfs {
JournalEntry::JournalEntry(JournalBase* journal, EntryStatus status, size_t header_index,
size_t commit_index, fbl::unique_ptr<WritebackWork> work)
: journal_(journal), status_(static_cast<uint32_t>(status)), block_count_(0),
header_index_(header_index), commit_index_(commit_index), work_(std::move(work)) {
if (status != EntryStatus::kInit) {
// In the case of a sync request or error, return early.
ZX_DEBUG_ASSERT(status == EntryStatus::kSync || status == EntryStatus::kError);
return;
}
size_t work_blocks = work_->BlkCount();
// Ensure the work is valid.
ZX_DEBUG_ASSERT(work_blocks > 0);
ZX_DEBUG_ASSERT(work_->IsBuffered());
ZX_DEBUG_ASSERT(work_blocks <= kMaxEntryDataBlocks);
// Copy all target blocks from the WritebackWork to the entry's header block.
for (size_t i = 0; i < work_->Requests().size(); i++) {
WriteRequest& request = work_->Requests()[i];
for (size_t j = request.dev_offset; j < request.dev_offset + request.length; j++) {
header_block_.target_blocks[block_count_++] = j;
}
}
ZX_DEBUG_ASSERT(work_blocks == block_count_);
// Set other information in the header/commit blocks.
header_block_.magic = kEntryHeaderMagic;
header_block_.num_blocks = block_count_;
header_block_.timestamp = zx_ticks_get();
commit_block_.magic = kEntryCommitMagic;
commit_block_.timestamp = header_block_.timestamp;
commit_block_.checksum = 0;
}
fbl::unique_ptr<WritebackWork> JournalEntry::TakeWork() {
ZX_DEBUG_ASSERT(work_ != nullptr);
if (header_index_ != commit_index_) {
// If the journal entry contains any transactions, set the work closure to update the entry
// status on write completion. This currently assumes that a WritebackWork with associated
// transactions will NOT already have a closure attached. If we ever want to include
// transactions on a syncing WritebackWork, we will need to revisit this.
work_->SetSyncCallback(CreateSyncCallback());
}
return std::move(work_);
}
ReadyCallback JournalEntry::CreateReadyCallback() {
return [this] () {
// If the entry is in a waiting state, it is ready to be written to disk.
return GetStatus() == EntryStatus::kWaiting;
};
}
SyncCallback JournalEntry::CreateSyncCallback() {
return [this] (zx_status_t result) {
// Signal the journal that an entry is ready for processing.
journal_->ProcessEntryResult(result, this);
};
}
void JournalEntry::SetStatusFromResult(zx_status_t result) {
// Set the state of the JournalEntry based on the last received result.
if (result != ZX_OK) {
SetStatus(EntryStatus::kError);
return;
}
EntryStatus last_status = SetStatus(EntryStatus::kPersisted);
ZX_DEBUG_ASSERT(last_status == EntryStatus::kWaiting);
}
void JournalEntry::SetChecksum(uint32_t checksum) {
commit_block_.checksum = checksum;
}
} // blobfs