inodes: start plumbing Mountd in the mount code.

Summary:
Once everything is plugged in, EdenFS will first register the mount point with
Mountd, and then execute the mount.nfs CLI against itself to mount the
repository with the OS.

For now, this does the first part by simply informing Mountd of a new mount
point during mount.

Reviewed By: kmancini

Differential Revision: D26139990

fbshipit-source-id: e5097b8e90c032c8c7bdd2cd03b69695074d7874
This commit is contained in:
Xavier Deguillard 2021-02-03 17:52:36 -08:00 committed by Facebook GitHub Bot
parent f20536cbaa
commit 22075c1159
5 changed files with 115 additions and 43 deletions

View File

@ -53,6 +53,8 @@ target_link_libraries(
eden_telemetry
eden_utils
Folly::folly
PRIVATE
eden_nfs_mountd
)
if (WIN32)

View File

@ -34,6 +34,7 @@
#include "eden/fs/model/Tree.h"
#include "eden/fs/model/git/GitIgnoreStack.h"
#include "eden/fs/model/git/TopLevelIgnores.h"
#include "eden/fs/nfs/Mountd.h"
#include "eden/fs/service/PrettyPrinters.h"
#include "eden/fs/service/gen-cpp2/eden_types.h"
#include "eden/fs/store/BlobAccess.h"
@ -636,8 +637,17 @@ folly::Future<folly::Unit> EdenMount::unmount() {
.via(serverState_->getThreadPool().get())
.ensure([this] { channel_.reset(); });
#else
return serverState_->getPrivHelper()->fuseUnmount(
getPath().stringPiece());
if (serverState_->getReloadableConfig()
.getEdenConfig()
->enableNfsServer.getValue() &&
getConfig()->getMountProtocol() == MountProtocol::NFS) {
// TODO(xavierd): We need to actually do the unmount here.
serverState_->getMountd()->unregisterMount(getPath());
return folly::makeFuture();
} else {
return serverState_->getPrivHelper()->fuseUnmount(
getPath().stringPiece());
}
#endif
})
.thenTry([this](Try<Unit>&& result) noexcept -> folly::Future<Unit> {
@ -1252,43 +1262,54 @@ folly::Future<EdenMount::channelType> EdenMount::channelMount(bool readOnly) {
return makeFuture(channel);
});
#else
return serverState_->getPrivHelper()
->fuseMount(mountPath.stringPiece(), readOnly)
.thenTry(
[mountPath, mountPromise, this](Try<folly::File>&& fuseDevice)
-> folly::Future<folly::File> {
if (fuseDevice.hasException()) {
mountPromise->setException(fuseDevice.exception());
return folly::makeFuture<folly::File>(
fuseDevice.exception());
}
if (mountingUnmountingState_.rlock()
->channelUnmountStarted()) {
fuseDevice->close();
return serverState_->getPrivHelper()
->fuseUnmount(mountPath.stringPiece())
.thenError(
folly::tag<std::exception>,
[](std::exception&& unmountError) {
// TODO(strager): Should we make
// EdenMount::unmount() also fail with the same
// exception?
XLOG(ERR)
<< "fuseMount was cancelled, but rollback (fuseUnmount) failed: "
<< unmountError.what();
throw std::move(unmountError);
})
.thenValue([mountPath, mountPromise](folly::Unit&&) {
auto error = FuseDeviceUnmountedDuringInitialization{
mountPath};
mountPromise->setException(error);
return folly::makeFuture<folly::File>(error);
});
}
if (serverState_->getReloadableConfig()
.getEdenConfig()
->enableNfsServer.getValue() &&
getConfig()->getMountProtocol() == MountProtocol::NFS) {
auto mountd = serverState_->getMountd();
mountd->registerMount(mountPath, getRootInode()->getNodeId());
// TODO(xavierd): We need to actually do a mount here.
return makeFuture(folly::File());
} else {
return serverState_->getPrivHelper()
->fuseMount(mountPath.stringPiece(), readOnly)
.thenTry(
[mountPath, mountPromise, this](Try<folly::File>&& fuseDevice)
-> folly::Future<folly::File> {
if (fuseDevice.hasException()) {
mountPromise->setException(fuseDevice.exception());
return folly::makeFuture<folly::File>(
fuseDevice.exception());
}
if (mountingUnmountingState_.rlock()
->channelUnmountStarted()) {
fuseDevice->close();
return serverState_->getPrivHelper()
->fuseUnmount(mountPath.stringPiece())
.thenError(
folly::tag<std::exception>,
[](std::exception&& unmountError) {
// TODO(strager): Should we make
// EdenMount::unmount() also fail with the same
// exception?
XLOG(ERR)
<< "fuseMount was cancelled, but rollback (fuseUnmount) failed: "
<< unmountError.what();
throw std::move(unmountError);
})
.thenValue([mountPath, mountPromise](folly::Unit&&) {
auto error =
FuseDeviceUnmountedDuringInitialization{
mountPath};
mountPromise->setException(error);
return folly::makeFuture<folly::File>(error);
});
}
mountPromise->setValue();
return folly::makeFuture(std::move(fuseDevice).value());
});
mountPromise->setValue();
return folly::makeFuture(std::move(fuseDevice).value());
});
}
#endif
});
}

View File

@ -11,7 +11,9 @@ add_library(
target_link_libraries(
eden_nfs_mountd
PUBLIC
eden_inodes_inodenumber
eden_nfs_rpc_server
eden_utils
PRIVATE
eden_nfs_mountd_rpc
Folly::folly

View File

@ -7,15 +7,16 @@
#include "eden/fs/nfs/Mountd.h"
#include <memory>
#include <unordered_map>
#include <folly/Synchronized.h>
#include <folly/futures/Future.h>
#include <folly/logging/xlog.h>
#include <memory>
#include "eden/fs/nfs/MountdRpc.h"
namespace facebook::eden {
namespace {
class MountdServerProcessor final : public RpcServerProcessor {
public:
MountdServerProcessor() = default;
@ -45,6 +46,13 @@ class MountdServerProcessor final : public RpcServerProcessor {
umountAll(folly::io::Cursor deser, folly::io::Appender ser, uint32_t xid);
folly::Future<folly::Unit>
exprt(folly::io::Cursor deser, folly::io::Appender ser, uint32_t xid);
void registerMount(AbsolutePathPiece path, InodeNumber rootIno);
void unregisterMount(AbsolutePathPiece path);
private:
folly::Synchronized<std::unordered_map<AbsolutePath, InodeNumber>>
mountPoints_;
};
using Handler = folly::Future<folly::Unit> (MountdServerProcessor::*)(
@ -174,10 +182,31 @@ folly::Future<folly::Unit> MountdServerProcessor::dispatchRpc(
return (this->*handlerEntry.handler)(std::move(deser), std::move(ser), xid);
}
} // namespace
void MountdServerProcessor::registerMount(
AbsolutePathPiece path,
InodeNumber ino) {
auto map = mountPoints_.wlock();
auto [iter, inserted] = map->emplace(path.copy(), ino);
XCHECK_EQ(inserted, true);
}
Mountd::Mountd() : server_(std::make_shared<MountdServerProcessor>()) {
void MountdServerProcessor::unregisterMount(AbsolutePathPiece path) {
auto map = mountPoints_.wlock();
auto numRemoved = map->erase(path.copy());
XCHECK_EQ(numRemoved, 1u);
}
Mountd::Mountd()
: proc_(std::make_shared<MountdServerProcessor>()), server_(proc_) {
server_.registerService(kMountdProgNumber, kMountdProgVersion);
}
void Mountd::registerMount(AbsolutePathPiece path, InodeNumber ino) {
proc_->registerMount(path, ino);
}
void Mountd::unregisterMount(AbsolutePathPiece path) {
proc_->unregisterMount(path);
}
} // namespace facebook::eden

View File

@ -10,20 +10,38 @@
// Implementation of the mount protocol as described in:
// https://tools.ietf.org/html/rfc1813#page-106
#include "eden/fs/inodes/InodeNumber.h"
#include "eden/fs/nfs/rpc/Server.h"
#include "eden/fs/utils/PathFuncs.h"
namespace facebook::eden {
class MountdServerProcessor;
class Mountd {
public:
Mountd();
/**
* Register a path as the root of a mount point.
*
* Once registered, the mount RPC request for that specific path will answer
* positively with the passed in InodeNumber.
*/
void registerMount(AbsolutePathPiece path, InodeNumber rootIno);
/**
* Unregister the mount point matching the path.
*/
void unregisterMount(AbsolutePathPiece path);
Mountd(const Mountd&) = delete;
Mountd(Mountd&&) = delete;
Mountd& operator=(const Mountd&) = delete;
Mountd& operator=(Mountd&&) = delete;
private:
std::shared_ptr<MountdServerProcessor> proc_;
RpcServer server_;
};