// Copyright 2019 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 "src/storage/blobfs/runner.h"

#include <fuchsia/fs/llcpp/fidl.h>
#include <lib/inspect/service/cpp/service.h>
#include <lib/syslog/cpp/macros.h>

#include <fs/pseudo_dir.h>

#include "src/storage/blobfs/query.h"

namespace blobfs {

// static.
zx_status_t Runner::Create(async::Loop* loop, std::unique_ptr<BlockDevice> device,
                           const MountOptions& options, zx::resource vmex_resource,
                           zx::channel diagnostics_dir_server, std::unique_ptr<Runner>* out) {
  std::unique_ptr<Blobfs> fs;
  zx_status_t status =
      Blobfs::Create(loop->dispatcher(), std::move(device), options, std::move(vmex_resource), &fs);
  if (status != ZX_OK) {
    return status;
  }

  // Setup the diagnostics directory for BlobFS
  auto diagnostics_dir = fbl::MakeRefCounted<fs::PseudoDir>();

  auto vnode = fbl::AdoptRef(
      // TODO(fxbug.dev/57330): Remove force_private_snapshot when we support requesting different
      // consistency from servers.
      new fs::Service([connector = inspect::MakeTreeHandler(
                           fs->Metrics()->inspector(), loop->dispatcher(),
                           inspect::TreeHandlerSettings{.force_private_snapshot = true})](
                          zx::channel chan) mutable {
        connector(fidl::InterfaceRequest<fuchsia::inspect::Tree>(std::move(chan)));
        return ZX_OK;
      }));

  status = diagnostics_dir->AddEntry(fuchsia::inspect::Tree::Name_, vnode);
  if (status != ZX_OK) {
    FX_LOGS(ERROR) << "failed to add Inspect vnode to diagnostics directory: "
                   << zx_status_get_string(status);
    return status;
  }

  auto runner = std::unique_ptr<Runner>(new Runner(loop, std::move(fs)));

  if (diagnostics_dir_server.is_valid()) {
    status = runner->ServeDirectory(diagnostics_dir, std::move(diagnostics_dir_server));
    if (status != ZX_OK) {
      FX_LOGS(ERROR) << "failed to serve diagnostics directory: " << zx_status_get_string(status);
      return status;
    }
  } else {
    FX_LOGS(WARNING) << "diagnostics directory server handle is invalid!";
  }

  *out = std::move(runner);
  return ZX_OK;
}

Runner::Runner(async::Loop* loop, std::unique_ptr<Blobfs> fs)
    : ManagedVfs(loop->dispatcher()), loop_(loop), blobfs_(std::move(fs)) {
  SetReadonly(blobfs_->writability() != Writability::Writable);
}

Runner::~Runner() {}

void Runner::Shutdown(fs::Vfs::ShutdownCallback cb) {
  TRACE_DURATION("blobfs", "Runner::Unmount");
  // Shutdown all external connections to blobfs.
  ManagedVfs::Shutdown([this, cb = std::move(cb)](zx_status_t status) mutable {
    async::PostTask(dispatcher(), [this, status, cb = std::move(cb)]() mutable {
      // Manually destroy the filesystem. The promise of Shutdown is that no
      // connections are active, and destroying the Runner object
      // should terminate all background workers.
      blobfs_ = nullptr;

      // Tell the mounting thread that the filesystem has terminated.
      loop_->Quit();

      // Tell the unmounting channel that we've completed teardown. This *must* be the last thing we
      // do because after this, the caller can assume that it's safe to destroy the runner.
      cb(status);
    });
  });
}

zx_status_t Runner::ServeRoot(zx::channel root, ServeLayout layout) {
  fbl::RefPtr<fs::Vnode> vn;
  zx_status_t status = blobfs_->OpenRootNode(&vn);
  if (status != ZX_OK) {
    FX_LOGS(ERROR) << "mount failed; could not get root blob";
    return status;
  }

  fbl::RefPtr<fs::Vnode> export_root;
  switch (layout) {
    case ServeLayout::kDataRootOnly:
      export_root = std::move(vn);
      break;
    case ServeLayout::kExportDirectory:
      auto outgoing = fbl::MakeRefCounted<fs::PseudoDir>();
      outgoing->AddEntry(kOutgoingDataRoot, std::move(vn));
      auto svc_dir = fbl::MakeRefCounted<fs::PseudoDir>();
      outgoing->AddEntry("svc", svc_dir);
      query_svc_ = fbl::MakeRefCounted<QueryService>(loop_->dispatcher(), blobfs_.get(), this);
      svc_dir->AddEntry(::llcpp::fuchsia::fs::Query::Name, query_svc_);
      export_root = std::move(outgoing);
      break;
  }

  status = ServeDirectory(std::move(export_root), std::move(root));
  if (status != ZX_OK) {
    FX_LOGS(ERROR) << "mount failed; could not serve root directory";
    return status;
  }
  return ZX_OK;
}

bool Runner::IsReadonly() {
#ifdef __Fuchsia__
  fbl::AutoLock lock(&vfs_lock_);
#endif
  return ReadonlyLocked();
}

}  // namespace blobfs
