blob: c8edf225672e236e8552d90bb6bbd875b314983c [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 <iostream>
#include <fbl/algorithm.h>
#include <fbl/auto_lock.h>
#include <fbl/function.h>
#include <fbl/intrusive_hash_table.h>
#include <fbl/intrusive_single_list.h>
#include <fbl/macros.h>
#include <fbl/mutex.h>
#include <fbl/ref_ptr.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 "bcache.h"
#include "vnode.h"
#include "dir.h"
#include "file.h"
#include "node.h"
#include "segment.h"
#include "mkfs.h"
// clang-format on
namespace f2fs {
struct MountOptions {
bool background_gc = false;
bool disable_roll_forward = true;
bool discard = false;
bool noheap = true;
bool xattr_user = false;
bool posix_acl = false;
bool disable_ext_identify = true;
uint32_t active_logs = 6;
};
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 Mkfs(const MkfsOptions &options, std::unique_ptr<f2fs::Bcache> bc);
zx_status_t Fsck(const MountOptions &options, std::unique_ptr<f2fs::Bcache> bc);
zx_status_t Mount(const MountOptions &options, std::unique_ptr<f2fs::Bcache> bc);
zx_status_t CreateBcache(std::unique_ptr<block_client::BlockDevice> device, bool *out_readonly,
std::unique_ptr<f2fs::Bcache> *out);
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);
void InsertVnode(VnodeF2fs *vn);
void EraseVnodeFromTable(VnodeF2fs *vn);
zx_status_t FindVnode(fbl::RefPtr<VnodeF2fs> *out, ino_t ino);
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);
// int ParseOptions(char *options);
#endif
loff_t MaxFileSize(unsigned bits);
int SanityCheckRawSuper();
int SanityCheckCkpt();
void InitSbInfo();
zx_status_t FillSuper();
#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(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();
private:
using HashTable = fbl::HashTable<ino_t, VnodeF2fs *>;
fbl::Mutex vnode_table_lock_;
HashTable vnode_table_ __TA_GUARDED(vnode_table_lock_){};
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_;
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_