mirror of
https://github.com/facebook/sapling.git
synced 2024-10-05 14:28:17 +03:00
inodes: mount plumbing
Summary: Now that `mount(2)` complete, we can start plumbing the rest of the mount code to accomodate for NFS. Trying to find a common ground between Prjfs, FUSE and Prjfs is harder than I wish it would be and thus I wasn't able to find a satisfatory solution. For now, I went with a std::variant that stores either a FuseChannel, or the Nfsd3. In the future once Nfs is stabilized and we have a good understanding of how it differs (and where it doesn't), EdenMount would probably need a good refactoring. Reviewed By: kmancini Differential Revision: D26500111 fbshipit-source-id: f02a2eaf8890261f150d7cdd2cdfd134aa62c2aa
This commit is contained in:
parent
c47ec0b4aa
commit
79888e20b4
@ -46,6 +46,7 @@ target_link_libraries(
|
||||
eden_journal
|
||||
eden_model_git
|
||||
eden_nfs_dispatcher
|
||||
eden_nfs_nfsd3
|
||||
eden_overlay_thrift_cpp
|
||||
eden_service_thrift_util
|
||||
eden_sqlite
|
||||
|
@ -636,11 +636,8 @@ folly::Future<folly::Unit> EdenMount::unmount() {
|
||||
.via(serverState_->getThreadPool().get())
|
||||
.ensure([this] { channel_.reset(); });
|
||||
#else
|
||||
if (serverState_->getReloadableConfig()
|
||||
.getEdenConfig()
|
||||
->enableNfsServer.getValue() &&
|
||||
getConfig()->getMountProtocol() == MountProtocol::NFS) {
|
||||
// TODO(xavierd): We need to actually do the unmount here.
|
||||
if (getNfsdChannel() != nullptr) {
|
||||
XLOG(FATAL) << "Unmount is not yet finished for NFS";
|
||||
serverState_->getNfsServer()->unregisterMount(getPath());
|
||||
return folly::makeFuture();
|
||||
} else {
|
||||
@ -671,11 +668,22 @@ InodeMetadataTable* EdenMount::getInodeMetadataTable() const {
|
||||
return overlay_->getInodeMetadataTable();
|
||||
}
|
||||
|
||||
FuseChannel* EdenMount::getFuseChannel() const {
|
||||
return channel_.get();
|
||||
FuseChannel* FOLLY_NULLABLE EdenMount::getFuseChannel() const {
|
||||
if (auto channel = std::get_if<EdenMount::FuseChannelVariant>(&channel_)) {
|
||||
return channel->get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Nfsd3* FOLLY_NULLABLE EdenMount::getNfsdChannel() const {
|
||||
if (auto channel = std::get_if<EdenMount::NfsdChannelVariant>(&channel_)) {
|
||||
return channel->get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#else
|
||||
PrjfsChannel* EdenMount::getPrjfsChannel() const {
|
||||
PrjfsChannel* FOLLY_NULLABLE EdenMount::getPrjfsChannel() const {
|
||||
return channel_.get();
|
||||
}
|
||||
#endif
|
||||
@ -1223,8 +1231,11 @@ folly::Future<TakeoverData::MountInfo> EdenMount::getChannelCompletionFuture() {
|
||||
|
||||
#ifndef _WIN32
|
||||
namespace {
|
||||
FuseChannel* makeFuseChannel(EdenMount* mount, folly::File fuseFd) {
|
||||
return new FuseChannel(
|
||||
std::unique_ptr<FuseChannel, FuseChannelDeleter> makeFuseChannel(
|
||||
EdenMount* mount,
|
||||
folly::File fuseFd) {
|
||||
std::unique_ptr<FuseChannel, FuseChannelDeleter> ret;
|
||||
ret.reset(new FuseChannel(
|
||||
std::move(fuseFd),
|
||||
mount->getPath(),
|
||||
FLAGS_fuseNumThreads,
|
||||
@ -1237,7 +1248,8 @@ FuseChannel* makeFuseChannel(EdenMount* mount, folly::File fuseFd) {
|
||||
.getEdenConfig()
|
||||
->fuseRequestTimeout.getValue()),
|
||||
mount->getServerState()->getNotifications(),
|
||||
mount->getConfig()->getCaseSensitive());
|
||||
mount->getConfig()->getCaseSensitive()));
|
||||
return ret;
|
||||
}
|
||||
} // namespace
|
||||
#endif
|
||||
@ -1324,13 +1336,8 @@ folly::Future<folly::Unit> EdenMount::channelMount(bool readOnly) {
|
||||
return folly::makeFuture<folly::Unit>(try_.exception());
|
||||
}
|
||||
|
||||
// TODO(xavierd): Do something meaningful once nfsMount
|
||||
// succeeds, and return the channel.
|
||||
XLOG(FATAL) << "Mount should have failed but didn't?";
|
||||
|
||||
mountPromise->setValue();
|
||||
// TODO(xavierd): make an NFS channel instead.
|
||||
channel_.reset(makeFuseChannel(this, folly::File()));
|
||||
channel_ = std::move(channel);
|
||||
return makeFuture(folly::unit);
|
||||
});
|
||||
});
|
||||
@ -1371,9 +1378,8 @@ folly::Future<folly::Unit> EdenMount::channelMount(bool readOnly) {
|
||||
}
|
||||
|
||||
mountPromise->setValue();
|
||||
auto channel =
|
||||
channel_ =
|
||||
makeFuseChannel(this, std::move(fuseDevice).value());
|
||||
channel_.reset(channel);
|
||||
return folly::makeFuture(folly::unit);
|
||||
});
|
||||
}
|
||||
@ -1396,10 +1402,40 @@ folly::Future<folly::Unit> EdenMount::startChannel(bool readOnly) {
|
||||
#ifdef _WIN32
|
||||
channelInitSuccessful(channel_->getStopFuture());
|
||||
#else
|
||||
return channel_->initialize().thenValue(
|
||||
[this](FuseChannel::StopFuture&& fuseCompleteFuture) {
|
||||
channelInitSuccessful(std::move(fuseCompleteFuture));
|
||||
});
|
||||
return std::visit(
|
||||
[this](auto&& variant) {
|
||||
using T = std::decay_t<decltype(variant)>;
|
||||
|
||||
if constexpr (std::
|
||||
is_same_v<T, EdenMount::FuseChannelVariant>) {
|
||||
return variant->initialize().thenValue(
|
||||
[this](FuseChannel::StopFuture&& fuseCompleteFuture) {
|
||||
auto stopFuture =
|
||||
std::move(fuseCompleteFuture)
|
||||
.deferValue(
|
||||
[](FuseChannel::StopData&& stopData)
|
||||
-> EdenMount::ChannelStopData {
|
||||
return std::move(stopData);
|
||||
});
|
||||
channelInitSuccessful(std::move(stopFuture));
|
||||
});
|
||||
} else if constexpr (std::is_same_v<
|
||||
T,
|
||||
EdenMount::NfsdChannelVariant>) {
|
||||
auto stopFuture = variant->getStopFuture().deferValue(
|
||||
[](Nfsd3::StopData&& stopData)
|
||||
-> EdenMount::ChannelStopData {
|
||||
return std::move(stopData);
|
||||
});
|
||||
channelInitSuccessful(std::move(stopFuture));
|
||||
return makeFuture(folly::unit);
|
||||
} else {
|
||||
static_assert(std::is_same_v<T, std::monostate>);
|
||||
return EDEN_BUG_FUTURE(folly::Unit)
|
||||
<< "EdenMount::channel_ is not constructed.";
|
||||
}
|
||||
},
|
||||
channel_);
|
||||
#endif
|
||||
})
|
||||
.thenError([this](folly::exception_wrapper&& ew) {
|
||||
@ -1451,22 +1487,46 @@ void EdenMount::channelInitSuccessful(
|
||||
SerializedInodeMap{} // placeholder
|
||||
));
|
||||
#else
|
||||
// If the FUSE device is no longer valid then the mount point has
|
||||
// been unmounted.
|
||||
if (!stopData.fuseDevice) {
|
||||
inodeMap_->setUnmounted();
|
||||
}
|
||||
std::visit(
|
||||
[this](auto&& variant) {
|
||||
using T = std::decay_t<decltype(variant)>;
|
||||
|
||||
std::vector<AbsolutePath> bindMounts;
|
||||
if constexpr (std::is_same_v<T, EdenMount::FuseStopData>) {
|
||||
// If the FUSE device is no longer valid then the mount point
|
||||
// has been unmounted.
|
||||
if (!variant.fuseDevice) {
|
||||
inodeMap_->setUnmounted();
|
||||
}
|
||||
|
||||
channelCompletionPromise_.setValue(TakeoverData::MountInfo(
|
||||
getPath(),
|
||||
config_->getClientDirectory(),
|
||||
bindMounts,
|
||||
std::move(stopData.fuseDevice),
|
||||
stopData.fuseSettings,
|
||||
SerializedInodeMap{} // placeholder
|
||||
));
|
||||
std::vector<AbsolutePath> bindMounts;
|
||||
|
||||
channelCompletionPromise_.setValue(TakeoverData::MountInfo(
|
||||
getPath(),
|
||||
config_->getClientDirectory(),
|
||||
bindMounts,
|
||||
std::move(variant.fuseDevice),
|
||||
variant.fuseSettings,
|
||||
SerializedInodeMap{} // placeholder
|
||||
));
|
||||
} else {
|
||||
static_assert(std::is_same_v<T, EdenMount::NfsdStopData>);
|
||||
|
||||
XLOG(FATAL) << "Unmount is not yet finished for NFS";
|
||||
|
||||
inodeMap_->setUnmounted();
|
||||
std::vector<AbsolutePath> bindMounts;
|
||||
channelCompletionPromise_.setValue(TakeoverData::MountInfo(
|
||||
getPath(),
|
||||
config_->getClientDirectory(),
|
||||
bindMounts,
|
||||
// TODO(xavierd): the next 2 fields should be a variant too.
|
||||
folly::File(),
|
||||
fuse_init_out{},
|
||||
SerializedInodeMap{} // placeholder
|
||||
));
|
||||
}
|
||||
},
|
||||
stopData);
|
||||
#endif
|
||||
})
|
||||
.thenError([this](folly::exception_wrapper&& ew) {
|
||||
@ -1482,9 +1542,15 @@ void EdenMount::takeoverFuse(FuseChannelData takeoverData) {
|
||||
try {
|
||||
beginMount().setValue();
|
||||
|
||||
channel_.reset(makeFuseChannel(this, std::move(takeoverData.fd)));
|
||||
auto channel = makeFuseChannel(this, std::move(takeoverData.fd));
|
||||
auto fuseCompleteFuture =
|
||||
channel_->initializeFromTakeover(takeoverData.connInfo);
|
||||
channel->initializeFromTakeover(takeoverData.connInfo)
|
||||
.deferValue(
|
||||
[](FuseChannel::StopData&& stopData)
|
||||
-> EdenMount::ChannelStopData {
|
||||
return std::move(stopData);
|
||||
});
|
||||
channel_ = std::move(channel);
|
||||
channelInitSuccessful(std::move(fuseCompleteFuture));
|
||||
} catch (const std::exception&) {
|
||||
transitionToFuseInitializationErrorState();
|
||||
|
@ -35,6 +35,7 @@
|
||||
#ifndef _WIN32
|
||||
#include "eden/fs/fuse/FuseChannel.h"
|
||||
#include "eden/fs/inodes/OverlayFileAccess.h"
|
||||
#include "eden/fs/nfs/Nfsd3.h"
|
||||
#else
|
||||
#include "eden/fs/prjfs/PrjfsChannel.h"
|
||||
#endif
|
||||
@ -271,9 +272,10 @@ class EdenMount {
|
||||
* no internal synchronization of its own.)
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
PrjfsChannel* getPrjfsChannel() const;
|
||||
PrjfsChannel* FOLLY_NULLABLE getPrjfsChannel() const;
|
||||
#else
|
||||
FuseChannel* getFuseChannel() const;
|
||||
FuseChannel* FOLLY_NULLABLE getFuseChannel() const;
|
||||
Nfsd3* FOLLY_NULLABLE getNfsdChannel() const;
|
||||
#endif
|
||||
|
||||
ProcessAccessLog& getProcessAccessLog() const {
|
||||
@ -776,7 +778,9 @@ class EdenMount {
|
||||
#ifdef _WIN32
|
||||
using ChannelStopData = PrjfsChannel::StopData;
|
||||
#else
|
||||
using ChannelStopData = FuseChannel::StopData;
|
||||
using FuseStopData = FuseChannel::StopData;
|
||||
using NfsdStopData = Nfsd3::StopData;
|
||||
using ChannelStopData = std::variant<FuseStopData, NfsdStopData>;
|
||||
#endif
|
||||
|
||||
using StopFuture = folly::SemiFuture<ChannelStopData>;
|
||||
@ -959,10 +963,13 @@ class EdenMount {
|
||||
*/
|
||||
std::unique_ptr<PrjfsChannel> channel_;
|
||||
#else
|
||||
using FuseChannelVariant = std::unique_ptr<FuseChannel, FuseChannelDeleter>;
|
||||
using NfsdChannelVariant = std::unique_ptr<Nfsd3>;
|
||||
|
||||
/**
|
||||
* The associated fuse channel to the kernel.
|
||||
*/
|
||||
std::unique_ptr<FuseChannel, FuseChannelDeleter> channel_;
|
||||
std::variant<std::monostate, FuseChannelVariant, NfsdChannelVariant> channel_;
|
||||
#endif // !_WIN32
|
||||
|
||||
/**
|
||||
|
@ -508,6 +508,17 @@ Nfsd3::Nfsd3(
|
||||
server_.registerService(kNfsdProgNumber, kNfsd3ProgVersion);
|
||||
}
|
||||
}
|
||||
|
||||
Nfsd3::~Nfsd3() {
|
||||
// TODO(xavierd): wait for the pending requests, and the sockets being tore
|
||||
// down
|
||||
stopPromise_.setValue(Nfsd3::StopData{});
|
||||
}
|
||||
|
||||
folly::SemiFuture<Nfsd3::StopData> Nfsd3::getStopFuture() {
|
||||
return stopPromise_.getSemiFuture();
|
||||
}
|
||||
|
||||
} // namespace facebook::eden
|
||||
|
||||
#endif
|
||||
|
@ -48,6 +48,8 @@ class Nfsd3 {
|
||||
Notifications* FOLLY_NULLABLE notifications,
|
||||
bool caseSensitive);
|
||||
|
||||
~Nfsd3();
|
||||
|
||||
/**
|
||||
* Obtain the TCP port that this NFSv3 program is listening on.
|
||||
*/
|
||||
@ -55,6 +57,13 @@ class Nfsd3 {
|
||||
return server_.getPort();
|
||||
}
|
||||
|
||||
struct StopData {};
|
||||
|
||||
/**
|
||||
* Return a future that will be triggered on unmount.
|
||||
*/
|
||||
folly::SemiFuture<StopData> getStopFuture();
|
||||
|
||||
Nfsd3(const Nfsd3&) = delete;
|
||||
Nfsd3(Nfsd3&&) = delete;
|
||||
Nfsd3& operator=(const Nfsd3&) = delete;
|
||||
@ -62,6 +71,7 @@ class Nfsd3 {
|
||||
|
||||
private:
|
||||
RpcServer server_;
|
||||
folly::Promise<StopData> stopPromise_;
|
||||
};
|
||||
|
||||
} // namespace facebook::eden
|
||||
|
Loading…
Reference in New Issue
Block a user