blob: d4ca0c418a3a18e05af90ce47b0bd4879d06e1ce [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.
#ifndef SRC_STORAGE_MINFS_SUPERBLOCK_H_
#define SRC_STORAGE_MINFS_SUPERBLOCK_H_
#include <cstdint>
#include <memory>
#include <fbl/macros.h>
#include "src/storage/minfs/format.h"
#include "src/storage/minfs/fsck.h"
#include "src/storage/minfs/minfs.h"
#include "src/storage/minfs/pending_work.h"
#ifdef __Fuchsia__
#include <lib/fzl/owned-vmo-mapper.h>
#include <lib/zx/vmo.h>
#include <block-client/cpp/block-device.h>
#endif
namespace minfs {
// SuperblockManager contains all filesystem-global metadata.
//
// It also contains mechanisms for updating this information
// on persistent storage. Although these fields may be
// updated from multiple threads (and |Write| may be invoked
// to push a snapshot of the superblock to persistent storage),
// caution should be taken to avoid Writing a snapshot of the
// superblock to disk while another thread has only partially
// updated the superblock.
#ifdef __Fuchsia__
class SuperblockManager {
public:
SuperblockManager() = delete;
// Not copyable or movable
SuperblockManager(const SuperblockManager&) = delete;
SuperblockManager& operator=(const SuperblockManager&) = delete;
SuperblockManager(SuperblockManager&&) = delete;
SuperblockManager& operator=(SuperblockManager&&) = delete;
~SuperblockManager();
static zx_status_t Create(block_client::BlockDevice* device, const Superblock* info,
uint32_t max_blocks, IntegrityCheck checks,
std::unique_ptr<SuperblockManager>* out);
bool is_dirty() const { return dirty_; }
const Superblock& Info() const { return *reinterpret_cast<const Superblock*>(mapping_.start()); }
uint32_t BlockSize() const {
// Either intentionally or unintenttionally, we do not want to change block
// size to anything other than kMinfsBlockSize yet. This is because changing
// block size might lead to format change and also because anything other
// than 8k is not well tested. So assert when we find block size other
// than 8k.
ZX_ASSERT(Info().BlockSize() == kMinfsBlockSize);
return Info().BlockSize();
}
// Acquire a pointer to the superblock, such that any
// modifications will be carried out to persistent storage
// the next time "Write" is invoked.
Superblock* MutableInfo() {
dirty_ = true;
return reinterpret_cast<Superblock*>(mapping_.start());
}
// Write the superblock/backup superblock back to persistent storage at respective locations.
// If write_backup is kUpdate, also update the backup superblock.
void Write(PendingWork* transaction, UpdateBackupSuperblock write_backup);
private:
SuperblockManager(const Superblock* info, fzl::OwnedVmoMapper mapper);
fzl::OwnedVmoMapper mapping_;
bool dirty_ = false;
};
#else // __Fuchsia__
class SuperblockManager {
public:
SuperblockManager() = delete;
// Not copyable or movable
SuperblockManager(const SuperblockManager&) = delete;
SuperblockManager& operator=(const SuperblockManager&) = delete;
SuperblockManager(SuperblockManager&&) = delete;
SuperblockManager& operator=(SuperblockManager&&) = delete;
~SuperblockManager();
static zx_status_t Create(const Superblock* info, uint32_t max_blocks, IntegrityCheck checks,
std::unique_ptr<SuperblockManager>* out);
bool is_dirty() const { return dirty_; }
const Superblock& Info() const { return *reinterpret_cast<const Superblock*>(&info_blk_[0]); }
uint32_t BlockSize() const {
// Either intentionally or unintenttionally, we do not want to change block
// size to anything other than kMinfsBlockSize yet. This is because changing
// block size might lead to format change and also because anything other
// than 8k is not well tested. So assert when we find block size other
// than 8k.
ZX_ASSERT(Info().BlockSize() == kMinfsBlockSize);
return Info().BlockSize();
}
// Acquire a pointer to the superblock, such that any
// modifications will be carried out to persistent storage
// the next time "Write" is invoked.
Superblock* MutableInfo() {
dirty_ = true;
return reinterpret_cast<Superblock*>(&info_blk_[0]);
}
// Write the superblock/backup superblock back to persistent storage at respective locations.
// If write_backup is kUpdate, also update the backup superblock.
void Write(PendingWork* transaction, UpdateBackupSuperblock write_backup);
private:
SuperblockManager(const Superblock* info);
uint8_t info_blk_[kMinfsBlockSize];
bool dirty_ = false;
};
#endif
} // namespace minfs
#endif // SRC_STORAGE_MINFS_SUPERBLOCK_H_