[f2fs] Fixed a bug where the vnode ref_count was not maintained properly during file creation.

Change-Id: Id5f948c1f1f2d490c71dd44744b829059440ddde
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/692643
Commit-Queue: Aaron Drew <ripper@google.com>
Reviewed-by: Aaron Drew <ripper@google.com>
diff --git a/src/storage/f2fs/namei.cc b/src/storage/f2fs/namei.cc
index 9328ed7..3e75331 100644
--- a/src/storage/f2fs/namei.cc
+++ b/src/storage/f2fs/namei.cc
@@ -113,6 +113,7 @@
     if (zx_status_t err = AddLink(name, vnode); err != ZX_OK) {
       vnode->ClearNlink();
       vnode->UnlockNewInode();
+      Vfs()->GetVCache().RemoveDirty(vnode);
       Vfs()->GetNodeManager().AllocNidFailed(vnode->Ino());
       return err;
     }
@@ -290,6 +291,7 @@
       vnode->ClearFlag(InodeInfoFlag::kIncLink);
       vnode->ClearNlink();
       vnode->UnlockNewInode();
+      Vfs()->GetVCache().RemoveDirty(vnode);
       Vfs()->GetNodeManager().AllocNidFailed(vnode->Ino());
       return err;
     }
diff --git a/src/storage/f2fs/test/unit/file.cc b/src/storage/f2fs/test/unit/file.cc
index 1aaa029..ac0854c 100644
--- a/src/storage/f2fs/test/unit/file.cc
+++ b/src/storage/f2fs/test/unit/file.cc
@@ -200,6 +200,44 @@
   test_file_vn = nullptr;
 }
 
+TEST(FileTest2, FailedNidReuse) {
+  std::unique_ptr<Bcache> bc;
+  constexpr uint64_t kBlockCount = 409600;
+  FileTester::MkfsOnFakeDevWithOptions(&bc, MkfsOptions(), kBlockCount);
+
+  std::unique_ptr<F2fs> fs;
+  async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
+  FileTester::MountWithOptions(loop.dispatcher(), MountOptions{}, &bc, &fs);
+
+  fbl::RefPtr<VnodeF2fs> root;
+  FileTester::CreateRoot(fs.get(), &root);
+  fbl::RefPtr<Dir> root_dir = fbl::RefPtr<Dir>::Downcast(std::move(root));
+
+  fbl::RefPtr<fs::Vnode> tmp_child;
+  uint32_t iter = 0;
+  while (true) {
+    if (auto err = root_dir->Create(std::to_string(++iter), S_IFREG, &tmp_child); err != ZX_OK) {
+      ASSERT_EQ(err, ZX_ERR_NO_SPACE);
+      break;
+    }
+    ASSERT_EQ(tmp_child->Close(), ZX_OK);
+    tmp_child = nullptr;
+  }
+
+  const uint32_t kIteration = fs->GetNodeManager().GetFreeNidCount() + 1;
+  for (uint32_t i = 0; i < kIteration; ++i) {
+    ASSERT_EQ(root_dir->Create(std::to_string(++iter), S_IFREG, &tmp_child), ZX_ERR_NO_SPACE);
+  }
+
+  for (uint32_t i = 0; i < kIteration; ++i) {
+    ASSERT_EQ(root_dir->Create(std::to_string(++iter), S_IFDIR, &tmp_child), ZX_ERR_NO_SPACE);
+  }
+
+  root_dir->Close();
+  root_dir = nullptr;
+  FileTester::Unmount(std::move(fs), &bc);
+}
+
 TEST(DeadLockTest, Truncate) {
   std::unique_ptr<Bcache> bc;
   FileTester::MkfsOnFakeDev(&bc);