[f2fs] Support for unmounting using fs/Admin.Shutdown

Test: fx test f2fs-unittest f2fs-fs-tests f2fs-slow-fs-tests
Change-Id: Iab5313321f40421769114d5553b047d2a0ac05b0
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/f2fs/+/566343
Reviewed-by: Brett Wilson <brettw@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 2292917..0bb896d 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -20,6 +20,7 @@
 static_library("f2fs") {
   friend = [ "test:*" ]
   sources = [
+    "admin.cc",
     "bcache.cc",
     "checkpoint.cc",
     "data.cc",
@@ -45,6 +46,7 @@
   ]
 
   public = [
+    "admin.h",
     "bcache.h",
     "dir.h",
     "f2fs.h",
diff --git a/admin.cc b/admin.cc
new file mode 100644
index 0000000..93591e2
--- /dev/null
+++ b/admin.cc
@@ -0,0 +1,26 @@
+// 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 "f2fs.h"
+
+namespace f2fs {
+
+AdminService::AdminService(async_dispatcher_t* dispatcher, F2fs* f2fs)
+    : fs::Service([dispatcher, this](fidl::ServerEnd<fuchsia_fs::Admin> server_end) {
+        return fidl::BindSingleInFlightOnly(dispatcher, std::move(server_end), this);
+      }),
+      f2fs_(f2fs) {}
+
+void AdminService::Shutdown(ShutdownRequestView request, ShutdownCompleter::Sync& completer) {
+  f2fs_->PutSuper();
+  f2fs_->bc_.reset();
+
+  completer.Reply();
+}
+
+void AdminService::GetRoot(GetRootRequestView request, GetRootCompleter::Sync& completer) {
+  // TODO: Implement GetRoot admin service
+}
+
+}  // namespace f2fs
diff --git a/admin.h b/admin.h
new file mode 100644
index 0000000..beebf15
--- /dev/null
+++ b/admin.h
@@ -0,0 +1,25 @@
+// 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_ADMIN_H_
+#define THIRD_PARTY_F2FS_ADMIN_H_
+
+namespace f2fs {
+
+class F2fs;
+
+class AdminService final : public fidl::WireServer<fuchsia_fs::Admin>, public fs::Service {
+ public:
+  AdminService(async_dispatcher_t* dispatcher, F2fs* f2fs);
+
+  void Shutdown(ShutdownRequestView request, ShutdownCompleter::Sync& completer) final;
+  void GetRoot(GetRootRequestView request, GetRootCompleter::Sync& completer) final;
+
+ private:
+  F2fs* const f2fs_;
+};
+
+}  // namespace f2fs
+
+#endif  // THIRD_PARTY_F2FS_ADMIN_H_
diff --git a/f2fs.cc b/f2fs.cc
index f2ac184..0d49abc 100644
--- a/f2fs.cc
+++ b/f2fs.cc
@@ -130,6 +130,10 @@
       svc_dir->AddEntry(fidl::DiscoverableProtocolName<fuchsia_fs::Query>, query_svc);
       fs->SetQueryService(std::move(query_svc));
 
+      auto admin_svc = fbl::MakeRefCounted<AdminService>(fs->dispatcher(), fs.get());
+      svc_dir->AddEntry(fidl::DiscoverableProtocolName<fuchsia_fs::Admin>, admin_svc);
+      fs->SetAdminService(std::move(admin_svc));
+
       export_root = std::move(outgoing);
       break;
   }
diff --git a/f2fs.h b/f2fs.h
index d9eb4b7..a089580 100644
--- a/f2fs.h
+++ b/f2fs.h
@@ -37,6 +37,7 @@
 #include "src/lib/storage/vfs/cpp/watcher.h"
 #include "src/lib/storage/vfs/cpp/service.h"
 
+#include "admin.h"
 #include "f2fs_types.h"
 #include "f2fs_lib.h"
 #include "f2fs_layout.h"
@@ -210,6 +211,7 @@
 
   VnodeCache &GetVCache() { return vnode_cache_; }
   void SetQueryService(fbl::RefPtr<QueryService> svc) { query_svc_ = std::move(svc); }
+  void SetAdminService(fbl::RefPtr<AdminService> svc) { admin_svc_ = std::move(svc); }
 
  private:
   fbl::RefPtr<VnodeF2fs> root_vnode_;
@@ -224,6 +226,7 @@
   VnodeCache vnode_cache_{};
 
   fbl::RefPtr<QueryService> query_svc_;
+  fbl::RefPtr<AdminService> admin_svc_;
 
   zx::event fs_id_;
   uint64_t fs_id_legacy_ = 0;
diff --git a/test/BUILD.gn b/test/BUILD.gn
index 3a19a8d..77bb5ad 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -104,7 +104,6 @@
   timestamp_granularity = 1
   supports_hard_links = true
   supports_resize = false
-  use_directory_admin_to_unmount = true
   max_file_size = 4329690886144
   is_journaled = false
   supports_fsck_after_every_transaction = false