blob: 96757301f8de654b67b781693dd84a6b04af2b57 [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 THIRD_PARTY_F2FS_F2FS_H_
#define THIRD_PARTY_F2FS_F2FS_H_
// clang-format off
#include <lib/zircon-internal/fnv1hash.h>
#include <lib/zircon-internal/thread_annotations.h>
#include <zircon/assert.h>
#include <zircon/device/vfs.h>
#include <zircon/errors.h>
#include <zircon/listnode.h>
#include <zircon/types.h>
#include <lib/syslog/cpp/macros.h>
#include <iostream>
#include <fbl/algorithm.h>
#include <fbl/auto_lock.h>
#include <fbl/condition_variable.h>
#include <fbl/function.h>
#include <fbl/intrusive_wavl_tree.h>
#include <fbl/intrusive_double_list.h>
#include <fbl/macros.h>
#include <fbl/mutex.h>
#include <fbl/ref_ptr.h>
#include <sys/stat.h>
#include "src/lib/storage/vfs/cpp/managed_vfs.h"
#include "src/lib/storage/vfs/cpp/vfs.h"
#include "src/lib/storage/vfs/cpp/vnode.h"
#include "src/lib/storage/vfs/cpp/watcher.h"
#include "f2fs_types.h"
#include "f2fs_lib.h"
#include "f2fs_layout.h"
#include "f2fs_internal.h"
#include "namestring.h"
#include "bcache.h"
#include "vnode.h"
#include "dir.h"
#include "file.h"
#include "vnode_cache.h"
#include "node.h"
#include "segment.h"
#include "mkfs.h"
#include "mount.h"
#include "fsck.h"
// clang-format on
namespace f2fs {
enum class ServeLayout {
// The root of the filesystem is exposed directly.
kDataRootOnly,
// Expose a pseudo-directory with the filesystem root located at "svc/root".
// TODO(fxbug.dev/34531): Also expose an administration service under "svc/fuchsia.fs.Admin".
kExportDirectory
};
zx_status_t LoadSuperblock(f2fs::Bcache *bc, SuperBlock *out_info);
zx_status_t LoadSuperblock(f2fs::Bcache *bc, SuperBlock *out_info, block_t bno);
zx::status<std::unique_ptr<F2fs>> CreateFsAndRoot(const MountOptions &mount_options,
async_dispatcher_t *dispatcher,
std::unique_ptr<f2fs::Bcache> bcache,
zx::channel mount_channel,
fbl::Closure on_unmount,
ServeLayout serve_layout);
using SyncCallback = fs::Vnode::SyncCallback;
class F2fs : public fs::ManagedVfs {
public:
// Not copyable or moveable
F2fs(const F2fs &) = delete;
F2fs &operator=(const F2fs &) = delete;
F2fs(F2fs &&) = delete;
F2fs &operator=(F2fs &&) = delete;
explicit F2fs(std::unique_ptr<f2fs::Bcache> bc, SuperBlock *sb,
const MountOptions &mount_options);
~F2fs() override;
[[nodiscard]] static zx_status_t Create(std::unique_ptr<f2fs::Bcache> bc,
const MountOptions &options, std::unique_ptr<F2fs> *out);
inline void InsertVnode(VnodeF2fs *vn) { __UNUSED zx_status_t status = vnode_cache_.Add(vn); }
inline void EvictVnode(VnodeF2fs *vn) { __UNUSED zx_status_t status = vnode_cache_.Evict(vn); }
inline zx_status_t LookupVnode(ino_t ino, fbl::RefPtr<VnodeF2fs> *out) {
return vnode_cache_.Lookup(ino, out);
}
void GetNodeInfo(nid_t nid, NodeInfo *ni);
void SetUnmountCallback(fbl::Closure closure) { on_unmount_ = std::move(closure); }
void Shutdown(fs::Vfs::ShutdownCallback cb) final;
// TODO(unknown): non-public member variables
std::unique_ptr<f2fs::Bcache> bc_;
SuperBlock &RawSb() { return *raw_sb_; }
SbInfo &GetSbInfo() { return *sbi_; }
SegMgr &Segmgr() { return *seg_mgr_; }
NodeMgr &Nodemgr() { return *node_mgr_; }
uint64_t FsId() const { return fs_id_; }
#if 0 // porting needed
// void InitOnce(void *foo);
// VnodeF2fs *F2fsAllocInode();
// static void F2fsICallback(rcu_head *head);
// void F2fsDestroyInode(inode *inode);
#endif
void PutSuper();
zx_status_t SyncFs(int sync);
#if 0 // porting needed
// int F2fsStatfs(dentry *dentry /*, kstatfs *buf*/);
// int F2fsShowOptions(/*seq_file *seq*/);
// VnodeF2fs *F2fsNfsGetInode(uint64_t ino, uint32_t generation);
// dentry *F2fsFhToDentry(fid *fid, int fh_len, int fh_type);
// dentry *F2fsFhToParent(fid *fid, int fh_len, int fh_type);
#endif
loff_t MaxFileSize(unsigned bits);
int SanityCheckRawSuper();
int SanityCheckCkpt();
void InitSbInfo();
zx_status_t FillSuper();
void ParseOptions();
#if 0 // porting needed
// dentry *F2fsMount(file_system_type *fs_type, int flags,
// const char *dev_name, void *data);
// int InitInodecache(void);
// void DestroyInodecache(void);
// int /*__init*/ initF2fsFs(void);
// void /*__exit*/ exitF2fsFs(void);
#endif
// checkpoint.cc
Page *GetMetaPage(pgoff_t index);
Page *GrabMetaPage(pgoff_t index);
zx_status_t F2fsWriteMetaPage(Page *page, WritebackControl *wbc);
#if 0 // porting needed
// int F2fsWriteMetaPages(address_space *mapping, WritebackControl *wbc);
#endif
int64_t SyncMetaPages(PageType type, long nr_to_write);
#if 0 // porting needed
// int F2fsSetMetaPageDirty(Page *page);
#endif
zx_status_t CheckOrphanSpace();
void AddOrphanInode(VnodeF2fs *vnode);
void AddOrphanInode(nid_t ino);
void RemoveOrphanInode(nid_t ino);
void RecoverOrphanInode(nid_t ino);
int RecoverOrphanInodes();
void WriteOrphanInodes(block_t start_blk);
zx_status_t GetValidCheckpoint();
Page *ValidateCheckpoint(block_t cp_addr, uint64_t *version);
#if 0 // porting needed
// void SetDirtyDirPage(VnodeF2fs *vnode, Page *page);
// void RemoveDirtyDirInode(VnodeF2fs *vnode);
#endif
void SyncDirtyDirInodes();
void BlockOperations();
void UnblockOperations();
void DoCheckpoint(bool is_umount);
void WriteCheckpoint(bool blocked, bool is_umount);
void InitOrphanInfo();
#if 0 // porting needed
int CreateCheckpointCaches();
void DestroyCheckpointCaches();
#endif
// recovery.cc
bool SpaceForRollForward();
FsyncInodeEntry *GetFsyncInode(list_node_t *head, nid_t ino);
zx_status_t RecoverDentry(Page *ipage, VnodeF2fs *vnode);
zx_status_t RecoverInode(VnodeF2fs *inode, Page *node_page);
zx_status_t FindFsyncDnodes(list_node_t *head);
void DestroyFsyncDnodes(list_node_t *head);
void CheckIndexInPrevNodes(block_t blkaddr);
void DoRecoverData(VnodeF2fs *inode, Page *page, block_t blkaddr);
void RecoverData(list_node_t *head, CursegType type);
void RecoverFsyncData();
// block count
void DecValidBlockCount(VnodeF2fs *vnode, block_t count);
zx_status_t IncValidBlockCount(VnodeF2fs *vnode, block_t count);
void CheckNidRange(const nid_t &nid);
VnodeCache &GetVCache() { return vnode_cache_; }
private:
fbl::RefPtr<VnodeF2fs> root_vnode_;
fbl::Closure on_unmount_{};
MountOptions mount_options_;
std::unique_ptr<SuperBlock> raw_sb_;
std::unique_ptr<SbInfo> sbi_;
std::unique_ptr<SegMgr> seg_mgr_;
std::unique_ptr<NodeMgr> node_mgr_;
VnodeCache vnode_cache_{};
uint64_t fs_id_ = 0;
};
f2fs_hash_t DentryHash(const char *name, int len);
zx_status_t FlushDirtyNodePage(F2fs *fs, Page *page);
zx_status_t FlushDirtyMetaPage(F2fs *fs, Page *page);
zx_status_t FlushDirtyDataPage(F2fs *fs, Page *page);
} // namespace f2fs
#endif // THIRD_PARTY_F2FS_F2FS_H_