blob: 0542dcad5c0e7219a57e1f40d9cf4d8e3bf9ea29 [file] [log] [blame]
// 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.
#ifndef SRC_STORAGE_FSHOST_BLOCK_WATCHER_H_
#define SRC_STORAGE_FSHOST_BLOCK_WATCHER_H_
#include <fuchsia/fshost/llcpp/fidl.h>
#include <memory>
#include <fbl/span.h>
#include <fs/service.h>
#include "src/storage/fshost/block-device-manager.h"
#include "src/storage/fshost/filesystem-mounter.h"
#include "src/storage/fshost/fs-manager.h"
namespace devmgr {
class BlockWatcher {
public:
// Does not take ownership of |config|, which must refer to a valid object that outlives this
// object.
BlockWatcher(FsManager& fshost, const Config* config);
~BlockWatcher() { ShutDown(); }
// Run the block watcher on a separate thread.
void Run();
// Increment the pause count for the block watcher. This function will not return until the block
// watcher is no longer running. The block watcher will not receive any new device events while
// paused.
zx_status_t Pause();
// Decrement the pause count for the block watcher.
zx_status_t Resume();
// Shut down the block watcher. This will block until complete.
void ShutDown();
private:
void Thread();
// Returns true if we received a WATCH_EVENT_IDLE and the watcher is paused.
bool Callback(int dirfd, int event, const char* name);
bool ProcessWatchMessages(fbl::Span<uint8_t> buf, int dirfd);
// Returns kSignalWatcherPaused if the watcher is paused, ZX_CHANNEL_PEER_CLOSED if the watcher
// channel was closed, and ZX_CHANNEL_READABLE if data was read, and 0 if some other error
// occured. |buf| should be a buffer of size |buf_len|. |read_len| will be updated to contain the
// actual number of bytes read.
zx_signals_t WaitForWatchMessages(const zx::unowned_channel& watcher_chan, bool finished_startup,
fbl::Span<uint8_t>& buf);
std::mutex lock_;
// pause_count_ == -1 means shut down.
int pause_count_ TA_GUARDED(lock_) = 0;
// Notified when watcher thread should resume, or when watcher thread is paused.
std::condition_variable_any pause_condition_;
zx::event pause_event_;
bool is_paused_ TA_GUARDED(lock_) = false;
FilesystemMounter mounter_;
BlockDeviceManager device_manager_;
std::thread thread_;
};
class BlockWatcherServer final : public llcpp::fuchsia::fshost::BlockWatcher::Interface {
public:
// Creates a new fs::Service backed by a new BlockWatcherServer, to be inserted into
// a pseudo fs. |watcher| is unowned and must outlive the returned instance.
static fbl::RefPtr<fs::Service> Create(async_dispatcher* dispatcher, BlockWatcher& watcher);
void Pause(PauseCompleter::Sync& completer) override;
void Resume(ResumeCompleter::Sync& completer) override;
private:
explicit BlockWatcherServer(BlockWatcher& watcher) : watcher_(watcher) {}
BlockWatcher& watcher_;
};
} // namespace devmgr
#endif // SRC_STORAGE_FSHOST_BLOCK_WATCHER_H_