blob: b54fd46b49bcf20c79bf9ff895bcb79e57542dcd [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.
#ifndef SRC_STORAGE_F2FS_COMMON_H_
#define SRC_STORAGE_F2FS_COMMON_H_
#include <lib/fit/function.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/trace/event.h>
#include <lib/zircon-internal/thread_annotations.h>
#include <lib/zx/result.h>
#include <sys/types.h>
#include <zircon/assert.h>
#include <zircon/compiler.h>
#include <zircon/errors.h>
#include <zircon/types.h>
#include <fbl/macros.h>
#include <fbl/no_destructor.h>
#include <fbl/ref_ptr.h>
#include <safemath/checked_math.h>
#include "src/storage/lib/vfs/cpp/fuchsia_vfs.h"
#include "src/storage/lib/vfs/cpp/paged_vfs.h"
namespace f2fs {
class VnodeF2fs;
using block_t = uint32_t;
using f2fs_hash_t = uint32_t;
using nid_t = uint32_t;
using ino_t = uint32_t;
using pgoff_t = uint64_t;
using umode_t = uint16_t;
using VnodeCallback = fit::function<zx_status_t(fbl::RefPtr<VnodeF2fs> &)>;
using SyncCallback = fs::Vnode::SyncCallback;
// A async_dispatcher_t* is needed for some functions on Fuchsia only. In order to avoid ifdefs on
// every call that is compiled for host Fuchsia and Host, we define this as a nullptr_t type when
// compiling on host where callers should pass null and it's ignored.
//
// Prefer async_dispatcher_t* for Fuchsia-specific functions since it makes the intent more clear.
using FuchsiaDispatcher = async_dispatcher_t *;
// A reference to the vfs is needed for some functions. The specific vfs type is different between
// Fuchsia and Host, so define a PlatformVfs which represents the one for our current platform to
// avoid ifdefs on every call.
//
// Prefer using the appropriate vfs when the function is only used for one or the other.
using PlatformVfs = fs::PagedVfs;
#if BYTE_ORDER == BIG_ENDIAN
inline uint16_t LeToCpu(uint16_t x) { return SWAP_16(x); }
inline uint32_t LeToCpu(uint32_t x) { return SWAP_32(x); }
inline uint64_t LeToCpu(uint64_t x) { return SWAP_64(x); }
inline uint16_t CpuToLe(uint16_t x) { return SWAP_16(x); }
inline uint32_t CpuToLe(uint32_t x) { return SWAP_32(x); }
inline uint64_t CpuToLe(uint64_t x) { return SWAP_64(x); }
#else
inline uint16_t LeToCpu(uint16_t x) { return x; }
inline uint32_t LeToCpu(uint32_t x) { return x; }
inline uint64_t LeToCpu(uint64_t x) { return x; }
inline uint16_t CpuToLe(uint16_t x) { return x; }
inline uint32_t CpuToLe(uint32_t x) { return x; }
inline uint64_t CpuToLe(uint64_t x) { return x; }
#endif
constexpr uint32_t kPageSize = PAGE_SIZE;
constexpr size_t kNumCheckpointHeaderBlocks = 2;
constexpr uint32_t kBitsPerByte = 8;
constexpr uint32_t kShiftForBitSize = 3;
constexpr uint32_t kF2fsSuperMagic = 0xF2F52010;
constexpr uint32_t kCrcPolyLe = 0xedb88320;
constexpr size_t kWriteTimeOut = 60; // in seconds
constexpr uint32_t kBlockSize = 4096; // F2fs block size in byte
constexpr block_t kNullAddr = 0x0U;
constexpr block_t kNewAddr = -1U;
// For INODE and NODE manager
constexpr int kXattrNodeOffset = -1;
// store xattrs to one node block per
// file keeping -1 as its node offset to
// distinguish from index node blocks.
constexpr int kLinkMax = 32000; // maximum link count per file
// For readahead
constexpr block_t kMaxReadaheadSize = 128;
constexpr block_t kDefaultNodeReadSize = 16;
// Checkpoint
inline bool VerAfter(uint64_t a, uint64_t b) { return a > b; }
inline bool IsValidBlockAddr(block_t addr) { return addr != kNullAddr && addr != kNewAddr; }
// CRC
inline uint32_t F2fsCalCrc32(uint32_t crc, void *buff, uint32_t len) {
unsigned char *p = static_cast<unsigned char *>(buff);
while (len-- > 0) {
crc ^= *p++;
for (int i = 0; i < 8; ++i)
crc = (crc >> 1) ^ ((crc & 1) ? kCrcPolyLe : 0);
}
return crc;
}
inline uint32_t F2fsCrc32(void *buff, uint32_t len) {
return F2fsCalCrc32(kF2fsSuperMagic, static_cast<unsigned char *>(buff), len);
}
inline bool F2fsCrcValid(uint32_t blk_crc, void *buff, uint32_t buff_size) {
return F2fsCrc32(buff, buff_size) == blk_crc;
}
inline bool IsDotOrDotDot(std::string_view name) { return (name == "." || name == ".."); }
template <typename T>
inline T CheckedDivRoundUp(const T n, const T d) {
return safemath::CheckDiv<T>(fbl::round_up(n, d), d).ValueOrDie();
}
// The below are the page types.
// The available types are:
// kData User data pages. It operates as async mode.
// kNode Node pages. It operates as async mode.
// kMeta FS metadata pages such as SIT, NAT, CP.
// kNrPageType The number of page types.
// kMetaFlush Make sure the previous pages are written
// with waiting the bio's completion
// ... Only can be used with META.
enum class PageType {
kData = 0,
kNode,
kMeta,
kNrPageType,
kMetaFlush,
};
template <typename T = uint8_t>
class BlockBuffer {
public:
BlockBuffer(BlockBuffer &&block) = delete;
BlockBuffer &operator=(BlockBuffer &&block) = delete;
BlockBuffer() {
Allocate();
std::memset(data_, 0, kBlockSize);
}
BlockBuffer(const BlockBuffer &block) {
Allocate();
std::memcpy(data_, block.get(), kBlockSize);
}
BlockBuffer &operator=(const BlockBuffer &block) {
std::memcpy(data_, block.get(), kBlockSize);
return *this;
}
~BlockBuffer() {
if (!data_)
return;
std::free(data_);
}
template <typename U = void>
U *get() {
return static_cast<U *>(data_);
}
template <typename U = void>
const U *get() const {
return static_cast<U *>(data_);
}
T *operator->() { return get<T>(); }
const T *operator->() const { return get<T>(); }
T *operator&() { return get<T>(); }
const T *operator&() const { return get<T>(); }
T &operator*() { return *get<T>(); }
const T &operator*() const { return *get<T>(); }
private:
void Allocate() {
if (data_)
return;
data_ = std::aligned_alloc(kBlockSize, kBlockSize);
}
void *data_ = nullptr;
};
// It should be acquired in shared mode before any operations modifying data and metadata (i.e.,
// data, node and meta blocks). GC and checkpoint acquire it exclusively.
inline std::shared_mutex &GetGlobalLock() {
static fbl::NoDestructor<std::shared_mutex> global_lock;
return *global_lock;
}
} // namespace f2fs
#endif // SRC_STORAGE_F2FS_COMMON_H_