| // 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_ |