blob: 0725c7597eed7fe1ff9b2612c7c6fdaf37660c6c [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.
#include <string.h>
#include <sys/stat.h>
#include "f2fs.h"
namespace f2fs {
void F2fs::PutSuper() {
#if 0 // porting needed
// DestroyStats(sbi_.get());
// StopGcThread(sbi_.get());
#endif
WriteCheckpoint(false, true);
GetVCache().Reset();
#if 0 // porting needed
// Iput(sbi_->node_inode);
// Iput(sbi_->meta_inode);
#endif
/* destroy f2fs internal modules */
node_mgr_->DestroyNodeManager();
seg_mgr_->DestroySegmentManager();
delete sbi_->ckpt;
#if 0 // porting needed
// brelse(sbi_->raw_super_buf);
#endif
node_mgr_.reset();
seg_mgr_.reset();
raw_sb_.reset();
sbi_.reset();
}
zx_status_t F2fs::SyncFs(int sync) {
#ifdef F2FS_BU_DEBUG
FX_LOGS(DEBUG) << "F2fs::SyncFs, sbi_->s_dirty=" << sbi_->s_dirty;
#endif
#if 0 // porting needed
//if (!sbi_->s_dirty && !GetPages(sbi_.get(), CountType::kDirtyNodes))
// return 0;
#endif
if (sync)
WriteCheckpoint(false, false);
return ZX_OK;
}
#if 0 // porting needed
// int F2fs::F2fsStatfs(dentry *dentry /*, kstatfs *buf*/) {
// super_block *sb = dentry->d_sb;
// SbInfo *sbi = F2FS_SB(sb);
// u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
// block_t total_count, user_block_count, start_count, ovp_count;
// total_count = LeToCpu(sbi->raw_super->block_count);
// user_block_count = sbi->user_block_count;
// start_count = LeToCpu(sbi->raw_super->segment0_blkaddr);
// ovp_count = GetSmInfo(sbi)->ovp_segments << sbi->log_blocks_per_seg;
// buf->f_type = kF2fsSuperMagic;
// buf->f_bsize = sbi->blocksize;
// buf->f_blocks = total_count - start_count;
// buf->f_bfree = buf->f_blocks - ValidUserBlocks(sbi) - ovp_count;
// buf->f_bavail = user_block_count - ValidUserBlocks(sbi);
// buf->f_files = ValidInodeCount(sbi);
// buf->f_ffree = sbi->total_node_count - ValidNodeCount(sbi);
// buf->f_namelen = kMaxNameLen;
// buf->f_fsid.val[0] = (u32)id;
// buf->f_fsid.val[1] = (u32)(id >> 32);
// return 0;
// }
// VnodeF2fs *F2fs::F2fsNfsGetInode(uint64_t ino, uint32_t generation) {
// fbl::RefPtr<VnodeF2fs> vnode_refptr;
// VnodeF2fs *vnode = nullptr;
// int err;
// if (ino < RootIno(sbi_.get()))
// return (VnodeF2fs *)ErrPtr(-ESTALE);
// /*
// * f2fs_iget isn't quite right if the inode is currently unallocated!
// * However f2fs_iget currently does appropriate checks to handle stale
// * inodes so everything is OK.
// */
// err = VnodeF2fs::Vget(this, ino, &vnode_refptr);
// if (err)
// return (VnodeF2fs *)ErrPtr(err);
// vnode = vnode_refptr.get();
// if (generation && vnode->i_generation != generation) {
// /* we didn't find the right inode.. */
// Iput(vnode);
// return (VnodeF2fs *)ErrPtr(-ESTALE);
// }
// return vnode;
// }
// struct fid {};
// dentry *F2fs::F2fsFhToDentry(fid *fid, int fh_len, int fh_type) {
// return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
// f2fs_nfs_get_inode);
// }
// dentry *F2fs::F2fsFhToParent(fid *fid, int fh_len, int fh_type) {
// return generic_fh_to_parent(sb, fid, fh_len, fh_type,
// f2fs_nfs_get_inode);
// }
#endif
void F2fs::ParseOptions() {
for (uint32_t i = 0; i < kOptMaxNum; i++) {
uint32_t value;
if (mount_options_.GetValue(i, &value) == ZX_OK) {
switch (i) {
case kOptActiveLogs:
sbi_->active_logs = value;
break;
case kOptDiscard:
if (value)
SetOpt(sbi_.get(), kMountDiscard);
break;
case kOptBgGcOff:
if (value)
SetOpt(sbi_.get(), kMountBgGcOff);
break;
case kOptNoHeap:
if (value)
SetOpt(sbi_.get(), kMountNoheap);
break;
case kOptDisableExtIdentify:
if (value)
SetOpt(sbi_.get(), kMountDisableExtIdentify);
break;
case kOptNoUserXAttr:
if (value)
SetOpt(sbi_.get(), kMountNoXAttr);
break;
case kOptNoAcl:
if (value)
SetOpt(sbi_.get(), kMountNoAcl);
break;
case kOptDisableRollForward:
if (value)
SetOpt(sbi_.get(), kMountDisableRollForward);
break;
case kOptInlineXattr:
if (value)
SetOpt(sbi_.get(), kMountInlineXattr);
break;
case kOptInlineData:
if (value)
SetOpt(sbi_.get(), kMountInlineData);
break;
case kOptInlineDentry:
if (value)
SetOpt(sbi_.get(), kMountInlineDentry);
break;
default:
FX_LOGS(WARNING) << mount_options_.GetNameView(i) << " is not supported.";
break;
};
}
}
}
loff_t F2fs::MaxFileSize(unsigned bits) {
loff_t result = kAddrsPerInode;
loff_t leaf_count = kAddrsPerBlock;
/* two direct node blocks */
result += (leaf_count * 2);
/* two indirect node blocks */
leaf_count *= kNidsPerBlock;
result += (leaf_count * 2);
/* one double indirect node block */
leaf_count *= kNidsPerBlock;
result += leaf_count;
result <<= bits;
return result;
}
int F2fs::SanityCheckRawSuper() {
unsigned int blocksize;
if (kF2fsSuperMagic != LeToCpu(raw_sb_->magic))
return 1;
/* Currently, support only 4KB block size */
blocksize = 1 << LeToCpu(raw_sb_->log_blocksize);
if (blocksize != kPageCacheSize)
return 1;
if (LeToCpu(raw_sb_->log_sectorsize) != kLogSectorSize)
return 1;
if (LeToCpu(raw_sb_->log_sectors_per_block) != kLogSectorsPerBlock)
return 1;
return 0;
}
int F2fs::SanityCheckCkpt() {
unsigned int total, fsmeta;
total = LeToCpu(raw_sb_->segment_count);
fsmeta = LeToCpu(raw_sb_->segment_count_ckpt);
fsmeta += LeToCpu(raw_sb_->segment_count_sit);
fsmeta += LeToCpu(raw_sb_->segment_count_nat);
fsmeta += LeToCpu(sbi_->ckpt->rsvd_segment_count);
fsmeta += LeToCpu(raw_sb_->segment_count_ssa);
if (fsmeta >= total)
return 1;
return 0;
}
void F2fs::InitSbInfo() {
int i;
sbi_->log_sectors_per_block = LeToCpu(RawSb().log_sectors_per_block);
sbi_->log_blocksize = LeToCpu(RawSb().log_blocksize);
sbi_->blocksize = 1 << sbi_->log_blocksize;
sbi_->log_blocks_per_seg = LeToCpu(RawSb().log_blocks_per_seg);
sbi_->blocks_per_seg = 1 << sbi_->log_blocks_per_seg;
sbi_->segs_per_sec = LeToCpu(RawSb().segs_per_sec);
sbi_->secs_per_zone = LeToCpu(RawSb().secs_per_zone);
sbi_->total_sections = LeToCpu(RawSb().section_count);
sbi_->total_node_count =
(LeToCpu(RawSb().segment_count_nat) / 2) * sbi_->blocks_per_seg * kNatEntryPerBlock;
sbi_->root_ino_num = LeToCpu(RawSb().root_ino);
sbi_->node_ino_num = LeToCpu(RawSb().node_ino);
sbi_->meta_ino_num = LeToCpu(RawSb().meta_ino);
for (i = 0; i < static_cast<int>(CountType::kNrCountType); i++)
AtomicSet(&sbi_->nr_pages[i], 0);
}
zx_status_t F2fs::FillSuper() {
#if 0 // porting needed
// SuperBlock *raw_super;
// buffer_head *raw_super_buf = NULL;
#endif
VnodeF2fs *root;
zx_status_t err = ZX_ERR_INVALID_ARGS;
/* allocate memory for f2fs-specific super block info */
sbi_ = std::make_unique<SbInfo>();
if (!sbi_)
return ZX_ERR_NO_MEMORY;
memset(sbi_.get(), 0, sizeof(SbInfo));
#if 0 // porting needed
// super_block *sb = sbi_->sb;
/* set a temporary block size */
// if (!SbSetBlocksize(sb, kBlockSize))
// goto free_sbi;
#endif
ParseOptions();
/* sanity checking of raw super */
if (SanityCheckRawSuper())
goto free_sb_buf;
#if 0 // porting needed
// sb->s_maxbytes = MaxFileSize(RawSb().log_blocksize);
// sb->s_max_links = kLinkMax;
// For NFS support
// get_random_bytes(&sbi->s_next_generation, sizeof(uint32_t));
// sb->s_op = &f2fs_sops;
// sb->s_xattr = f2fs_xattr_handlers;
// sb->s_export_op = &f2fs_export_ops;
// sb->s_magic = kF2fsSuperMagic;
// sb->s_fs_info = sbi_.get();
// sb->s_time_gran = 1;
// sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
// (TestOpt(sbi_.get(), kMountPosixAcl) ? MS_POSIXACL : 0);
// memcpy(&sb->s_uuid, RawSb().uuid, sizeof(RawSb().uuid));
/* init f2fs-specific super block info */
// sbi->sb = sb;
#endif
sbi_->raw_super = raw_sb_.get();
#if 0 // porting needed
// sbi_->raw_super_buf = raw_super_buf;
#endif
sbi_->por_doing = 0;
#if 0 // porting needed
// init_rwsem(&sbi->bio_sem);
#endif
InitSbInfo();
/* get an inode for meta space */
#if 0 // porting needed
// err = VnodeF2fs::Vget(this, MetaIno(sbi_), &sbi_->meta_vnode);
// if (err) {
// goto free_sb_buf;
// }
#endif
err = GetValidCheckpoint();
if (err)
goto free_meta_inode;
/* sanity checking of checkpoint */
err = ZX_ERR_INVALID_ARGS;
if (SanityCheckCkpt())
goto free_cp;
sbi_->total_valid_node_count = LeToCpu(sbi_->ckpt->valid_node_count);
sbi_->total_valid_inode_count = LeToCpu(sbi_->ckpt->valid_inode_count);
sbi_->user_block_count = LeToCpu(sbi_->ckpt->user_block_count);
sbi_->total_valid_block_count = LeToCpu(sbi_->ckpt->valid_block_count);
sbi_->last_valid_block_count = sbi_->total_valid_block_count;
sbi_->alloc_valid_block_count = 0;
list_initialize(&sbi_->dir_inode_list);
/* init super block */
#if 0 // porting needed
// if (!SbSetBlocksize(sb, sbi_->blocksize))
// goto free_cp;
#endif
InitOrphanInfo();
/* setup f2fs internal modules */
seg_mgr_ = std::make_unique<SegMgr>(this);
err = seg_mgr_->BuildSegmentManager();
if (err)
goto free_sm;
node_mgr_ = std::make_unique<NodeMgr>(this);
err = node_mgr_->BuildNodeManager();
if (err)
goto free_nm;
#if 0 // porting needed
// BuildGcManager(sbi);
/* get an inode for node space */
// err = VnodeF2fs::Vget(this, NodeIno(sbi_), &sbi_->node_vnode);
// if (err) {
// goto free_nm;
// }
#endif
/* if there are nt orphan nodes free them */
err = ZX_ERR_INVALID_ARGS;
if (RecoverOrphanInodes() != ZX_OK)
goto free_node_inode;
/* read root inode and dentry */
err = VnodeF2fs::Vget(this, RootIno(sbi_.get()), &root_vnode_);
if (err) {
goto free_node_inode;
}
root = root_vnode_.get();
if (!root->IsDir() || !root->GetBlocks() || !root->GetSize())
goto free_root_inode;
#if 0 // porting needed
// sb->s_root = DMakeRoot(root); /* allocate root dentry */
// if (!sb->s_root) {
// err = ZX_ERR_NO_MEMORY;
// goto free_root_inode;
// }
#endif
// try to recover fsynced data every mount time
if (!TestOpt(sbi_.get(), kMountDisableRollForward)) {
RecoverFsyncData();
}
#if 0 // porting needed
/* After POR, we can run background GC thread */
// err = StartGcThread(sbi);
// if (err)
// goto fail;
// err = BuildStats(sbi_.get());
// if (err)
// goto fail;
#endif
return ZX_OK;
#if 0 // porting needed
fail:
// StopGcThread(sbi);
#endif
free_root_inode:
#if 0 // porting needed
// dput(sb->s_root);
// sb->s_root = NULL;
#endif
free_node_inode:
#if 0 // porting needed
// Iput(sbi_->node_inode);
#endif
free_nm:
node_mgr_->DestroyNodeManager();
node_mgr_.reset();
free_sm:
seg_mgr_->DestroySegmentManager();
seg_mgr_.reset();
free_cp:
delete sbi_->ckpt;
free_meta_inode:
#if 0 // porting needed
// MakeBadInode(sbi_->meta_inode);
// Iput(sbi_->meta_inode);
#endif
free_sb_buf:
#if 0 // porting needed
// brelse(raw_super_buf);
// free_sbi:
#endif
sbi_.reset();
return err;
}
} // namespace f2fs