mount: unify channelMount

Summary:
Most of what fuseMount does can be shared between fuse and prjfs, so let's
rename it and start using it on Windows.

Reviewed By: fanzeyi

Differential Revision: D21797079

fbshipit-source-id: b92a36ecc702ee72df8ebdf9534add42bea9b97e
This commit is contained in:
Xavier Deguillard 2020-06-19 18:02:42 -07:00 committed by Facebook GitHub Bot
parent b3a13a6fd8
commit ffb214384d
2 changed files with 103 additions and 76 deletions

View File

@ -1192,66 +1192,30 @@ folly::Future<TakeoverData::MountInfo> EdenMount::getChannelCompletionFuture() {
return channelCompletionPromise_.getFuture();
}
folly::Future<folly::Unit> EdenMount::startChannel(bool readOnly) {
return folly::makeFutureWith([&]() {
transitionState(
/*expected=*/State::INITIALIZED, /*newState=*/State::STARTING);
// Just in case the mount point directory doesn't exist,
// automatically create it.
boost::filesystem::path boostMountPath{getPath().value()};
boost::filesystem::create_directories(boostMountPath);
#ifdef _WIN32
fsChannel_ = std::make_unique<PrjfsChannel>(this);
fsChannel_->start(getPath(), readOnly);
createRepoConfig(
getPath(),
serverState_->getSocketPath(),
config_->getClientDirectory());
XLOGF(
INFO, "Started EdenMount (0x{:x})", reinterpret_cast<uintptr_t>(this));
transitionState(State::STARTING, State::RUNNING);
return folly::makeFuture();
#else
return fuseMount(readOnly)
.thenValue([this](folly::File&& fuseDevice) {
createFuseChannel(std::move(fuseDevice));
return channel_->initialize().thenValue(
[this](FuseChannel::StopFuture&& fuseCompleteFuture) {
fuseInitSuccessful(std::move(fuseCompleteFuture));
});
})
.thenError([this](folly::exception_wrapper&& ew) {
transitionToFuseInitializationErrorState();
return makeFuture<folly::Unit>(std::move(ew));
});
#endif
});
}
#ifndef _WIN32
void EdenMount::takeoverFuse(FuseChannelData takeoverData) {
transitionState(State::INITIALIZED, State::STARTING);
try {
beginMount().setValue();
createFuseChannel(std::move(takeoverData.fd));
auto fuseCompleteFuture =
channel_->initializeFromTakeover(takeoverData.connInfo);
fuseInitSuccessful(std::move(fuseCompleteFuture));
} catch (const std::exception&) {
transitionToFuseInitializationErrorState();
throw;
}
}
folly::Future<folly::File> EdenMount::fuseMount(bool readOnly) {
folly::Future<EdenMount::channelType> EdenMount::channelMount(bool readOnly) {
return folly::makeFutureWith([&] { return &beginMount(); })
.thenValue([this, readOnly](folly::Promise<folly::Unit>* mountPromise) {
AbsolutePath mountPath = getPath();
#ifdef _WIN32
return folly::makeFutureWith(
[mountPath, readOnly, this]() -> folly::Future<FsChannel*> {
auto channel = new PrjfsChannel(this);
channel->start(mountPath, readOnly);
return channel;
})
.thenTry([mountPromise, this](Try<FsChannel*>&& channel) {
if (channel.hasException()) {
mountPromise->setException(channel.exception());
return makeFuture<FsChannel*>(channel.exception());
}
// TODO(xavierd): similarly to the non-Windows code below, we
// need to handle the case where mount was cancelled.
mountPromise->setValue();
return makeFuture(channel);
});
#else
return serverState_->getPrivHelper()
->fuseMount(mountPath.stringPiece(), readOnly)
.thenTry(
@ -1289,9 +1253,62 @@ folly::Future<folly::File> EdenMount::fuseMount(bool readOnly) {
mountPromise->setValue();
return folly::makeFuture(std::move(fuseDevice).value());
});
#endif
});
}
void EdenMount::createChannel(EdenMount::channelType channel) {
#if _WIN32
fsChannel_.reset(channel);
#else
channel_.reset(new FuseChannel(
std::move(channel),
getPath(),
FLAGS_fuseNumThreads,
dispatcher_.get(),
serverState_->getProcessNameCache(),
std::chrono::duration_cast<folly::Duration>(
serverState_->getReloadableConfig()
.getEdenConfig()
->fuseRequestTimeout.getValue()),
serverState_->getNotifications()));
#endif
}
folly::Future<folly::Unit> EdenMount::startChannel(bool readOnly) {
return folly::makeFutureWith([&]() {
transitionState(
/*expected=*/State::INITIALIZED, /*newState=*/State::STARTING);
// Just in case the mount point directory doesn't exist,
// automatically create it.
boost::filesystem::path boostMountPath{getPath().value()};
boost::filesystem::create_directories(boostMountPath);
return channelMount(readOnly)
.thenValue([this](EdenMount::channelType&& channel) {
createChannel(std::move(channel));
#ifdef _WIN32
createRepoConfig(
getPath(),
serverState_->getSocketPath(),
config_->getClientDirectory());
transitionState(State::STARTING, State::RUNNING);
#else
return channel_->initialize().thenValue(
[this](FuseChannel::StopFuture&& fuseCompleteFuture) {
fuseInitSuccessful(std::move(fuseCompleteFuture));
});
#endif
})
.thenError([this](folly::exception_wrapper&& ew) {
transitionToFuseInitializationErrorState();
return makeFuture<folly::Unit>(std::move(ew));
});
});
}
folly::Promise<folly::Unit>& EdenMount::beginMount() {
auto mountingUnmountingState = mountingUnmountingState_.wlock();
if (mountingUnmountingState->channelMountPromise.has_value()) {
@ -1313,18 +1330,21 @@ folly::Promise<folly::Unit>& EdenMount::beginMount() {
return *mountingUnmountingState->channelMountPromise;
}
void EdenMount::createFuseChannel(folly::File fuseDevice) {
channel_.reset(new FuseChannel(
std::move(fuseDevice),
getPath(),
FLAGS_fuseNumThreads,
dispatcher_.get(),
serverState_->getProcessNameCache(),
std::chrono::duration_cast<folly::Duration>(
serverState_->getReloadableConfig()
.getEdenConfig()
->fuseRequestTimeout.getValue()),
serverState_->getNotifications()));
#ifndef _WIN32
void EdenMount::takeoverFuse(FuseChannelData takeoverData) {
transitionState(State::INITIALIZED, State::STARTING);
try {
beginMount().setValue();
createChannel(std::move(takeoverData.fd));
auto fuseCompleteFuture =
channel_->initializeFromTakeover(takeoverData.connInfo);
fuseInitSuccessful(std::move(fuseCompleteFuture));
} catch (const std::exception&) {
transitionToFuseInitializationErrorState();
throw;
}
}
void EdenMount::fuseInitSuccessful(

View File

@ -834,12 +834,6 @@ class EdenMount {
bool enforceCurrentParent,
apache::thrift::ResponseChannelRequest* FOLLY_NULLABLE request) const;
#ifndef _WIN32
/**
* Open the FUSE device and mount it using the mount(2) syscall.
*/
folly::Future<folly::File> fuseMount(bool readOnly);
/**
* Signal to unmount() that fuseMount() or takeoverFuse() has started.
*
@ -856,10 +850,23 @@ class EdenMount {
*/
FOLLY_NODISCARD folly::Promise<folly::Unit>& beginMount();
#ifdef _WIN32
using channelType = FsChannel*;
#else
using channelType = folly::File;
#endif
/**
* Open the platform specific device and mount it.
*/
folly::Future<channelType> channelMount(bool readOnly);
/**
* Construct the channel_ member variable.
*/
void createFuseChannel(folly::File fuseDevice);
void createChannel(channelType fuseDevice);
#ifndef _WIN32
/**
* Once the FuseChannel has been initialized, set up callbacks to clean up