2016-05-12 23:43:17 +03:00
|
|
|
/*
|
2017-01-21 09:02:33 +03:00
|
|
|
* Copyright (c) 2016-present, Facebook, Inc.
|
2016-05-12 23:43:17 +03:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*
|
|
|
|
*/
|
2017-06-22 23:39:57 +03:00
|
|
|
#include "eden/fs/fuse/Dispatcher.h"
|
|
|
|
|
2016-05-12 23:43:17 +03:00
|
|
|
#include <folly/Exception.h>
|
|
|
|
#include <folly/Format.h>
|
|
|
|
#include <folly/MoveWrapper.h>
|
2017-10-05 22:59:42 +03:00
|
|
|
#include <folly/executors/GlobalExecutor.h>
|
2017-06-22 23:39:57 +03:00
|
|
|
#include <folly/experimental/logging/xlog.h>
|
|
|
|
|
|
|
|
#include "eden/fs/fuse/DirHandle.h"
|
|
|
|
#include "eden/fs/fuse/FileHandle.h"
|
|
|
|
#include "eden/fs/fuse/RequestData.h"
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
using namespace folly;
|
2016-06-10 21:26:35 +03:00
|
|
|
using namespace std::chrono;
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
namespace facebook {
|
|
|
|
namespace eden {
|
|
|
|
namespace fusell {
|
|
|
|
|
2017-09-09 05:15:20 +03:00
|
|
|
Dispatcher::Attr::Attr(const struct stat& st, double timeout)
|
|
|
|
: st(st), timeout(timeout) {}
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
Dispatcher::~Dispatcher() {}
|
|
|
|
|
2017-08-18 21:43:55 +03:00
|
|
|
Dispatcher::Dispatcher(ThreadLocalEdenStats* stats) : stats_(stats) {}
|
2017-03-31 21:23:02 +03:00
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
void Dispatcher::initConnection(fuse_conn_info& /*conn*/) {}
|
2016-05-12 23:43:17 +03:00
|
|
|
|
2016-07-26 19:59:18 +03:00
|
|
|
FileHandleMap& Dispatcher::getFileHandles() {
|
|
|
|
return fileHandles_;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<FileHandleBase> Dispatcher::getGenericFileHandle(uint64_t fh) {
|
|
|
|
return fileHandles_.getGenericFileHandle(fh);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<FileHandle> Dispatcher::getFileHandle(uint64_t fh) {
|
|
|
|
return fileHandles_.getFileHandle(fh);
|
|
|
|
}
|
|
|
|
std::shared_ptr<DirHandle> Dispatcher::getDirHandle(uint64_t dh) {
|
|
|
|
return fileHandles_.getDirHandle(dh);
|
|
|
|
}
|
|
|
|
|
2016-05-12 23:43:17 +03:00
|
|
|
static std::string flagsToLabel(
|
2017-11-04 01:58:04 +03:00
|
|
|
const std::unordered_map<int32_t, const char*>& labels,
|
|
|
|
uint32_t flags) {
|
2016-05-12 23:43:17 +03:00
|
|
|
std::vector<const char*> bits;
|
|
|
|
for (auto& it : labels) {
|
|
|
|
if (it.first == 0) {
|
|
|
|
// Sometimes a define evaluates to zero; it's not useful so skip it
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((flags & it.first) == it.first) {
|
|
|
|
bits.push_back(it.second);
|
|
|
|
flags &= ~it.first;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::string str;
|
|
|
|
folly::join(" ", bits, str);
|
|
|
|
if (flags == 0) {
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
return folly::format("{} unknown:0x{:x}", str, flags).str();
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::unordered_map<int32_t, const char*> capsLabels = {
|
|
|
|
{FUSE_CAP_ASYNC_READ, "ASYNC_READ"},
|
|
|
|
{FUSE_CAP_POSIX_LOCKS, "POSIX_LOCKS"},
|
|
|
|
{FUSE_CAP_ATOMIC_O_TRUNC, "ATOMIC_O_TRUNC"},
|
|
|
|
{FUSE_CAP_EXPORT_SUPPORT, "EXPORT_SUPPORT"},
|
|
|
|
{FUSE_CAP_BIG_WRITES, "BIG_WRITES"},
|
|
|
|
{FUSE_CAP_DONT_MASK, "DONT_MASK"},
|
|
|
|
#ifdef FUSE_CAP_SPLICE_WRITE
|
|
|
|
{FUSE_CAP_SPLICE_WRITE, "SPLICE_WRITE"},
|
|
|
|
{FUSE_CAP_SPLICE_MOVE, "SPLICE_MOVE"},
|
|
|
|
{FUSE_CAP_SPLICE_READ, "SPLICE_READ"},
|
|
|
|
{FUSE_CAP_FLOCK_LOCKS, "FLOCK_LOCKS"},
|
|
|
|
{FUSE_CAP_IOCTL_DIR, "IOCTL_DIR"},
|
|
|
|
#endif
|
|
|
|
#ifdef __APPLE__
|
|
|
|
{FUSE_CAP_ALLOCATE, "ALLOCATE"},
|
|
|
|
{FUSE_CAP_EXCHANGE_DATA, "EXCHANGE_DATA"},
|
|
|
|
{FUSE_CAP_CASE_INSENSITIVE, "CASE_INSENSITIVE"},
|
|
|
|
{FUSE_CAP_VOL_RENAME, "VOL_RENAME"},
|
|
|
|
{FUSE_CAP_XTIMES, "XTIMES"},
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
void Dispatcher::disp_init(void* userdata, struct fuse_conn_info* conn) {
|
|
|
|
auto disp = reinterpret_cast<Dispatcher*>(userdata);
|
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
conn->want |=
|
|
|
|
conn->capable &
|
|
|
|
(
|
2016-05-12 23:43:17 +03:00
|
|
|
#ifdef FUSE_CAP_IOCTL_DIR
|
2017-11-04 01:58:04 +03:00
|
|
|
FUSE_CAP_IOCTL_DIR |
|
2016-05-12 23:43:17 +03:00
|
|
|
#endif
|
2017-11-29 07:01:24 +03:00
|
|
|
// It would be great to enable FUSE_CAP_ATOMIC_O_TRUNC but it seems
|
|
|
|
// to trigger a kernel/FUSE bug. See
|
|
|
|
// test_mmap_is_null_terminated_after_truncate_and_write_to_overlay in
|
|
|
|
// mmap_test.py.
|
|
|
|
// FUSE_CAP_ATOMIC_O_TRUNC |
|
|
|
|
FUSE_CAP_BIG_WRITES | FUSE_CAP_ASYNC_READ);
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
disp->initConnection(*conn);
|
|
|
|
disp->connInfo_ = *conn;
|
|
|
|
|
2017-06-22 23:39:57 +03:00
|
|
|
XLOG(INFO) << "Speaking fuse protocol " << conn->proto_major << "."
|
|
|
|
<< conn->proto_minor << ", async_read=" << conn->async_read
|
|
|
|
<< ", max_write=" << conn->max_write
|
|
|
|
<< ", max_readahead=" << conn->max_readahead
|
|
|
|
<< ", capable=" << flagsToLabel(capsLabels, conn->capable)
|
|
|
|
<< ", want=" << flagsToLabel(capsLabels, conn->want);
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void Dispatcher::destroy() {}
|
|
|
|
|
|
|
|
static void disp_destroy(void* userdata) {
|
|
|
|
static_cast<Dispatcher*>(userdata)->destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
folly::Future<fuse_entry_param> Dispatcher::lookup(
|
2017-07-22 00:50:24 +03:00
|
|
|
fuse_ino_t /*parent*/,
|
|
|
|
PathComponentPiece /*name*/) {
|
2016-05-12 23:43:17 +03:00
|
|
|
throwSystemErrorExplicit(ENOENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void disp_lookup(fuse_req_t req, fuse_ino_t parent, const char* name) {
|
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2017-03-31 21:23:02 +03:00
|
|
|
request.setRequestFuture(
|
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::lookup)
|
|
|
|
.then([=, &request] {
|
|
|
|
return dispatcher->lookup(parent, PathComponentPiece(name));
|
|
|
|
})
|
|
|
|
.then([](fuse_entry_param&& param) {
|
|
|
|
RequestData::get().replyEntry(param);
|
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
folly::Future<folly::Unit> Dispatcher::forget(
|
|
|
|
fuse_ino_t /*ino*/,
|
|
|
|
unsigned long /*nlookup*/) {
|
2016-05-12 23:43:17 +03:00
|
|
|
return Unit{};
|
|
|
|
}
|
|
|
|
|
|
|
|
static void disp_forget(fuse_req_t req, fuse_ino_t ino, unsigned long nlookup) {
|
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-08-01 20:01:56 +03:00
|
|
|
request.catchErrors(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::forget)
|
2016-08-01 20:01:56 +03:00
|
|
|
.then([=, &request] { return dispatcher->forget(ino, nlookup); })
|
|
|
|
.then([]() { RequestData::get().replyNone(); }));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2017-03-07 07:24:44 +03:00
|
|
|
#if FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 9
|
2017-01-24 05:02:39 +03:00
|
|
|
static void
|
|
|
|
disp_forget_multi(fuse_req_t req, size_t count, fuse_forget_data* forgets) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
|
|
|
std::vector<fuse_forget_data> forget(forgets, forgets + count);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2017-03-31 21:23:02 +03:00
|
|
|
request.catchErrors(
|
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::forgetmulti)
|
2017-11-04 01:58:04 +03:00
|
|
|
.then([=, &request, forget = std::move(forget)] {
|
2017-03-31 21:23:02 +03:00
|
|
|
for (auto& f : forget) {
|
|
|
|
dispatcher->forget(f.ino, f.nlookup);
|
|
|
|
}
|
|
|
|
return Unit{};
|
|
|
|
})
|
|
|
|
.then([]() { RequestData::get().replyNone(); }));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
folly::Future<Dispatcher::Attr> Dispatcher::getattr(fuse_ino_t /*ino*/) {
|
2016-05-12 23:43:17 +03:00
|
|
|
throwSystemErrorExplicit(ENOENT);
|
|
|
|
}
|
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
static void
|
|
|
|
disp_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
if (fi) {
|
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::getattr)
|
2017-11-04 01:58:04 +03:00
|
|
|
.then([=, &request, fi = *fi] {
|
2016-07-26 19:59:18 +03:00
|
|
|
return dispatcher->getGenericFileHandle(fi.fh)->getattr();
|
2016-05-12 23:43:17 +03:00
|
|
|
})
|
|
|
|
.then([](Dispatcher::Attr&& attr) {
|
|
|
|
RequestData::get().replyAttr(attr.st, attr.timeout);
|
2016-08-01 20:01:56 +03:00
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
} else {
|
2016-06-10 21:26:35 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::getattr)
|
2016-06-10 21:26:35 +03:00
|
|
|
.then([=, &request] { return dispatcher->getattr(ino); })
|
|
|
|
.then([](Dispatcher::Attr&& attr) {
|
|
|
|
RequestData::get().replyAttr(attr.st, attr.timeout);
|
2016-08-01 20:01:56 +03:00
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
folly::Future<Dispatcher::Attr> Dispatcher::setattr(
|
|
|
|
fuse_ino_t /*ino*/,
|
|
|
|
const struct stat& /*attr*/,
|
|
|
|
int /*to_set*/) {
|
2016-05-12 23:43:17 +03:00
|
|
|
FUSELL_NOT_IMPL();
|
|
|
|
}
|
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
static void disp_setattr(
|
|
|
|
fuse_req_t req,
|
|
|
|
fuse_ino_t ino,
|
|
|
|
struct stat* attr,
|
|
|
|
int to_set,
|
|
|
|
struct fuse_file_info* fi) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
if (fi) {
|
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::setattr)
|
2017-11-04 01:58:04 +03:00
|
|
|
.then([=, &request, fi = *fi]() {
|
2016-07-26 19:59:18 +03:00
|
|
|
return dispatcher->getGenericFileHandle(fi.fh)->setattr(
|
|
|
|
*attr, to_set);
|
2016-05-12 23:43:17 +03:00
|
|
|
})
|
|
|
|
.then([](Dispatcher::Attr&& attr) {
|
|
|
|
RequestData::get().replyAttr(attr.st, attr.timeout);
|
2016-08-01 20:01:56 +03:00
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
} else {
|
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::setattr)
|
2016-05-12 23:43:17 +03:00
|
|
|
.then([=, &request]() {
|
2016-06-10 21:26:35 +03:00
|
|
|
return dispatcher->setattr(ino, *attr, to_set);
|
2016-05-12 23:43:17 +03:00
|
|
|
})
|
|
|
|
.then([](Dispatcher::Attr&& attr) {
|
|
|
|
RequestData::get().replyAttr(attr.st, attr.timeout);
|
2016-08-01 20:01:56 +03:00
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
folly::Future<std::string> Dispatcher::readlink(fuse_ino_t /*ino*/) {
|
2016-05-12 23:43:17 +03:00
|
|
|
FUSELL_NOT_IMPL();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void disp_readlink(fuse_req_t req, fuse_ino_t ino) {
|
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::readlink)
|
2016-06-10 21:26:35 +03:00
|
|
|
.then([=, &request] { return dispatcher->readlink(ino); })
|
2016-08-01 20:01:56 +03:00
|
|
|
.then([](std::string&& str) {
|
|
|
|
RequestData::get().replyReadLink(str);
|
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
folly::Future<fuse_entry_param> Dispatcher::mknod(
|
2017-07-22 00:50:24 +03:00
|
|
|
fuse_ino_t /*parent*/,
|
|
|
|
PathComponentPiece /*name*/,
|
|
|
|
mode_t /*mode*/,
|
|
|
|
dev_t /*rdev*/) {
|
2016-05-12 23:43:17 +03:00
|
|
|
FUSELL_NOT_IMPL();
|
|
|
|
}
|
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
static void disp_mknod(
|
|
|
|
fuse_req_t req,
|
|
|
|
fuse_ino_t parent,
|
|
|
|
const char* name,
|
|
|
|
mode_t mode,
|
|
|
|
dev_t rdev) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-05-12 23:43:17 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::mknod)
|
2016-05-12 23:43:17 +03:00
|
|
|
.then([=, &request] {
|
2016-06-10 21:26:35 +03:00
|
|
|
return dispatcher->mknod(
|
2016-05-12 23:43:17 +03:00
|
|
|
parent, PathComponentPiece(name), mode, rdev);
|
|
|
|
})
|
|
|
|
.then([](fuse_entry_param&& param) {
|
|
|
|
RequestData::get().replyEntry(param);
|
2016-08-01 20:01:56 +03:00
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
folly::Future<fuse_entry_param>
|
2017-11-04 01:58:04 +03:00
|
|
|
Dispatcher::mkdir(fuse_ino_t, PathComponentPiece, mode_t) {
|
2016-05-12 23:43:17 +03:00
|
|
|
FUSELL_NOT_IMPL();
|
|
|
|
}
|
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
static void
|
|
|
|
disp_mkdir(fuse_req_t req, fuse_ino_t parent, const char* name, mode_t mode) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2017-03-31 21:23:02 +03:00
|
|
|
request.setRequestFuture(
|
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::mkdir)
|
|
|
|
.then([=, &request] {
|
|
|
|
return dispatcher->mkdir(parent, PathComponentPiece(name), mode);
|
|
|
|
})
|
|
|
|
.then([](fuse_entry_param&& param) {
|
|
|
|
RequestData::get().replyEntry(param);
|
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
folly::Future<folly::Unit> Dispatcher::unlink(fuse_ino_t, PathComponentPiece) {
|
|
|
|
FUSELL_NOT_IMPL();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void disp_unlink(fuse_req_t req, fuse_ino_t parent, const char* name) {
|
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-08-01 20:01:56 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::unlink)
|
2016-08-01 20:01:56 +03:00
|
|
|
.then([=, &request] {
|
|
|
|
return dispatcher->unlink(parent, PathComponentPiece(name));
|
|
|
|
})
|
|
|
|
.then([]() { RequestData::get().replyError(0); }));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
folly::Future<folly::Unit> Dispatcher::rmdir(fuse_ino_t, PathComponentPiece) {
|
|
|
|
FUSELL_NOT_IMPL();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void disp_rmdir(fuse_req_t req, fuse_ino_t parent, const char* name) {
|
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-08-01 20:01:56 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::rmdir)
|
2016-08-01 20:01:56 +03:00
|
|
|
.then([=, &request] {
|
|
|
|
return dispatcher->rmdir(parent, PathComponentPiece(name));
|
|
|
|
})
|
|
|
|
.then([]() { RequestData::get().replyError(0); }));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
folly::Future<fuse_entry_param>
|
2016-12-15 02:35:06 +03:00
|
|
|
Dispatcher::symlink(fuse_ino_t, PathComponentPiece, folly::StringPiece) {
|
2016-05-12 23:43:17 +03:00
|
|
|
FUSELL_NOT_IMPL();
|
|
|
|
}
|
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
static void disp_symlink(
|
|
|
|
fuse_req_t req,
|
|
|
|
const char* link,
|
|
|
|
fuse_ino_t parent,
|
|
|
|
const char* name) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2017-03-31 21:23:02 +03:00
|
|
|
request.setRequestFuture(
|
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::symlink)
|
|
|
|
.then([=, &request] {
|
|
|
|
return dispatcher->symlink(parent, PathComponentPiece(name), link);
|
|
|
|
})
|
|
|
|
.then([](fuse_entry_param&& param) {
|
|
|
|
RequestData::get().replyEntry(param);
|
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
folly::Future<folly::Unit> Dispatcher::rename(
|
|
|
|
fuse_ino_t,
|
|
|
|
PathComponentPiece,
|
|
|
|
fuse_ino_t,
|
|
|
|
PathComponentPiece) {
|
|
|
|
FUSELL_NOT_IMPL();
|
|
|
|
}
|
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
static void disp_rename(
|
|
|
|
fuse_req_t req,
|
|
|
|
fuse_ino_t parent,
|
|
|
|
const char* name,
|
|
|
|
fuse_ino_t newparent,
|
|
|
|
const char* newname) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2017-11-04 01:58:04 +03:00
|
|
|
request.setRequestFuture(
|
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::rename)
|
|
|
|
.then([=, &request] {
|
|
|
|
return dispatcher->rename(
|
|
|
|
parent,
|
|
|
|
PathComponentPiece(name),
|
|
|
|
newparent,
|
|
|
|
PathComponentPiece(newname));
|
|
|
|
})
|
|
|
|
.then([]() { RequestData::get().replyError(0); }));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
folly::Future<fuse_entry_param>
|
2017-11-04 01:58:04 +03:00
|
|
|
Dispatcher::link(fuse_ino_t, fuse_ino_t, PathComponentPiece) {
|
2016-05-12 23:43:17 +03:00
|
|
|
FUSELL_NOT_IMPL();
|
|
|
|
}
|
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
static void disp_link(
|
|
|
|
fuse_req_t req,
|
|
|
|
fuse_ino_t ino,
|
|
|
|
fuse_ino_t newparent,
|
|
|
|
const char* newname) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-05-12 23:43:17 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::link)
|
2016-05-12 23:43:17 +03:00
|
|
|
.then([=, &request] {
|
2016-06-10 21:26:35 +03:00
|
|
|
return dispatcher->link(
|
2016-05-12 23:43:17 +03:00
|
|
|
ino, newparent, PathComponentPiece(newname));
|
|
|
|
})
|
|
|
|
.then([](fuse_entry_param&& param) {
|
|
|
|
RequestData::get().replyEntry(param);
|
2016-08-01 20:01:56 +03:00
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2016-07-26 19:59:18 +03:00
|
|
|
folly::Future<std::shared_ptr<FileHandle>> Dispatcher::open(
|
2017-07-22 00:50:24 +03:00
|
|
|
fuse_ino_t /*ino*/,
|
|
|
|
const struct fuse_file_info& /*fi*/) {
|
2016-05-12 23:43:17 +03:00
|
|
|
FUSELL_NOT_IMPL();
|
|
|
|
}
|
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
static void
|
|
|
|
disp_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-05-18 04:16:07 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::open)
|
2017-11-04 01:58:04 +03:00
|
|
|
.then([=, &request, fi = *fi] { return dispatcher->open(ino, fi); })
|
|
|
|
.then([req, dispatcher, orig_info = *fi](
|
|
|
|
std::shared_ptr<FileHandle> fh) {
|
2016-05-18 04:16:07 +03:00
|
|
|
if (!fh) {
|
|
|
|
throw std::runtime_error("Dispatcher::open failed to set fh");
|
|
|
|
}
|
|
|
|
fuse_file_info fi = orig_info;
|
|
|
|
fi.direct_io = fh->usesDirectIO();
|
|
|
|
fi.keep_cache = fh->preserveCache();
|
2016-05-12 23:43:17 +03:00
|
|
|
#if FUSE_MINOR_VERSION >= 8
|
2016-05-18 04:16:07 +03:00
|
|
|
fi.nonseekable = !fh->isSeekable();
|
2016-05-12 23:43:17 +03:00
|
|
|
#endif
|
2016-07-26 19:59:18 +03:00
|
|
|
fi.fh = dispatcher->getFileHandles().recordHandle(std::move(fh));
|
2016-05-18 04:16:07 +03:00
|
|
|
if (!RequestData::get().replyOpen(fi)) {
|
|
|
|
// Was interrupted, tidy up.
|
2016-07-27 07:02:09 +03:00
|
|
|
dispatcher->getFileHandles().forgetGenericHandle(fi.fh);
|
2016-05-18 04:16:07 +03:00
|
|
|
}
|
2016-08-01 20:01:56 +03:00
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
static void disp_read(
|
|
|
|
fuse_req_t req,
|
|
|
|
fuse_ino_t /*ino*/,
|
|
|
|
size_t size,
|
|
|
|
off_t off,
|
|
|
|
struct fuse_file_info* fi) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2017-03-31 21:23:02 +03:00
|
|
|
request.setRequestFuture(
|
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::read)
|
2017-11-04 01:58:04 +03:00
|
|
|
.then([=, &request, fi = *fi] {
|
2017-03-31 21:23:02 +03:00
|
|
|
auto fh = dispatcher->getFileHandle(fi.fh);
|
|
|
|
return fh->read(size, off);
|
|
|
|
})
|
|
|
|
.then([](BufVec&& buf) {
|
|
|
|
auto iov = buf.getIov();
|
|
|
|
RequestData::get().replyIov(iov.data(), iov.size());
|
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
static void disp_write(
|
|
|
|
fuse_req_t req,
|
|
|
|
fuse_ino_t /*ino*/,
|
|
|
|
const char* buf,
|
|
|
|
size_t size,
|
|
|
|
off_t off,
|
|
|
|
struct fuse_file_info* fi) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-05-12 23:43:17 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::write)
|
2017-11-04 01:58:04 +03:00
|
|
|
.then([=, &request, fi = *fi] {
|
2016-07-26 19:59:18 +03:00
|
|
|
auto fh = dispatcher->getFileHandle(fi.fh);
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
return fh->write(folly::StringPiece(buf, size), off);
|
|
|
|
})
|
2016-08-01 20:01:56 +03:00
|
|
|
.then([](size_t wrote) { RequestData::get().replyWrite(wrote); }));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
static void
|
|
|
|
disp_flush(fuse_req_t req, fuse_ino_t /*ino*/, struct fuse_file_info* fi) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-08-01 20:01:56 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::flush)
|
2017-11-04 01:58:04 +03:00
|
|
|
.then([=, &request, fi = *fi] {
|
2016-08-01 20:01:56 +03:00
|
|
|
auto fh = dispatcher->getFileHandle(fi.fh);
|
2016-07-26 19:59:18 +03:00
|
|
|
|
2016-08-01 20:01:56 +03:00
|
|
|
return fh->flush(fi.lock_owner);
|
|
|
|
})
|
|
|
|
.then([]() { RequestData::get().replyError(0); }));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
static void
|
|
|
|
disp_release(fuse_req_t req, fuse_ino_t /*ino*/, struct fuse_file_info* fi) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-07-26 19:59:18 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::release)
|
2017-11-04 01:58:04 +03:00
|
|
|
.then([=, &request, fi = *fi] {
|
2016-07-27 07:02:09 +03:00
|
|
|
dispatcher->getFileHandles().forgetGenericHandle(fi.fh);
|
|
|
|
RequestData::get().replyError(0);
|
2016-08-01 20:01:56 +03:00
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
static void disp_fsync(
|
|
|
|
fuse_req_t req,
|
|
|
|
fuse_ino_t /*ino*/,
|
|
|
|
int datasync,
|
|
|
|
struct fuse_file_info* fi) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-08-01 20:01:56 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::fsync)
|
2017-11-04 01:58:04 +03:00
|
|
|
.then([=, &request, fi = *fi] {
|
2016-08-01 20:01:56 +03:00
|
|
|
auto fh = dispatcher->getFileHandle(fi.fh);
|
|
|
|
return fh->fsync(datasync);
|
|
|
|
})
|
|
|
|
.then([]() { RequestData::get().replyError(0); }));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2016-07-26 19:59:18 +03:00
|
|
|
folly::Future<std::shared_ptr<DirHandle>> Dispatcher::opendir(
|
2017-07-22 00:50:24 +03:00
|
|
|
fuse_ino_t /*ino*/,
|
|
|
|
const struct fuse_file_info& /*fi*/) {
|
2016-05-12 23:43:17 +03:00
|
|
|
FUSELL_NOT_IMPL();
|
|
|
|
}
|
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
static void
|
|
|
|
disp_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-05-12 23:43:17 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::opendir)
|
2017-11-04 01:58:04 +03:00
|
|
|
.then(
|
|
|
|
[=, &request, fi = *fi] { return dispatcher->opendir(ino, fi); })
|
|
|
|
.then([dispatcher, orig_info = *fi](std::shared_ptr<DirHandle> dh) {
|
2016-05-18 04:16:07 +03:00
|
|
|
if (!dh) {
|
2016-05-12 23:43:17 +03:00
|
|
|
throw std::runtime_error("Dispatcher::opendir failed to set dh");
|
|
|
|
}
|
|
|
|
fuse_file_info fi = orig_info;
|
2016-07-26 19:59:18 +03:00
|
|
|
fi.fh = dispatcher->getFileHandles().recordHandle(std::move(dh));
|
2016-05-12 23:43:17 +03:00
|
|
|
if (!RequestData::get().replyOpen(fi)) {
|
|
|
|
// Was interrupted, tidy up
|
2016-07-27 07:02:09 +03:00
|
|
|
dispatcher->getFileHandles().forgetGenericHandle(fi.fh);
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
2016-08-01 20:01:56 +03:00
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
static void disp_readdir(
|
|
|
|
fuse_req_t req,
|
|
|
|
fuse_ino_t /*ino*/,
|
|
|
|
size_t size,
|
|
|
|
off_t off,
|
|
|
|
struct fuse_file_info* fi) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2017-03-31 21:23:02 +03:00
|
|
|
request.setRequestFuture(
|
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::readdir)
|
2017-11-04 01:58:04 +03:00
|
|
|
.then([=, &request, fi = *fi] {
|
2017-03-31 21:23:02 +03:00
|
|
|
auto dh = dispatcher->getDirHandle(fi.fh);
|
|
|
|
return dh->readdir(DirList(size), off);
|
|
|
|
})
|
|
|
|
.then([](DirList&& list) {
|
|
|
|
auto buf = list.getBuf();
|
|
|
|
RequestData::get().replyBuf(buf.data(), buf.size());
|
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
static void
|
|
|
|
disp_releasedir(fuse_req_t req, fuse_ino_t /*ino*/, struct fuse_file_info* fi) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-07-26 19:59:18 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::releasedir)
|
2017-11-04 01:58:04 +03:00
|
|
|
.then([=, &request, fi = *fi] {
|
2016-07-27 07:02:09 +03:00
|
|
|
dispatcher->getFileHandles().forgetGenericHandle(fi.fh);
|
|
|
|
RequestData::get().replyError(0);
|
2016-08-01 20:01:56 +03:00
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
static void disp_fsyncdir(
|
|
|
|
fuse_req_t req,
|
|
|
|
fuse_ino_t /*ino*/,
|
|
|
|
int datasync,
|
|
|
|
struct fuse_file_info* fi) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-08-01 20:01:56 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::fsyncdir)
|
2017-11-04 01:58:04 +03:00
|
|
|
.then([=, &request, fi = *fi] {
|
2016-08-01 20:01:56 +03:00
|
|
|
auto dh = dispatcher->getDirHandle(fi.fh);
|
|
|
|
return dh->fsyncdir(datasync);
|
|
|
|
})
|
|
|
|
.then([]() { RequestData::get().replyError(0); }));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
folly::Future<struct statvfs> Dispatcher::statfs(fuse_ino_t /*ino*/) {
|
2016-05-12 23:43:17 +03:00
|
|
|
struct statvfs info;
|
|
|
|
memset(&info, 0, sizeof(info));
|
|
|
|
|
|
|
|
// Suggest a large blocksize to software that looks at that kind of thing
|
|
|
|
info.f_bsize = getConnInfo().max_readahead;
|
|
|
|
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void disp_statfs(fuse_req_t req, fuse_ino_t ino) {
|
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-05-12 23:43:17 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::statfs)
|
2016-06-10 21:26:35 +03:00
|
|
|
.then([=, &request] { return dispatcher->statfs(ino); })
|
2016-05-12 23:43:17 +03:00
|
|
|
.then([](struct statvfs&& info) {
|
|
|
|
RequestData::get().replyStatfs(info);
|
2016-08-01 20:01:56 +03:00
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
folly::Future<folly::Unit> Dispatcher::setxattr(
|
|
|
|
fuse_ino_t /*ino*/,
|
|
|
|
folly::StringPiece /*name*/,
|
|
|
|
folly::StringPiece /*value*/,
|
|
|
|
int /*flags*/) {
|
2016-05-12 23:43:17 +03:00
|
|
|
FUSELL_NOT_IMPL();
|
|
|
|
}
|
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
static void disp_setxattr(
|
|
|
|
fuse_req_t req,
|
|
|
|
fuse_ino_t ino,
|
|
|
|
const char* name,
|
|
|
|
const char* value,
|
|
|
|
size_t size,
|
|
|
|
int flags
|
2016-05-12 23:43:17 +03:00
|
|
|
#ifdef __APPLE__
|
2017-11-04 01:58:04 +03:00
|
|
|
,
|
|
|
|
uint32_t position
|
2016-05-12 23:43:17 +03:00
|
|
|
#endif
|
2017-11-04 01:58:04 +03:00
|
|
|
) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
if (position != 0) {
|
|
|
|
request.replyError(EINVAL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::setxattr)
|
2016-05-12 23:43:17 +03:00
|
|
|
.then([=, &request] {
|
2016-06-10 21:26:35 +03:00
|
|
|
return dispatcher->setxattr(
|
2016-05-12 23:43:17 +03:00
|
|
|
ino, name, folly::StringPiece(value, size), flags);
|
|
|
|
})
|
2016-08-01 20:01:56 +03:00
|
|
|
.then([]() { RequestData::get().replyError(0); }));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
const int Dispatcher::kENOATTR =
|
|
|
|
#ifndef ENOATTR
|
|
|
|
ENODATA // Linux
|
|
|
|
#else
|
|
|
|
ENOATTR
|
|
|
|
#endif
|
|
|
|
;
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
folly::Future<std::string> Dispatcher::getxattr(
|
|
|
|
fuse_ino_t /*ino*/,
|
|
|
|
folly::StringPiece /*name*/) {
|
2016-05-12 23:43:17 +03:00
|
|
|
throwSystemErrorExplicit(kENOATTR);
|
|
|
|
}
|
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
static void disp_getxattr(
|
|
|
|
fuse_req_t req,
|
|
|
|
fuse_ino_t ino,
|
|
|
|
const char* name,
|
|
|
|
size_t size
|
2016-05-12 23:43:17 +03:00
|
|
|
#ifdef __APPLE__
|
2017-11-04 01:58:04 +03:00
|
|
|
,
|
|
|
|
uint32_t position
|
2016-05-12 23:43:17 +03:00
|
|
|
#endif
|
2017-11-04 01:58:04 +03:00
|
|
|
) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
if (position != 0) {
|
|
|
|
request.replyError(EINVAL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-06-10 21:26:35 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::getxattr)
|
2016-06-10 21:26:35 +03:00
|
|
|
.then([=, &request] { return dispatcher->getxattr(ino, name); })
|
|
|
|
.then([size](std::string attr) {
|
|
|
|
auto& request = RequestData::get();
|
|
|
|
if (size == 0) {
|
|
|
|
request.replyXattr(attr.size());
|
|
|
|
} else if (size < attr.size()) {
|
|
|
|
request.replyError(ERANGE);
|
|
|
|
} else {
|
|
|
|
request.replyBuf(attr.data(), attr.size());
|
|
|
|
}
|
2016-08-01 20:01:56 +03:00
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
folly::Future<std::vector<std::string>> Dispatcher::listxattr(
|
|
|
|
fuse_ino_t /*ino*/) {
|
2016-05-12 23:43:17 +03:00
|
|
|
return std::vector<std::string>();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void disp_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) {
|
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::listxattr)
|
2016-06-10 21:26:35 +03:00
|
|
|
.then([=, &request] { return dispatcher->listxattr(ino); })
|
|
|
|
.then([size](std::vector<std::string>&& attrs) {
|
|
|
|
auto& request = RequestData::get();
|
|
|
|
|
|
|
|
// Initialize count to include the \0 for each
|
|
|
|
// entry.
|
|
|
|
size_t count = attrs.size();
|
|
|
|
for (auto& attr : attrs) {
|
|
|
|
count += attr.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (size == 0) {
|
|
|
|
request.replyXattr(count);
|
|
|
|
} else if (size < count) {
|
|
|
|
request.replyError(ERANGE);
|
|
|
|
} else {
|
|
|
|
std::string buf;
|
|
|
|
folly::join('\0', attrs, buf);
|
|
|
|
buf.push_back('\0');
|
|
|
|
DCHECK(count == buf.size());
|
|
|
|
request.replyBuf(buf.data(), count);
|
|
|
|
}
|
2016-08-01 20:01:56 +03:00
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
folly::Future<folly::Unit> Dispatcher::removexattr(
|
|
|
|
fuse_ino_t /*ino*/,
|
|
|
|
folly::StringPiece /*name*/) {
|
2016-05-12 23:43:17 +03:00
|
|
|
FUSELL_NOT_IMPL();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void disp_removexattr(fuse_req_t req, fuse_ino_t ino, const char* name) {
|
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::removexattr)
|
2016-06-10 21:26:35 +03:00
|
|
|
.then([=, &request] { return dispatcher->removexattr(ino, name); })
|
2016-08-01 20:01:56 +03:00
|
|
|
.then([]() { RequestData::get().replyError(0); }));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
folly::Future<folly::Unit> Dispatcher::access(
|
|
|
|
fuse_ino_t /*ino*/,
|
|
|
|
int /*mask*/) {
|
2016-08-04 02:18:23 +03:00
|
|
|
// Note that if you mount with the "default_permissions" kernel mount option,
|
|
|
|
// the kernel will perform all permissions checks for you, and will never
|
|
|
|
// invoke access() directly.
|
|
|
|
//
|
|
|
|
// Implementing access() is only needed when not using the
|
|
|
|
// "default_permissions" option.
|
2016-05-12 23:43:17 +03:00
|
|
|
FUSELL_NOT_IMPL();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void disp_access(fuse_req_t req, fuse_ino_t ino, int mask) {
|
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::access)
|
2016-06-10 21:26:35 +03:00
|
|
|
.then([=, &request] { return dispatcher->access(ino, mask); })
|
2016-08-01 20:01:56 +03:00
|
|
|
.then([]() { RequestData::get().replyError(0); }));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
folly::Future<Dispatcher::Create>
|
|
|
|
Dispatcher::create(fuse_ino_t, PathComponentPiece, mode_t, int) {
|
|
|
|
FUSELL_NOT_IMPL();
|
|
|
|
}
|
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
static void disp_create(
|
|
|
|
fuse_req_t req,
|
|
|
|
fuse_ino_t parent,
|
|
|
|
const char* name,
|
|
|
|
mode_t mode,
|
|
|
|
struct fuse_file_info* fi) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-05-12 23:43:17 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::create)
|
2017-11-04 01:58:04 +03:00
|
|
|
.then([=, &request, fi = *fi] {
|
2016-06-10 21:26:35 +03:00
|
|
|
return dispatcher->create(
|
2016-05-12 23:43:17 +03:00
|
|
|
parent, PathComponentPiece(name), mode, fi.flags);
|
|
|
|
})
|
2017-11-04 01:58:04 +03:00
|
|
|
.then([dispatcher, orig_info = *fi](Dispatcher::Create info) {
|
2016-05-12 23:43:17 +03:00
|
|
|
fuse_file_info fi = orig_info;
|
|
|
|
fi.direct_io = info.fh->usesDirectIO();
|
|
|
|
fi.keep_cache = info.fh->preserveCache();
|
|
|
|
#if FUSE_MINOR_VERSION >= 8
|
|
|
|
fi.nonseekable = !info.fh->isSeekable();
|
|
|
|
#endif
|
2016-07-26 19:59:18 +03:00
|
|
|
fi.fh =
|
|
|
|
dispatcher->getFileHandles().recordHandle(std::move(info.fh));
|
2016-05-12 23:43:17 +03:00
|
|
|
if (!RequestData::get().replyCreate(info.entry, fi)) {
|
|
|
|
// Interrupted, tidy up
|
2016-07-27 07:02:09 +03:00
|
|
|
dispatcher->getFileHandles().forgetGenericHandle(fi.fh);
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
2016-08-01 20:01:56 +03:00
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2017-07-22 00:50:24 +03:00
|
|
|
folly::Future<uint64_t>
|
|
|
|
Dispatcher::bmap(fuse_ino_t /*ino*/, size_t /*blocksize*/, uint64_t /*idx*/) {
|
2016-05-12 23:43:17 +03:00
|
|
|
FUSELL_NOT_IMPL();
|
|
|
|
}
|
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
static void
|
|
|
|
disp_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize, uint64_t idx) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-05-12 23:43:17 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::bmap)
|
2016-06-10 21:26:35 +03:00
|
|
|
.then([=, &request] { return dispatcher->bmap(ino, blocksize, idx); })
|
2017-03-03 00:29:25 +03:00
|
|
|
.then([](uint64_t resultIdx) {
|
|
|
|
RequestData::get().replyBmap(resultIdx);
|
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#if FUSE_MINOR_VERSION >= 8
|
2017-07-22 00:50:24 +03:00
|
|
|
static void disp_ioctl(
|
|
|
|
fuse_req_t req,
|
|
|
|
fuse_ino_t /*ino*/,
|
|
|
|
int cmd,
|
|
|
|
void* arg,
|
|
|
|
struct fuse_file_info* fi,
|
|
|
|
unsigned flags,
|
|
|
|
const void* in_buf,
|
|
|
|
size_t in_bufsz,
|
|
|
|
size_t out_bufsz) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
if (flags & FUSE_IOCTL_UNRESTRICTED) {
|
|
|
|
// We only support restricted ioctls
|
|
|
|
request.replyError(-EPERM);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::ioctl)
|
2017-11-04 01:58:04 +03:00
|
|
|
.then([=, &request, fi = *fi] {
|
2016-07-26 19:59:18 +03:00
|
|
|
auto fh = dispatcher->getGenericFileHandle(fi.fh);
|
2016-05-12 23:43:17 +03:00
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
return fh->ioctl(
|
|
|
|
cmd,
|
|
|
|
arg,
|
|
|
|
folly::ByteRange((uint8_t*)in_buf, in_bufsz),
|
|
|
|
out_bufsz);
|
2016-05-12 23:43:17 +03:00
|
|
|
})
|
|
|
|
.then([](FileHandleBase::Ioctl&& result) {
|
|
|
|
auto iov = result.buf.getIov();
|
|
|
|
RequestData::get().replyIoctl(
|
|
|
|
result.result, iov.data(), iov.size());
|
2016-08-01 20:01:56 +03:00
|
|
|
}));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if FUSE_MINOR_VERSION >= 8
|
2017-07-22 00:50:24 +03:00
|
|
|
static void disp_poll(
|
|
|
|
fuse_req_t req,
|
|
|
|
fuse_ino_t /*ino*/,
|
|
|
|
struct fuse_file_info* fi,
|
|
|
|
struct fuse_pollhandle* ph) {
|
2016-05-12 23:43:17 +03:00
|
|
|
auto& request = RequestData::create(req);
|
2016-06-10 21:26:35 +03:00
|
|
|
auto* dispatcher = request.getDispatcher();
|
2016-05-12 23:43:17 +03:00
|
|
|
request.setRequestFuture(
|
2017-03-31 21:23:02 +03:00
|
|
|
request.startRequest(dispatcher->getStats(), &EdenStats::poll)
|
2017-11-04 01:58:04 +03:00
|
|
|
.then([=, &request, fi = *fi] {
|
2016-07-26 19:59:18 +03:00
|
|
|
auto fh = dispatcher->getGenericFileHandle(fi.fh);
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
std::unique_ptr<PollHandle> poll_handle;
|
|
|
|
if (ph) {
|
|
|
|
poll_handle = std::make_unique<PollHandle>(ph);
|
|
|
|
}
|
|
|
|
|
|
|
|
return fh->poll(std::move(poll_handle));
|
|
|
|
})
|
2016-08-01 20:01:56 +03:00
|
|
|
.then(
|
|
|
|
[](unsigned revents) { RequestData::get().replyPoll(revents); }));
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-09-09 05:15:17 +03:00
|
|
|
const fuse_lowlevel_ops dispatcher_ops = {
|
2016-05-12 23:43:17 +03:00
|
|
|
.init = Dispatcher::disp_init,
|
|
|
|
.destroy = disp_destroy,
|
|
|
|
.lookup = disp_lookup,
|
|
|
|
.forget = disp_forget,
|
|
|
|
.getattr = disp_getattr,
|
|
|
|
.setattr = disp_setattr,
|
|
|
|
.readlink = disp_readlink,
|
|
|
|
.mknod = disp_mknod,
|
|
|
|
.mkdir = disp_mkdir,
|
|
|
|
.unlink = disp_unlink,
|
|
|
|
.rmdir = disp_rmdir,
|
|
|
|
.symlink = disp_symlink,
|
|
|
|
.rename = disp_rename,
|
|
|
|
.link = disp_link,
|
|
|
|
.open = disp_open,
|
|
|
|
.read = disp_read,
|
|
|
|
.write = disp_write,
|
|
|
|
.flush = disp_flush,
|
|
|
|
.release = disp_release,
|
|
|
|
.fsync = disp_fsync,
|
|
|
|
.opendir = disp_opendir,
|
|
|
|
.readdir = disp_readdir,
|
|
|
|
.releasedir = disp_releasedir,
|
|
|
|
.fsyncdir = disp_fsyncdir,
|
|
|
|
.statfs = disp_statfs,
|
|
|
|
.setxattr = disp_setxattr,
|
|
|
|
.getxattr = disp_getxattr,
|
|
|
|
.listxattr = disp_listxattr,
|
|
|
|
.removexattr = disp_removexattr,
|
|
|
|
.access = disp_access,
|
|
|
|
.create = disp_create,
|
2017-03-25 08:57:12 +03:00
|
|
|
// Leave it to the kernel to handle locking
|
|
|
|
.getlk = nullptr,
|
|
|
|
.setlk = nullptr,
|
2016-05-12 23:43:17 +03:00
|
|
|
.bmap = disp_bmap,
|
2017-03-07 07:24:44 +03:00
|
|
|
#if FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8
|
2016-05-12 23:43:17 +03:00
|
|
|
.ioctl = disp_ioctl,
|
|
|
|
.poll = disp_poll,
|
|
|
|
#endif
|
2017-03-07 07:24:44 +03:00
|
|
|
#if FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 9
|
|
|
|
.write_buf = nullptr,
|
|
|
|
.retrieve_reply = nullptr,
|
2016-05-12 23:43:17 +03:00
|
|
|
.forget_multi = disp_forget_multi,
|
2017-03-07 07:24:44 +03:00
|
|
|
.flock = nullptr,
|
|
|
|
.fallocate = nullptr,
|
2016-05-12 23:43:17 +03:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
const fuse_conn_info& Dispatcher::getConnInfo() const {
|
|
|
|
return connInfo_;
|
|
|
|
}
|
2016-05-12 23:43:17 +03:00
|
|
|
|
2017-08-18 21:43:55 +03:00
|
|
|
ThreadLocalEdenStats* Dispatcher::getStats() const {
|
2016-06-10 21:26:35 +03:00
|
|
|
return stats_;
|
|
|
|
}
|
2017-11-04 01:58:04 +03:00
|
|
|
} // namespace fusell
|
|
|
|
} // namespace eden
|
|
|
|
} // namespace facebook
|