blob: 345c477c5c01ad09a8548e69af967524ecad929d [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 <fs/paged_vfs.h>
#include <fs/paged_vnode.h>
namespace fs {
PagedVnode::PagedVnode(PagedVfs* vfs) : vfs_(vfs), clone_watcher_(this) {}
PagedVnode::~PagedVnode() {}
void PagedVnode::DetachVfs() { vfs_ = nullptr; }
zx::status<> PagedVnode::EnsureCreateVmo(uint64_t size) {
if (vmo_)
return zx::ok();
if (!vfs_)
return zx::error(ZX_ERR_BAD_STATE); // Currently shutting down.
auto vfs_or = vfs_->CreatePagedNodeVmo(fbl::RefPtr<PagedVnode>(this), size);
if (vfs_or.is_error())
return vfs_or.take_error();
vmo_ = std::move(vfs_or).value();
// Watch the VMO for the presence of no children. The VMO currently has no children because we
// just created it, but the signal will be edge-triggered.
WatchForZeroVmoClones();
return zx::ok();
}
void PagedVnode::OnNoClones() {
// It is now save to release the VMO. Since we know there are no clones, we don't have to
// call zx_pager_detach_vmo() to stop delivery of requests.
vmo_.reset();
}
void PagedVnode::OnNoClonesMessage(async_dispatcher_t* dispatcher, async::WaitBase* wait,
zx_status_t status, const zx_packet_signal_t* signal) {
// TODO(fxbug.dev/51111) Needs a lock to prevent getting requests from another thread.
if (!vfs_)
return; // Called during tear-down.
// The kernel signal delivery could have raced with us creating a new clone. Validate that there
// are still no clones before tearing down.
zx_info_vmo_t info;
if (vmo_.get_info(ZX_INFO_VMO, &info, sizeof(info), nullptr, nullptr) != ZX_OK)
return; // Something wrong with the VMO, don't try to tear down.
if (info.num_children > 0) {
// Race with new VMO. Re-arm the clone watcher and continue as if the signal was not sent.
WatchForZeroVmoClones();
return;
}
clone_watcher_.set_object(ZX_HANDLE_INVALID);
OnNoClones();
}
void PagedVnode::WatchForZeroVmoClones() {
clone_watcher_.set_object(vmo_.get());
clone_watcher_.set_trigger(ZX_VMO_ZERO_CHILDREN);
clone_watcher_.Begin(vfs_->dispatcher());
}
} // namespace fs