[f2fs] Clean up fs_lock
It removes unnecessary fs_locks except for two.
Those are enough for blocking file operations
and keeping writes in order during checkpoint.
Test: f2fs-fs-tests f2fs-slow-fs-tests f2fs-unittest
Change-Id: I8278ec4d6983a75775744a86e896d4eeffd9dd7f
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/f2fs/+/568641
Reviewed-by: Brett Wilson <brettw@google.com>
diff --git a/admin.h b/admin.h
index beebf15..45eaa72 100644
--- a/admin.h
+++ b/admin.h
@@ -7,8 +7,6 @@
namespace f2fs {
-class F2fs;
-
class AdminService final : public fidl::WireServer<fuchsia_fs::Admin>, public fs::Service {
public:
AdminService(async_dispatcher_t* dispatcher, F2fs* f2fs);
diff --git a/checkpoint.cc b/checkpoint.cc
index 7c4cbc9..4c02787 100644
--- a/checkpoint.cc
+++ b/checkpoint.cc
@@ -571,7 +571,6 @@
*/
void F2fs::BlockOperations() TA_NO_THREAD_SAFETY_ANALYSIS {
SbInfo &sbi = GetSbInfo();
- int t;
struct WritebackControl wbc = {
#if 0 // porting needed
// .nr_to_write = LONG_MAX,
@@ -581,46 +580,34 @@
#endif
};
- /* Stop renaming operation */
- mutex_lock_op(&sbi, LockType::kRename);
- mutex_lock_op(&sbi, LockType::kDentryOps);
-
retry_dents:
- /* write all the dirty dentry pages */
+ // write all the dirty dentry pages
SyncDirtyDirInodes();
- mutex_lock_op(&sbi, LockType::kDataWrtie);
+ // Stop file operation
+ mutex_lock_op(&sbi, LockType::kFileOp);
if (GetPages(&sbi, CountType::kDirtyDents)) {
- mutex_unlock_op(&sbi, LockType::kDataWrtie);
+ mutex_unlock_op(&sbi, LockType::kFileOp);
goto retry_dents;
}
- /* block all the operations */
- for (t = static_cast<int>(LockType::kDataNew); t <= static_cast<int>(LockType::kNodeTrunc); t++)
- mutex_lock_op(&sbi, static_cast<LockType>(t));
-
- fbl::AutoLock write_inode(&sbi.write_inode);
-
- /*
- * POR: we should ensure that there is no dirty node pages
- * until finishing nat/sit flush.
- */
+ // POR: we should ensure that there is no dirty node pages
+ // until finishing nat/sit flush.
retry:
Nodemgr().SyncNodePages(0, &wbc);
- mutex_lock_op(&sbi, LockType::kNodeWrite);
+ mutex_lock_op(&sbi, LockType::kNodeOp);
if (GetPages(&sbi, CountType::kDirtyNodes)) {
- mutex_unlock_op(&sbi, LockType::kNodeWrite);
+ mutex_unlock_op(&sbi, LockType::kNodeOp);
goto retry;
}
}
void F2fs::UnblockOperations() TA_NO_THREAD_SAFETY_ANALYSIS {
SbInfo &sbi = GetSbInfo();
- int t;
- for (t = static_cast<int>(LockType::kNodeWrite); t >= static_cast<int>(LockType::kRename); t--)
- mutex_unlock_op(&sbi, static_cast<LockType>(t));
+ mutex_unlock_op(&sbi, LockType::kNodeOp);
+ mutex_unlock_op(&sbi, LockType::kFileOp);
}
void F2fs::DoCheckpoint(bool is_umount) {
diff --git a/data.cc b/data.cc
index a57b10c..5938411 100644
--- a/data.cc
+++ b/data.cc
@@ -516,7 +516,7 @@
#endif
do {
- fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kDataWrtie)]);
+ fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kFileOp)]);
if (IsDir()) {
DecPageCount(&sbi, CountType::kDirtyDents);
#if 0 // porting needed
@@ -601,10 +601,9 @@
return ZX_ERR_NO_MEMORY;
#endif
+ fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kFileOp)]);
+ std::lock_guard write_lock(io_lock_);
do {
- fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kDataNew)]);
- std::lock_guard write_lock(io_lock_);
-
SetNewDnode(&dn, this, NULL, NULL, 0);
if (zx_status_t err = Vfs()->Nodemgr().GetDnodeOfData(&dn, index, 0); err != ZX_OK) {
F2fsPutPage(*pagep, 1);
diff --git a/dir.cc b/dir.cc
index 627a9a0..71f92a0 100644
--- a/dir.cc
+++ b/dir.cc
@@ -207,9 +207,6 @@
}
void Dir::SetLink(DirEntry *de, Page *page, VnodeF2fs *vnode) {
- SbInfo &sbi = Vfs()->GetSbInfo();
-
- fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kDentryOps)]);
std::lock_guard write_lock(io_lock_);
#if 0 // porting needed
// lock_page(page);
@@ -356,7 +353,6 @@
f2fs_hash_t dentry_hash;
DirEntry *de;
unsigned int nbucket, nblock;
- SbInfo &sbi = Vfs()->GetSbInfo();
int namelen = name.length();
Page *dentry_page = nullptr;
DentryBlock *dentry_blk = nullptr;
@@ -366,7 +362,6 @@
if (TestFlag(InodeInfoFlag::kInlineDentry)) {
bool is_converted = false;
- fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kDentryOps)]);
std::lock_guard write_lock(io_lock_);
if (err = AddInlineEntry(name, vnode, &is_converted); err != ZX_OK)
return err;
@@ -397,63 +392,56 @@
bidx = DirBlockIndex(level, (dentry_hash % nbucket));
for (block = bidx; block <= (bidx + nblock - 1); block++) {
- fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kDentryOps)]);
std::lock_guard write_lock(io_lock_);
if (err = GetNewDataPage(block, true, &dentry_page); err != ZX_OK) {
return err;
}
-#if 0 // porting needed
+ // porting needed
// dentry_blk = kmap(dentry_page);
-#else
dentry_blk = reinterpret_cast<DentryBlock *>(dentry_page->data);
-#endif
bit_pos = RoomForFilename(dentry_blk, slots);
if (bit_pos < kNrDentryInBlock) {
-#if 0 // porting needed
- // if (err = InitInodeMetadata(vnode, dentry); err == ZX_OK) {
-#else
+ // porting needed
+ // if (err = InitInodeMetadata(vnode, dentry); err == ZX_OK) {
if (err = InitInodeMetadata(vnode); err == ZX_OK) {
-#endif
- WaitOnPageWriteback(dentry_page);
+ WaitOnPageWriteback(dentry_page);
- de = &dentry_blk->dentry[bit_pos];
- de->hash_code = CpuToLe(dentry_hash);
- de->name_len = CpuToLe(static_cast<uint16_t>(namelen));
- memcpy(dentry_blk->filename[bit_pos], name.data(), namelen);
- de->ino = CpuToLe(vnode->Ino());
- SetDeType(de, vnode);
- for (i = 0; i < slots; i++)
- test_and_set_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap);
+ de = &dentry_blk->dentry[bit_pos];
+ de->hash_code = CpuToLe(dentry_hash);
+ de->name_len = CpuToLe(static_cast<uint16_t>(namelen));
+ memcpy(dentry_blk->filename[bit_pos], name.data(), namelen);
+ de->ino = CpuToLe(vnode->Ino());
+ SetDeType(de, vnode);
+ for (i = 0; i < slots; i++)
+ test_and_set_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap);
#if 0 // porting needed
// set_page_dirty(dentry_page);
#else
FlushDirtyDataPage(Vfs(), dentry_page);
#endif
- UpdateParentMetadata(vnode, current_depth);
+ UpdateParentMetadata(vnode, current_depth);
+ }
+
+ if (TestFlag(InodeInfoFlag::kUpdateDir)) {
+ WriteInode(nullptr);
+ ClearFlag(InodeInfoFlag::kUpdateDir);
+ }
+
+ // porting needed
+ // kunmap(dentry_page);
+ F2fsPutPage(dentry_page, 1);
+ return err;
}
- if (TestFlag(InodeInfoFlag::kUpdateDir)) {
- WriteInode(nullptr);
- ClearFlag(InodeInfoFlag::kUpdateDir);
- }
-
-#if 0 // porting needed
- // kunmap(dentry_page);
-#endif
+ // porting needed
+ // kunmap(dentry_page);
F2fsPutPage(dentry_page, 1);
- return err;
}
-#if 0 // porting needed
- // kunmap(dentry_page);
-#endif
- F2fsPutPage(dentry_page, 1);
+ /* Move to next level to find the empty slot for new dentry */
+ ++level;
}
-
- /* Move to next level to find the empty slot for new dentry */
- ++level;
-}
}
/**
@@ -471,7 +459,6 @@
void *kaddr = PageAddress(page);
int i;
- fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kDentryOps)]);
std::lock_guard write_lock(io_lock_);
if (TestFlag(InodeInfoFlag::kInlineDentry)) {
diff --git a/dir.h b/dir.h
index 1b6059e..e2a97aa 100644
--- a/dir.h
+++ b/dir.h
@@ -42,72 +42,73 @@
// Required for memory management, see the class comment above Vnode for more.
void fbl_recycle() { RecycleNode(); }
+ // Lookup
zx_status_t Lookup(std::string_view name, fbl::RefPtr<fs::Vnode> *out) final;
+ zx_status_t DoLookup(std::string_view name, fbl::RefPtr<fs::Vnode> *out);
+ DirEntry *FindEntry(std::string_view name, Page **res_page) __TA_EXCLUDES(io_lock_);
+ DirEntry *FindInInlineDir(const std::string_view &name, Page **res_page);
+ DirEntry *FindInBlock(Page *dentry_page, const char *name, int namelen, int *max_slots,
+ f2fs_hash_t namehash, Page **res_page);
+ DirEntry *FindInLevel(unsigned int level, std::string_view name, int namelen,
+ f2fs_hash_t namehash, Page **res_page);
zx_status_t Readdir(fs::VdirCookie *cookie, void *dirents, size_t len, size_t *out_actual) final
__TA_EXCLUDES(io_lock_);
- zx_status_t Create(std::string_view name, uint32_t mode, fbl::RefPtr<fs::Vnode> *out) final;
- zx_status_t Link(std::string_view name, fbl::RefPtr<fs::Vnode> _target) final;
- zx_status_t Unlink(std::string_view name, bool must_be_dir) final;
+ zx_status_t ReadInlineDir(fs::VdirCookie *cookie, void *dirents, size_t len, size_t *out_actual);
+
+ // delete & set link
zx_status_t Rename(fbl::RefPtr<fs::Vnode> _newdir, std::string_view oldname,
std::string_view newname, bool src_must_be_dir, bool dst_must_be_dir);
+ void SetLink(DirEntry *de, Page *page, VnodeF2fs *inode) __TA_EXCLUDES(io_lock_)
+ __TA_EXCLUDES(io_lock_);
+ DirEntry *ParentDir(Page **p);
+ DirEntry *ParentInlineDir(Page **p);
+ bool IsEmptyDir();
+ bool IsEmptyInlineDir();
+ zx::status<bool> IsSubdir(Dir *possible_dir);
+ // create
+ zx_status_t Link(std::string_view name, fbl::RefPtr<fs::Vnode> _target) final;
+ zx_status_t Create(std::string_view name, uint32_t mode, fbl::RefPtr<fs::Vnode> *out) final;
+ zx_status_t DoCreate(std::string_view name, uint32_t mode, fbl::RefPtr<fs::Vnode> *out);
+ zx_status_t NewInode(uint32_t mode, fbl::RefPtr<VnodeF2fs> *out);
+ zx_status_t Mkdir(std::string_view name, uint32_t mode, fbl::RefPtr<fs::Vnode> *out);
+ zx_status_t AddLink(std::string_view name, VnodeF2fs *vnode) __TA_EXCLUDES(io_lock_)
+ __TA_EXCLUDES(io_lock_);
+ zx_status_t AddInlineEntry(std::string_view name, VnodeF2fs *vnode, bool *is_converted);
+ unsigned int RoomInInlineDir(InlineDentry *dentry_blk, int slots);
+ zx_status_t ConvertInlineDir(InlineDentry *inline_dentry);
+ int RoomForFilename(DentryBlock *dentry_blk, int slots);
+ void UpdateParentMetadata(VnodeF2fs *inode, unsigned int current_depth);
+ zx_status_t InitInodeMetadata(VnodeF2fs *vnode);
+ zx_status_t MakeEmpty(VnodeF2fs *vnode, VnodeF2fs *parent);
+ zx_status_t MakeEmptyInlineDir(VnodeF2fs *vnode, VnodeF2fs *parent);
+ void InitDentInode(VnodeF2fs *vnode, Page *ipage);
+
+ // delete
+ zx_status_t Unlink(std::string_view name, bool must_be_dir) final;
+ zx_status_t Rmdir(Dir *vnode, std::string_view name);
+ zx_status_t DoUnlink(VnodeF2fs *vnode, std::string_view name);
+ void DeleteEntry(DirEntry *dentry, Page *page, VnodeF2fs *vnode) __TA_EXCLUDES(io_lock_)
+ __TA_EXCLUDES(io_lock_);
+ void DeleteInlineEntry(DirEntry *dentry, Page *page, VnodeF2fs *vnode);
+
+ // helper
+ ino_t InodeByName(std::string_view name);
+ int IsMultimediaFile(const char *s, const char *sub);
+ void SetColdFile(const char *name, VnodeF2fs *vnode);
uint64_t DirBlocks();
static unsigned int DirBuckets(unsigned int level);
static unsigned int BucketBlocks(unsigned int level);
void SetDeType(DirEntry *de, VnodeF2fs *vnode);
static uint64_t DirBlockIndex(unsigned int level, unsigned int idx);
bool EarlyMatchName(const char *name, int namelen, f2fs_hash_t namehash, DirEntry *de);
- DirEntry *FindInBlock(Page *dentry_page, const char *name, int namelen, int *max_slots,
- f2fs_hash_t namehash, Page **res_page);
- DirEntry *FindInLevel(unsigned int level, std::string_view name, int namelen,
- f2fs_hash_t namehash, Page **res_page);
- DirEntry *FindEntry(std::string_view name, Page **res_page) __TA_EXCLUDES(io_lock_);
- DirEntry *ParentDir(Page **p);
- ino_t InodeByName(std::string_view name);
- void SetLink(DirEntry *de, Page *page, VnodeF2fs *inode) __TA_EXCLUDES(io_lock_);
- void InitDentInode(VnodeF2fs *vnode, Page *ipage);
-#if 0 // porting needed
- // zx_status_t InitInodeMetadata(VnodeF2fs *vnode, dentry *dentry);
-#else
- zx_status_t InitInodeMetadata(VnodeF2fs *vnode);
-#endif
- void UpdateParentMetadata(VnodeF2fs *inode, unsigned int current_depth);
- int RoomForFilename(DentryBlock *dentry_blk, int slots);
- zx_status_t AddLink(std::string_view name, VnodeF2fs *vnode) __TA_EXCLUDES(io_lock_);
- void DeleteEntry(DirEntry *dentry, Page *page, VnodeF2fs *vnode) __TA_EXCLUDES(io_lock_);
- zx_status_t MakeEmpty(VnodeF2fs *vnode, VnodeF2fs *parent);
- bool IsEmptyDir();
- zx_status_t NewInode(uint32_t mode, fbl::RefPtr<VnodeF2fs> *out);
- int IsMultimediaFile(const char *s, const char *sub);
- void SetColdFile(const char *name, VnodeF2fs *vnode);
- zx_status_t DoCreate(std::string_view name, uint32_t mode, fbl::RefPtr<fs::Vnode> *out);
#if 0 // porting needed
// int F2fsLink(dentry *old_dentry, dentry *dentry);
// dentry *F2fsGetParent(dentry *child);
-#endif
- zx_status_t DoUnlink(VnodeF2fs *vnode, std::string_view name);
-#if 0 // porting needed
// int F2fsSymlink(dentry *dentry, const char *symname);
-#endif
- zx_status_t Mkdir(std::string_view name, uint32_t mode, fbl::RefPtr<fs::Vnode> *out);
- zx_status_t Rmdir(Dir *vnode, std::string_view name);
-#if 0 // porting needed
// int F2fsMknod(dentry *dentry, umode_t mode, dev_t rdev);
#endif
- zx_status_t DoLookup(std::string_view name, fbl::RefPtr<fs::Vnode> *out);
- // Check if possible_child is its subdir
- zx::status<bool> IsSubdir(Dir *possible_dir);
-
- DirEntry *FindInInlineDir(const std::string_view &name, Page **res_page);
- DirEntry *ParentInlineDir(Page **p);
- zx_status_t MakeEmptyInlineDir(VnodeF2fs *vnode, VnodeF2fs *parent);
- unsigned int RoomInInlineDir(InlineDentry *dentry_blk, int slots);
- zx_status_t ConvertInlineDir(InlineDentry *inline_dentry);
- zx_status_t AddInlineEntry(std::string_view name, VnodeF2fs *vnode, bool *is_converted);
- void DeleteInlineEntry(DirEntry *dentry, Page *page, VnodeF2fs *vnode);
- bool IsEmptyInlineDir();
- zx_status_t ReadInlineDir(fs::VdirCookie *cookie, void *dirents, size_t len, size_t *out_actual);
};
} // namespace f2fs
diff --git a/f2fs.h b/f2fs.h
index 056b677..6b79972 100644
--- a/f2fs.h
+++ b/f2fs.h
@@ -39,7 +39,6 @@
#include "src/lib/storage/vfs/cpp/shared_mutex.h"
#include "src/lib/storage/vfs/cpp/service.h"
-#include "admin.h"
#include "f2fs_types.h"
#include "f2fs_lib.h"
#include "f2fs_layout.h"
@@ -51,11 +50,12 @@
#include "file.h"
#include "vnode_cache.h"
#include "node.h"
-#include "query.h"
#include "segment.h"
#include "mkfs.h"
#include "mount.h"
#include "fsck.h"
+#include "admin.h"
+#include "query.h"
// clang-format on
namespace f2fs {
diff --git a/f2fs_internal.h b/f2fs_internal.h
index 4aaeb7a..52c9824 100644
--- a/f2fs_internal.h
+++ b/f2fs_internal.h
@@ -210,20 +210,11 @@
kNrCountType,
};
-// FS_LOCK nesting subclasses for the lock validator:
-//
// The locking order between these classes is
-// LockType::kRename -> LockType::kDentryOps -> LockType::kDataWrtie -> LockType::kDataNew
-// -> LockType::kDataTrunc -> LockType::kNodeWrite -> LockType::kNodeNew -> LockType::kNodeTrunc
+// LockType::FileOp -> LockType::kNodeOp
enum class LockType {
- kRename = 0, // for renaming operations
- kDentryOps, // for directory operations
- kDataWrtie, // for data write
- kDataNew, // for data allocation
- kDataTrunc, // for data truncate
- kNodeNew, // for node allocation
- kNodeTrunc, // for node truncate
- kNodeWrite, // for node write
+ kFileOp, // for file op
+ kNodeOp, // for node op
kNrLockType,
};
@@ -267,7 +258,6 @@
fbl::RefPtr<VnodeF2fs> meta_vnode;
fbl::Mutex cp_mutex; // for checkpoint procedure
fs::SharedMutex fs_lock[static_cast<int>(LockType::kNrLockType)]; // for blocking FS operations
- fbl::Mutex write_inode; // mutex for write inode
fbl::Mutex writepages; // mutex for writepages()
int por_doing = 0; // recovery is doing or not
@@ -352,8 +342,6 @@
static inline void mutex_lock_op(SbInfo *sbi, LockType t)
TA_ACQ(&sbi->fs_lock[static_cast<int>(t)]) {
- // TODO: Too many locks.
- // It seems that two locks (node/io) are enough to sync between cp and io path.
sbi->fs_lock[static_cast<int>(t)].lock();
}
diff --git a/namei.cc b/namei.cc
index 4be5915..8b0c28e 100644
--- a/namei.cc
+++ b/namei.cc
@@ -15,7 +15,7 @@
VnodeF2fs *vnode = nullptr;
do {
- fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kNodeNew)]);
+ fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kFileOp)]);
if (!Vfs()->Nodemgr().AllocNid(&ino)) {
Iput(vnode);
return ZX_ERR_NO_SPACE;
@@ -109,12 +109,15 @@
SetColdFile(name.data(), vnode);
vnode->SetFlag(InodeInfoFlag::kIncLink);
- if (zx_status_t err = AddLink(name, vnode); err != ZX_OK) {
- vnode->ClearNlink();
- vnode->UnlockNewInode();
- Iput(vnode);
- Vfs()->Nodemgr().AllocNidFailed(vnode->Ino());
- return err;
+ {
+ fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kFileOp)]);
+ if (zx_status_t err = AddLink(name, vnode); err != ZX_OK) {
+ vnode->ClearNlink();
+ vnode->UnlockNewInode();
+ Iput(vnode);
+ Vfs()->Nodemgr().AllocNidFailed(vnode->Ino());
+ return err;
+ }
}
Vfs()->Nodemgr().AllocNidDone(vnode->Ino());
@@ -152,12 +155,15 @@
#if 0 // porting needed
// AtomicInc(&inode->i_count);
#endif
-
- target->SetFlag(InodeInfoFlag::kIncLink);
- if (zx_status_t err = AddLink(name, target); err != ZX_OK) {
- target->ClearFlag(InodeInfoFlag::kIncLink);
- Iput(target);
- return err;
+ {
+ SbInfo &sbi = Vfs()->GetSbInfo();
+ fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kFileOp)]);
+ target->SetFlag(InodeInfoFlag::kIncLink);
+ if (zx_status_t err = AddLink(name, target); err != ZX_OK) {
+ target->ClearFlag(InodeInfoFlag::kIncLink);
+ Iput(target);
+ return err;
+ }
}
#if 0 // porting needed
@@ -221,16 +227,20 @@
return ZX_ERR_NOT_FOUND;
}
- if (zx_status_t err = Vfs()->CheckOrphanSpace(); err != ZX_OK) {
+ {
+ SbInfo &sbi = Vfs()->GetSbInfo();
+ fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kFileOp)]);
+ if (zx_status_t err = Vfs()->CheckOrphanSpace(); err != ZX_OK) {
#if 0 // porting needed
// if (!f2fs_has_inline_dentry(dir))
// kunmap(page);
#endif
- F2fsPutPage(page, 0);
- return err;
- }
+ F2fsPutPage(page, 0);
+ return err;
+ }
- DeleteEntry(de, page, vnode);
+ DeleteEntry(de, page, vnode);
+ }
Vfs()->Segmgr().BalanceFs();
@@ -289,15 +299,18 @@
#endif
vnode->SetFlag(InodeInfoFlag::kIncLink);
- if (zx_status_t err = AddLink(name, vnode); err != ZX_OK) {
- vnode->ClearFlag(InodeInfoFlag::kIncLink);
- vnode->ClearNlink();
- vnode->UnlockNewInode();
- Iput(vnode);
- Vfs()->Nodemgr().AllocNidFailed(vnode->Ino());
- return err;
+ {
+ SbInfo &sbi = Vfs()->GetSbInfo();
+ fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kFileOp)]);
+ if (zx_status_t err = AddLink(name, vnode); err != ZX_OK) {
+ vnode->ClearFlag(InodeInfoFlag::kIncLink);
+ vnode->ClearNlink();
+ vnode->UnlockNewInode();
+ Iput(vnode);
+ Vfs()->Nodemgr().AllocNidFailed(vnode->Ino());
+ return err;
+ }
}
-
Vfs()->Nodemgr().AllocNidDone(vnode->Ino());
#if 0 // porting needed
@@ -434,7 +447,7 @@
}
do {
- fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kRename)]);
+ fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kFileOp)]);
new_entry = new_dir->FindEntry(newname, &new_page);
if (new_entry) {
diff --git a/node.cc b/node.cc
index 18f7e3c..19ed1c9 100644
--- a/node.cc
+++ b/node.cc
@@ -732,7 +732,6 @@
// Caller should call f2fs_put_dnode(dn).
zx_status_t NodeMgr::GetDnodeOfData(DnodeOfData *dn, pgoff_t index, int ro) {
- SbInfo &sbi = fs_->GetSbInfo();
Page *npage[4];
Page *parent;
int offset[4];
@@ -763,8 +762,6 @@
bool done = false;
if (!nids[i] && !ro) {
- fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kNodeNew)]);
-
/* alloc new node */
if (!AllocNid(&(nids[i]))) {
err = ZX_ERR_NO_SPACE;
@@ -1103,13 +1100,11 @@
}
zx_status_t NodeMgr::RemoveInodePage(VnodeF2fs *vnode) {
- SbInfo &sbi = fs_->GetSbInfo();
Page *page = nullptr;
nid_t ino = vnode->Ino();
DnodeOfData dn;
zx_status_t err = 0;
- fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kNodeTrunc)]);
err = GetNodePage(ino, &page);
if (err) {
return err;
@@ -1147,18 +1142,15 @@
}
zx_status_t NodeMgr::NewInodePage(Dir *parent, VnodeF2fs *child) {
- SbInfo &sbi = fs_->GetSbInfo();
Page *page = nullptr;
DnodeOfData dn;
zx_status_t err = 0;
/* allocate inode page for new inode */
SetNewDnode(&dn, child, nullptr, nullptr, child->Ino());
- {
- fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kNodeNew)]);
- err = NewNodePage(&dn, 0, &page);
- parent->InitDentInode(child, page);
- }
+ err = NewNodePage(&dn, 0, &page);
+ parent->InitDentInode(child, page);
+
if (err)
return err;
F2fsPutPage(page, 1);
@@ -1440,8 +1432,6 @@
#endif
WaitOnPageWriteback(page);
- fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kNodeWrite)]);
-
/* get old block addr of this node page */
nid = NidOfNode(page);
nofs = OfsOfNode(page);
@@ -1454,12 +1444,15 @@
return ZX_OK;
}
- SetPageWriteback(page);
+ {
+ fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kNodeOp)]);
+ SetPageWriteback(page);
- /* insert node offset */
- fs_->Segmgr().WriteNodePage(page, nid, ni.blk_addr, &new_addr);
- SetNodeAddr(&ni, new_addr);
- DecPageCount(&sbi, CountType::kDirtyNodes);
+ /* insert node offset */
+ fs_->Segmgr().WriteNodePage(page, nid, ni.blk_addr, &new_addr);
+ SetNodeAddr(&ni, new_addr);
+ DecPageCount(&sbi, CountType::kDirtyNodes);
+ }
// TODO: IMPL
// unlock_page(page);
diff --git a/node.h b/node.h
index 9341581..cfc2b18 100644
--- a/node.h
+++ b/node.h
@@ -95,6 +95,7 @@
zx_status_t ReadNodePage(Page *page, nid_t nid, int type);
zx_status_t GetNodePage(pgoff_t nid, Page **out);
+ // Caller should acquire LockType:kFileOp when |ro| = 0.
zx_status_t GetDnodeOfData(DnodeOfData *dn, pgoff_t index, int ro);
void FillNodeFooter(Page *page, nid_t nid, nid_t ino, uint32_t ofs, bool reset);
@@ -127,8 +128,11 @@
void AllocNidDone(nid_t nid);
zx_status_t TruncateInodeBlocks(VnodeF2fs *vnode, pgoff_t from);
+ // Caller should acquire LockType:kFileOp.
zx_status_t RemoveInodePage(VnodeF2fs *vnode);
+ // Caller should acquire LockType:kFileOp.
zx_status_t NewInodePage(Dir *parent, VnodeF2fs *child);
+
int IsCheckpointedNode(nid_t nid);
void ClearColdData(Page *page);
diff --git a/vnode.cc b/vnode.cc
index 0e461ac..8d5b6f3 100644
--- a/vnode.cc
+++ b/vnode.cc
@@ -304,29 +304,28 @@
#endif
}
-int VnodeF2fs::WriteInode(WritebackControl *wbc) TA_NO_THREAD_SAFETY_ANALYSIS {
+int VnodeF2fs::WriteInode(WritebackControl *wbc) {
SbInfo &sbi = Vfs()->GetSbInfo();
Page *node_page = nullptr;
zx_status_t ret = ZX_OK;
- if (ino_ == NodeIno(&sbi) || ino_ == MetaIno(&sbi))
+ if (ino_ == NodeIno(&sbi) || ino_ == MetaIno(&sbi)) {
return ret;
+ }
- if (ret = Vfs()->Nodemgr().GetNodePage(ino_, &node_page); ret != ZX_OK)
- return ret;
+ if (!IsDirty()) {
+ return ZX_OK;
+ }
- if (PageDirty(node_page) || IsDirty()) {
- UpdateInode(node_page);
- F2fsPutPage(node_page, 1);
- } else {
- F2fsPutPage(node_page, 1);
- fbl::AutoLock lock(&sbi.write_inode);
+ {
+ fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kNodeOp)]);
if (ret = Vfs()->Nodemgr().GetNodePage(ino_, &node_page); ret != ZX_OK)
return ret;
UpdateInode(node_page);
- F2fsPutPage(node_page, 1);
}
+ F2fsPutPage(node_page, 1);
+
return ZX_OK;
}
@@ -414,7 +413,7 @@
pgoff_t free_from = static_cast<pgoff_t>((from + blocksize - 1) >> (sbi.log_blocksize));
{
- fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kDataTrunc)]);
+ fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kFileOp)]);
std::lock_guard write_lock(io_lock_);
do {
@@ -454,9 +453,7 @@
for (index = pg_start; index < pg_end; index++) {
DnodeOfData dn;
- SbInfo &sbi = Vfs()->GetSbInfo();
- fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kDataTrunc)]);
SetNewDnode(&dn, this, NULL, NULL, 0);
if (zx_status_t err = Vfs()->Nodemgr().GetDnodeOfData(&dn, index, kRdOnlyNode); err != ZX_OK) {
if (err == ZX_ERR_NOT_FOUND)
@@ -504,7 +501,10 @@
if (HasBlocks())
TruncateToSize();
- Vfs()->Nodemgr().RemoveInodePage(this);
+ {
+ fs::SharedLock rlock(sbi.fs_lock[static_cast<int>(LockType::kFileOp)]);
+ Vfs()->Nodemgr().RemoveInodePage(this);
+ }
Vfs()->EvictVnode(this);
// no_delete:
// ClearInode(this);