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.
|
|
|
|
*
|
|
|
|
*/
|
2016-12-02 04:49:42 +03:00
|
|
|
#include "EdenDispatcher.h"
|
2016-05-12 23:43:17 +03:00
|
|
|
|
2016-12-23 05:11:59 +03:00
|
|
|
#include <folly/Format.h>
|
2017-10-23 00:33:08 +03:00
|
|
|
#include <folly/executors/CPUThreadPoolExecutor.h>
|
2017-10-05 22:59:42 +03:00
|
|
|
#include <folly/executors/GlobalExecutor.h>
|
2018-05-01 07:20:51 +03:00
|
|
|
#include <folly/logging/xlog.h>
|
2017-05-03 20:23:28 +03:00
|
|
|
#include <gflags/gflags.h>
|
Allow rm of files with corrupt overlay
Summary:
Sometimes, Eden's overlay (in `$client_dir/local/`) gets corrupt. In
particular, sometimes overlay files can be truncated or missing after a hard
reboot where the underlying filesystem state was not flushed to disk.
For such files, open(), stat(), unlink(), etc. from Eden report ENOENT, yet
readdir() on the containing directory shows that the file does exist.
In other words, the problematic file is undeletable:
```
$ ls -la dir/
/bin/ls: cannot access dir/corrupt_file: No such file or directory
total 0
drwxr-xr-x. 3 strager 0 Jul 10 21:41 .
drwxr-xr-x. 48 strager 0 Jul 10 21:41 ..
-?????????? ? ? ? ? corrupt_file
$ rm dir/corrupt_file
rm: cannot remove ‘dir/corrupt_file’: No such file or directory
```
Allow users to delete these problematic files (if the file was a regular file
and not a directory) by doing the following:
* Allow corrupt regular files to be unlink()d successfully.
* Allow corrupt regular files to be stat()d.
Making stat() succeed is a requirement by FUSE:
* For unlink(), FUSE performs FUSE_LOOKUP before FUSE_UNLINK. If FUSE_LOOKUP
fails, unlink() fails. Therefore, we must make FUSE_LOOKUP succeed for
corrupt files.
* For stat(), FUSE performs FUSE_LOOKUP and sometimes FUSE_GETATTR. Since we
must make FUSE_LOOKUP succeed (for unlink()), it's natural to make
FUSE_GETATTR succeed too.
A future diff will fix corrupted directories.
Reviewed By: chadaustin
Differential Revision: D8884793
fbshipit-source-id: 1100037bf52475fcca66f39946b917ce604f12dc
2018-07-26 06:52:58 +03:00
|
|
|
#include <cstring>
|
2016-05-12 23:43:17 +03:00
|
|
|
#include <shared_mutex>
|
2017-06-22 23:39:57 +03:00
|
|
|
|
2018-12-05 03:35:29 +03:00
|
|
|
#include "eden/fs/fuse/DirList.h"
|
2017-04-14 21:31:48 +03:00
|
|
|
#include "eden/fs/fuse/FileHandle.h"
|
|
|
|
#include "eden/fs/fuse/RequestData.h"
|
2017-06-22 23:39:57 +03:00
|
|
|
#include "eden/fs/inodes/EdenMount.h"
|
|
|
|
#include "eden/fs/inodes/FileInode.h"
|
|
|
|
#include "eden/fs/inodes/InodeMap.h"
|
Allow rm of files with corrupt overlay
Summary:
Sometimes, Eden's overlay (in `$client_dir/local/`) gets corrupt. In
particular, sometimes overlay files can be truncated or missing after a hard
reboot where the underlying filesystem state was not flushed to disk.
For such files, open(), stat(), unlink(), etc. from Eden report ENOENT, yet
readdir() on the containing directory shows that the file does exist.
In other words, the problematic file is undeletable:
```
$ ls -la dir/
/bin/ls: cannot access dir/corrupt_file: No such file or directory
total 0
drwxr-xr-x. 3 strager 0 Jul 10 21:41 .
drwxr-xr-x. 48 strager 0 Jul 10 21:41 ..
-?????????? ? ? ? ? corrupt_file
$ rm dir/corrupt_file
rm: cannot remove ‘dir/corrupt_file’: No such file or directory
```
Allow users to delete these problematic files (if the file was a regular file
and not a directory) by doing the following:
* Allow corrupt regular files to be unlink()d successfully.
* Allow corrupt regular files to be stat()d.
Making stat() succeed is a requirement by FUSE:
* For unlink(), FUSE performs FUSE_LOOKUP before FUSE_UNLINK. If FUSE_LOOKUP
fails, unlink() fails. Therefore, we must make FUSE_LOOKUP succeed for
corrupt files.
* For stat(), FUSE performs FUSE_LOOKUP and sometimes FUSE_GETATTR. Since we
must make FUSE_LOOKUP succeed (for unlink()), it's natural to make
FUSE_GETATTR succeed too.
A future diff will fix corrupted directories.
Reviewed By: chadaustin
Differential Revision: D8884793
fbshipit-source-id: 1100037bf52475fcca66f39946b917ce604f12dc
2018-07-26 06:52:58 +03:00
|
|
|
#include "eden/fs/inodes/Overlay.h"
|
2017-06-22 23:39:57 +03:00
|
|
|
#include "eden/fs/inodes/TreeInode.h"
|
2018-03-20 23:31:14 +03:00
|
|
|
#include "eden/fs/utils/SystemError.h"
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
using namespace folly;
|
|
|
|
using facebook::eden::PathComponent;
|
2017-11-04 01:58:04 +03:00
|
|
|
using facebook::eden::PathComponentPiece;
|
2016-05-12 23:43:17 +03:00
|
|
|
using facebook::eden::RelativePath;
|
|
|
|
using std::string;
|
|
|
|
using std::vector;
|
|
|
|
|
2016-05-26 19:49:08 +03:00
|
|
|
DEFINE_int32(
|
|
|
|
inode_reserve,
|
|
|
|
1000000,
|
|
|
|
"pre-size inode hash table for this many entries");
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
namespace facebook {
|
|
|
|
namespace eden {
|
|
|
|
|
2016-12-23 02:34:56 +03:00
|
|
|
EdenDispatcher::EdenDispatcher(EdenMount* mount)
|
2017-03-31 21:23:02 +03:00
|
|
|
: Dispatcher(mount->getStats()),
|
|
|
|
mount_(mount),
|
|
|
|
inodeMap_(mount_->getInodeMap()) {}
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
namespace {
|
2016-12-02 04:49:42 +03:00
|
|
|
|
2018-01-03 03:25:03 +03:00
|
|
|
/** Compute a fuse_entry_out */
|
|
|
|
fuse_entry_out computeEntryParam(
|
2018-03-20 03:01:15 +03:00
|
|
|
InodeNumber number,
|
|
|
|
const Dispatcher::Attr& attr) {
|
2018-09-20 22:49:41 +03:00
|
|
|
fuse_entry_out entry = {};
|
2018-02-27 23:40:30 +03:00
|
|
|
entry.nodeid = number.get();
|
2018-09-20 22:49:41 +03:00
|
|
|
entry.generation = 0;
|
2018-01-03 03:25:03 +03:00
|
|
|
auto fuse_attr = attr.asFuseAttr();
|
|
|
|
entry.attr = fuse_attr.attr;
|
|
|
|
entry.attr_valid = fuse_attr.attr_valid;
|
|
|
|
entry.attr_valid_nsec = fuse_attr.attr_valid_nsec;
|
|
|
|
entry.entry_valid = fuse_attr.attr_valid;
|
|
|
|
entry.entry_valid_nsec = fuse_attr.attr_valid_nsec;
|
2016-12-02 04:49:42 +03:00
|
|
|
return entry;
|
|
|
|
}
|
Allow rm of files with corrupt overlay
Summary:
Sometimes, Eden's overlay (in `$client_dir/local/`) gets corrupt. In
particular, sometimes overlay files can be truncated or missing after a hard
reboot where the underlying filesystem state was not flushed to disk.
For such files, open(), stat(), unlink(), etc. from Eden report ENOENT, yet
readdir() on the containing directory shows that the file does exist.
In other words, the problematic file is undeletable:
```
$ ls -la dir/
/bin/ls: cannot access dir/corrupt_file: No such file or directory
total 0
drwxr-xr-x. 3 strager 0 Jul 10 21:41 .
drwxr-xr-x. 48 strager 0 Jul 10 21:41 ..
-?????????? ? ? ? ? corrupt_file
$ rm dir/corrupt_file
rm: cannot remove ‘dir/corrupt_file’: No such file or directory
```
Allow users to delete these problematic files (if the file was a regular file
and not a directory) by doing the following:
* Allow corrupt regular files to be unlink()d successfully.
* Allow corrupt regular files to be stat()d.
Making stat() succeed is a requirement by FUSE:
* For unlink(), FUSE performs FUSE_LOOKUP before FUSE_UNLINK. If FUSE_LOOKUP
fails, unlink() fails. Therefore, we must make FUSE_LOOKUP succeed for
corrupt files.
* For stat(), FUSE performs FUSE_LOOKUP and sometimes FUSE_GETATTR. Since we
must make FUSE_LOOKUP succeed (for unlink()), it's natural to make
FUSE_GETATTR succeed too.
A future diff will fix corrupted directories.
Reviewed By: chadaustin
Differential Revision: D8884793
fbshipit-source-id: 1100037bf52475fcca66f39946b917ce604f12dc
2018-07-26 06:52:58 +03:00
|
|
|
|
|
|
|
Dispatcher::Attr attrForInodeWithCorruptOverlay() noexcept {
|
|
|
|
struct stat st;
|
|
|
|
std::memset(&st, 0, sizeof(st));
|
|
|
|
st.st_mode = S_IFREG;
|
|
|
|
return Dispatcher::Attr{st};
|
|
|
|
}
|
2017-11-04 01:58:04 +03:00
|
|
|
} // namespace
|
2016-05-12 23:43:17 +03:00
|
|
|
|
2018-03-20 03:01:15 +03:00
|
|
|
folly::Future<Dispatcher::Attr> EdenDispatcher::getattr(InodeNumber ino) {
|
2017-07-28 06:09:11 +03:00
|
|
|
FB_LOGF(mount_->getStraceLogger(), DBG7, "getattr({})", ino);
|
2018-07-25 09:29:25 +03:00
|
|
|
return inodeMap_->lookupInode(ino).thenValue(
|
2016-12-23 02:34:56 +03:00
|
|
|
[](const InodePtr& inode) { return inode->getattr(); });
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2018-12-05 12:32:49 +03:00
|
|
|
folly::Future<uint64_t> EdenDispatcher::opendir(InodeNumber ino, int flags) {
|
2018-01-03 03:25:03 +03:00
|
|
|
FB_LOGF(
|
|
|
|
mount_->getStraceLogger(), DBG7, "opendir({}, flags={:x})", ino, flags);
|
2018-12-05 12:32:49 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
folly::Future<folly::Unit> EdenDispatcher::releasedir(
|
|
|
|
InodeNumber ino,
|
|
|
|
uint64_t fh) {
|
|
|
|
FB_LOGF(mount_->getStraceLogger(), DBG7, "releasedir({}, {})", ino, fh);
|
|
|
|
return folly::unit;
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2018-01-03 03:25:03 +03:00
|
|
|
folly::Future<fuse_entry_out> EdenDispatcher::lookup(
|
2018-03-20 03:01:15 +03:00
|
|
|
InodeNumber parent,
|
2016-05-12 23:43:17 +03:00
|
|
|
PathComponentPiece namepiece) {
|
2017-07-28 06:09:11 +03:00
|
|
|
FB_LOGF(mount_->getStraceLogger(), DBG7, "lookup({}, {})", parent, namepiece);
|
2016-12-23 02:34:56 +03:00
|
|
|
return inodeMap_->lookupTreeInode(parent)
|
2018-10-23 23:39:59 +03:00
|
|
|
.thenValue([name = PathComponent(namepiece)](const TreeInodePtr& tree) {
|
2016-12-23 02:34:56 +03:00
|
|
|
return tree->getOrLoadChild(name);
|
|
|
|
})
|
2018-10-23 23:39:59 +03:00
|
|
|
.thenValue([](const InodePtr& inode) {
|
Allow rm of files with corrupt overlay
Summary:
Sometimes, Eden's overlay (in `$client_dir/local/`) gets corrupt. In
particular, sometimes overlay files can be truncated or missing after a hard
reboot where the underlying filesystem state was not flushed to disk.
For such files, open(), stat(), unlink(), etc. from Eden report ENOENT, yet
readdir() on the containing directory shows that the file does exist.
In other words, the problematic file is undeletable:
```
$ ls -la dir/
/bin/ls: cannot access dir/corrupt_file: No such file or directory
total 0
drwxr-xr-x. 3 strager 0 Jul 10 21:41 .
drwxr-xr-x. 48 strager 0 Jul 10 21:41 ..
-?????????? ? ? ? ? corrupt_file
$ rm dir/corrupt_file
rm: cannot remove ‘dir/corrupt_file’: No such file or directory
```
Allow users to delete these problematic files (if the file was a regular file
and not a directory) by doing the following:
* Allow corrupt regular files to be unlink()d successfully.
* Allow corrupt regular files to be stat()d.
Making stat() succeed is a requirement by FUSE:
* For unlink(), FUSE performs FUSE_LOOKUP before FUSE_UNLINK. If FUSE_LOOKUP
fails, unlink() fails. Therefore, we must make FUSE_LOOKUP succeed for
corrupt files.
* For stat(), FUSE performs FUSE_LOOKUP and sometimes FUSE_GETATTR. Since we
must make FUSE_LOOKUP succeed (for unlink()), it's natural to make
FUSE_GETATTR succeed too.
A future diff will fix corrupted directories.
Reviewed By: chadaustin
Differential Revision: D8884793
fbshipit-source-id: 1100037bf52475fcca66f39946b917ce604f12dc
2018-07-26 06:52:58 +03:00
|
|
|
return folly::makeFutureWith([&]() { return inode->getattr(); })
|
2018-10-23 23:39:59 +03:00
|
|
|
.thenTry([inode](folly::Try<Dispatcher::Attr> maybeAttr) {
|
Allow rm of files with corrupt overlay
Summary:
Sometimes, Eden's overlay (in `$client_dir/local/`) gets corrupt. In
particular, sometimes overlay files can be truncated or missing after a hard
reboot where the underlying filesystem state was not flushed to disk.
For such files, open(), stat(), unlink(), etc. from Eden report ENOENT, yet
readdir() on the containing directory shows that the file does exist.
In other words, the problematic file is undeletable:
```
$ ls -la dir/
/bin/ls: cannot access dir/corrupt_file: No such file or directory
total 0
drwxr-xr-x. 3 strager 0 Jul 10 21:41 .
drwxr-xr-x. 48 strager 0 Jul 10 21:41 ..
-?????????? ? ? ? ? corrupt_file
$ rm dir/corrupt_file
rm: cannot remove ‘dir/corrupt_file’: No such file or directory
```
Allow users to delete these problematic files (if the file was a regular file
and not a directory) by doing the following:
* Allow corrupt regular files to be unlink()d successfully.
* Allow corrupt regular files to be stat()d.
Making stat() succeed is a requirement by FUSE:
* For unlink(), FUSE performs FUSE_LOOKUP before FUSE_UNLINK. If FUSE_LOOKUP
fails, unlink() fails. Therefore, we must make FUSE_LOOKUP succeed for
corrupt files.
* For stat(), FUSE performs FUSE_LOOKUP and sometimes FUSE_GETATTR. Since we
must make FUSE_LOOKUP succeed (for unlink()), it's natural to make
FUSE_GETATTR succeed too.
A future diff will fix corrupted directories.
Reviewed By: chadaustin
Differential Revision: D8884793
fbshipit-source-id: 1100037bf52475fcca66f39946b917ce604f12dc
2018-07-26 06:52:58 +03:00
|
|
|
if (maybeAttr.hasValue()) {
|
|
|
|
inode->incFuseRefcount();
|
|
|
|
return computeEntryParam(inode->getNodeId(), maybeAttr.value());
|
|
|
|
} else {
|
|
|
|
// The most common case for getattr() failing is if this file is
|
|
|
|
// materialized but the data for it in the overlay is missing
|
|
|
|
// or corrupt. This can happen after a hard reboot where the
|
|
|
|
// overlay data was not synced to disk first.
|
|
|
|
//
|
|
|
|
// We intentionally want to return a result here rather than
|
|
|
|
// failing; otherwise we can't return the inode number to the
|
|
|
|
// kernel at all. This blocks other operations on the file,
|
|
|
|
// like FUSE_UNLINK. By successfully returning from the
|
|
|
|
// lookup we allow clients to remove this corrupt file with an
|
|
|
|
// unlink operation. (Even though FUSE_UNLINK does not require
|
|
|
|
// the child inode number, the kernel does not appear to send a
|
|
|
|
// FUSE_UNLINK request to us if it could not get the child inode
|
|
|
|
// number first.)
|
|
|
|
XLOG(WARN) << "error getting attributes for inode "
|
|
|
|
<< inode->getNodeId() << " (" << inode->getLogPath()
|
|
|
|
<< "): " << maybeAttr.exception().what();
|
|
|
|
inode->incFuseRefcount();
|
|
|
|
return computeEntryParam(
|
|
|
|
inode->getNodeId(), attrForInodeWithCorruptOverlay());
|
|
|
|
}
|
|
|
|
});
|
2018-02-27 06:39:06 +03:00
|
|
|
})
|
2019-01-30 20:45:02 +03:00
|
|
|
.thenError(
|
|
|
|
folly::tag_t<std::system_error>{}, [](const std::system_error& err) {
|
|
|
|
// Translate ENOENT into a successful response with an
|
|
|
|
// inode number of 0 and a large entry_valid time, to let the kernel
|
|
|
|
// cache this negative lookup result.
|
|
|
|
if (isEnoent(err)) {
|
|
|
|
fuse_entry_out entry = {};
|
|
|
|
entry.attr_valid =
|
|
|
|
std::numeric_limits<decltype(entry.attr_valid)>::max();
|
|
|
|
entry.entry_valid =
|
|
|
|
std::numeric_limits<decltype(entry.entry_valid)>::max();
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
throw err;
|
|
|
|
});
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2018-03-20 03:01:15 +03:00
|
|
|
folly::Future<Dispatcher::Attr> EdenDispatcher::setattr(
|
|
|
|
InodeNumber ino,
|
2018-01-03 03:25:03 +03:00
|
|
|
const fuse_setattr_in& attr) {
|
2017-07-28 06:09:11 +03:00
|
|
|
FB_LOGF(mount_->getStraceLogger(), DBG7, "setattr({})", ino);
|
2018-07-25 09:29:25 +03:00
|
|
|
return inodeMap_->lookupInode(ino).thenValue(
|
2018-01-03 03:25:03 +03:00
|
|
|
[attr](const InodePtr& inode) { return inode->setattr(attr); });
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2018-04-27 06:41:40 +03:00
|
|
|
void EdenDispatcher::forget(InodeNumber ino, unsigned long nlookup) {
|
2017-07-28 06:09:11 +03:00
|
|
|
FB_LOGF(mount_->getStraceLogger(), DBG7, "forget({}, {})", ino, nlookup);
|
2017-01-18 02:01:43 +03:00
|
|
|
inodeMap_->decFuseRefcount(ino, nlookup);
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2018-12-13 23:18:53 +03:00
|
|
|
folly::Future<uint64_t> EdenDispatcher::open(InodeNumber ino, int flags) {
|
2018-01-03 03:25:03 +03:00
|
|
|
FB_LOGF(mount_->getStraceLogger(), DBG7, "open({}, flags={:x})", ino, flags);
|
2018-12-18 07:11:12 +03:00
|
|
|
#ifdef FUSE_NO_OPEN_SUPPORT
|
2018-12-13 08:46:58 +03:00
|
|
|
if (getConnInfo().flags & FUSE_NO_OPEN_SUPPORT) {
|
|
|
|
// If the kernel understands FUSE_NO_OPEN_SUPPORT, then returning ENOSYS
|
|
|
|
// means that no further open() nor release() calls will make it into Eden.
|
|
|
|
folly::throwSystemErrorExplicit(
|
|
|
|
ENOSYS, "Eden open() calls are stateless and not required");
|
|
|
|
}
|
2018-12-18 07:11:12 +03:00
|
|
|
#endif
|
|
|
|
return 0;
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2018-12-13 03:48:11 +03:00
|
|
|
folly::Future<fuse_entry_out> EdenDispatcher::create(
|
2018-03-20 03:01:15 +03:00
|
|
|
InodeNumber parent,
|
2016-05-12 23:43:17 +03:00
|
|
|
PathComponentPiece name,
|
|
|
|
mode_t mode,
|
|
|
|
int flags) {
|
2017-07-21 16:48:03 +03:00
|
|
|
FB_LOGF(
|
2017-07-28 06:09:11 +03:00
|
|
|
mount_->getStraceLogger(),
|
2017-07-21 16:48:03 +03:00
|
|
|
DBG7,
|
|
|
|
"create({}, {}, {:#x}, {:#x})",
|
|
|
|
parent,
|
|
|
|
name,
|
|
|
|
mode,
|
|
|
|
flags);
|
2016-12-23 02:34:56 +03:00
|
|
|
return inodeMap_->lookupTreeInode(parent)
|
2018-10-23 23:39:59 +03:00
|
|
|
.thenValue([childName = PathComponent{name}, mode, flags](
|
|
|
|
const TreeInodePtr& parentInode) {
|
2016-12-23 02:34:56 +03:00
|
|
|
return parentInode->create(childName, mode, flags);
|
|
|
|
})
|
2018-10-23 23:39:59 +03:00
|
|
|
.thenValue([=](TreeInode::CreateResult created) {
|
2017-01-18 02:01:43 +03:00
|
|
|
created.inode->incFuseRefcount();
|
2018-12-13 03:48:11 +03:00
|
|
|
return computeEntryParam(created.inode->getNodeId(), created.attr);
|
2016-05-12 23:43:17 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-10-09 01:08:35 +03:00
|
|
|
folly::Future<BufVec>
|
|
|
|
EdenDispatcher::read(InodeNumber ino, size_t size, off_t off) {
|
|
|
|
FB_LOGF(
|
|
|
|
mount_->getStraceLogger(),
|
|
|
|
DBG7,
|
|
|
|
"read({}, off={}, len={})",
|
|
|
|
ino,
|
|
|
|
off,
|
|
|
|
size);
|
|
|
|
return inodeMap_->lookupFileInode(ino).thenValue(
|
|
|
|
[size, off](FileInodePtr&& inode) { return inode->read(size, off); });
|
|
|
|
}
|
|
|
|
|
2018-12-13 03:48:11 +03:00
|
|
|
folly::Future<size_t>
|
|
|
|
EdenDispatcher::write(InodeNumber ino, folly::StringPiece data, off_t off) {
|
2018-10-09 01:08:37 +03:00
|
|
|
FB_LOGF(
|
|
|
|
mount_->getStraceLogger(),
|
|
|
|
DBG7,
|
|
|
|
"write({}, off={}, len={})",
|
|
|
|
ino,
|
|
|
|
off,
|
|
|
|
data.size());
|
|
|
|
return inodeMap_->lookupFileInode(ino).thenValue(
|
2018-12-13 03:48:09 +03:00
|
|
|
[copy = data.str(), off](FileInodePtr&& inode) {
|
2018-10-09 01:08:37 +03:00
|
|
|
return inode->write(copy, off);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-10-08 21:11:37 +03:00
|
|
|
folly::Future<folly::Unit> EdenDispatcher::fsync(
|
|
|
|
InodeNumber ino,
|
|
|
|
bool datasync) {
|
|
|
|
FB_LOGF(mount_->getStraceLogger(), DBG7, "fsync({})", ino);
|
|
|
|
return inodeMap_->lookupFileInode(ino).thenValue(
|
|
|
|
[datasync](FileInodePtr inode) { return inode->fsync(datasync); });
|
|
|
|
};
|
|
|
|
|
2018-11-22 11:43:41 +03:00
|
|
|
folly::Future<std::string> EdenDispatcher::readlink(
|
|
|
|
InodeNumber ino,
|
|
|
|
bool kernelCachesReadlink) {
|
2017-07-28 06:09:11 +03:00
|
|
|
FB_LOGF(mount_->getStraceLogger(), DBG7, "readlink({})", ino);
|
2018-10-23 23:39:59 +03:00
|
|
|
return inodeMap_->lookupFileInode(ino).thenValue(
|
2018-11-22 11:43:41 +03:00
|
|
|
[kernelCachesReadlink](const FileInodePtr& inode) {
|
|
|
|
// Only release the symlink blob after it's loaded if we can assume the
|
|
|
|
// FUSE will cache the result in the kernel's page cache.
|
|
|
|
return inode->readlink(
|
|
|
|
kernelCachesReadlink ? CacheHint::NotNeededAgain
|
|
|
|
: CacheHint::LikelyNeededAgain);
|
|
|
|
});
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2018-12-05 12:32:49 +03:00
|
|
|
folly::Future<DirList> EdenDispatcher::readdir(
|
|
|
|
InodeNumber ino,
|
|
|
|
DirList&& dirList,
|
|
|
|
off_t offset,
|
|
|
|
uint64_t /*fh*/) {
|
2018-12-05 03:35:29 +03:00
|
|
|
FB_LOGF(mount_->getStraceLogger(), DBG7, "readdir({}, {})", ino, offset);
|
|
|
|
return inodeMap_->lookupTreeInode(ino).thenValue(
|
|
|
|
[dirList = std::move(dirList), offset](TreeInodePtr inode) mutable {
|
|
|
|
return inode->readdir(std::move(dirList), offset);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-01-03 03:25:03 +03:00
|
|
|
folly::Future<fuse_entry_out> EdenDispatcher::mknod(
|
2018-03-20 03:01:15 +03:00
|
|
|
InodeNumber parent,
|
2016-05-12 23:43:17 +03:00
|
|
|
PathComponentPiece name,
|
|
|
|
mode_t mode,
|
|
|
|
dev_t rdev) {
|
2017-07-21 16:48:03 +03:00
|
|
|
FB_LOGF(
|
2017-07-28 06:09:11 +03:00
|
|
|
mount_->getStraceLogger(),
|
2017-07-21 16:48:03 +03:00
|
|
|
DBG7,
|
|
|
|
"mknod({}, {}, {:#x}, {:#x})",
|
|
|
|
parent,
|
|
|
|
name,
|
|
|
|
mode,
|
|
|
|
rdev);
|
2018-10-23 23:39:59 +03:00
|
|
|
return inodeMap_->lookupTreeInode(parent).thenValue(
|
2017-11-04 01:58:04 +03:00
|
|
|
[childName = PathComponent{name}, mode, rdev](const TreeInodePtr& inode) {
|
2017-03-31 09:38:42 +03:00
|
|
|
auto child = inode->mknod(childName, mode, rdev);
|
2018-09-15 02:57:46 +03:00
|
|
|
return child->getattr().thenValue([child](Dispatcher::Attr attr) {
|
2017-03-31 09:38:42 +03:00
|
|
|
child->incFuseRefcount();
|
|
|
|
return computeEntryParam(child->getNodeId(), attr);
|
|
|
|
});
|
|
|
|
});
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2018-01-03 03:25:03 +03:00
|
|
|
folly::Future<fuse_entry_out> EdenDispatcher::mkdir(
|
2018-03-20 03:01:15 +03:00
|
|
|
InodeNumber parent,
|
2018-01-03 03:25:03 +03:00
|
|
|
PathComponentPiece name,
|
|
|
|
mode_t mode) {
|
2017-07-21 16:48:03 +03:00
|
|
|
FB_LOGF(
|
2017-07-28 06:09:11 +03:00
|
|
|
mount_->getStraceLogger(),
|
|
|
|
DBG7,
|
|
|
|
"mkdir({}, {}, {:#x})",
|
|
|
|
parent,
|
|
|
|
name,
|
|
|
|
mode);
|
2018-10-23 23:39:59 +03:00
|
|
|
return inodeMap_->lookupTreeInode(parent).thenValue(
|
2017-11-04 01:58:04 +03:00
|
|
|
[childName = PathComponent{name}, mode](const TreeInodePtr& inode) {
|
2016-12-23 02:34:56 +03:00
|
|
|
auto child = inode->mkdir(childName, mode);
|
2018-09-15 02:57:46 +03:00
|
|
|
return child->getattr().thenValue([child](Dispatcher::Attr attr) {
|
2017-01-18 02:01:43 +03:00
|
|
|
child->incFuseRefcount();
|
|
|
|
return computeEntryParam(child->getNodeId(), attr);
|
2016-12-23 02:34:56 +03:00
|
|
|
});
|
|
|
|
});
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2016-12-02 04:49:42 +03:00
|
|
|
folly::Future<folly::Unit> EdenDispatcher::unlink(
|
2018-03-20 03:01:15 +03:00
|
|
|
InodeNumber parent,
|
2016-05-12 23:43:17 +03:00
|
|
|
PathComponentPiece name) {
|
2017-07-28 06:09:11 +03:00
|
|
|
FB_LOGF(mount_->getStraceLogger(), DBG7, "unlink({}, {})", parent, name);
|
2018-10-23 23:39:59 +03:00
|
|
|
return inodeMap_->lookupTreeInode(parent).thenValue(
|
2018-06-01 20:55:42 +03:00
|
|
|
[childName = PathComponent{name}](const TreeInodePtr& inode) {
|
2018-04-27 06:41:38 +03:00
|
|
|
return inode->unlink(childName);
|
2016-05-12 23:43:17 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-12-02 04:49:42 +03:00
|
|
|
folly::Future<folly::Unit> EdenDispatcher::rmdir(
|
2018-03-20 03:01:15 +03:00
|
|
|
InodeNumber parent,
|
2016-05-12 23:43:17 +03:00
|
|
|
PathComponentPiece name) {
|
2017-07-28 06:09:11 +03:00
|
|
|
FB_LOGF(mount_->getStraceLogger(), DBG7, "rmdir({}, {})", parent, name);
|
2018-10-23 23:39:59 +03:00
|
|
|
return inodeMap_->lookupTreeInode(parent).thenValue(
|
2017-11-04 01:58:04 +03:00
|
|
|
[childName = PathComponent{name}](const TreeInodePtr& inode) {
|
2016-12-23 02:34:56 +03:00
|
|
|
return inode->rmdir(childName);
|
2016-05-12 23:43:17 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-01-03 03:25:03 +03:00
|
|
|
folly::Future<fuse_entry_out> EdenDispatcher::symlink(
|
2018-03-20 03:01:15 +03:00
|
|
|
InodeNumber parent,
|
2016-12-15 02:35:06 +03:00
|
|
|
PathComponentPiece name,
|
|
|
|
StringPiece link) {
|
2017-07-28 06:09:11 +03:00
|
|
|
FB_LOGF(
|
|
|
|
mount_->getStraceLogger(), DBG7, "rmdir({}, {}, {})", parent, name, link);
|
2018-10-23 23:39:59 +03:00
|
|
|
return inodeMap_->lookupTreeInode(parent).thenValue(
|
2017-11-04 01:58:04 +03:00
|
|
|
[linkContents = link.str(),
|
|
|
|
childName = PathComponent{name}](const TreeInodePtr& inode) {
|
2017-03-02 19:16:18 +03:00
|
|
|
auto symlinkInode = inode->symlink(childName, linkContents);
|
|
|
|
symlinkInode->incFuseRefcount();
|
2018-09-15 02:57:46 +03:00
|
|
|
return symlinkInode->getattr().thenValue([symlinkInode](Attr&& attr) {
|
2017-03-02 19:16:18 +03:00
|
|
|
return computeEntryParam(symlinkInode->getNodeId(), attr);
|
|
|
|
});
|
2016-12-23 02:34:56 +03:00
|
|
|
});
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2016-12-02 04:49:42 +03:00
|
|
|
folly::Future<folly::Unit> EdenDispatcher::rename(
|
2018-03-20 03:01:15 +03:00
|
|
|
InodeNumber parent,
|
2016-12-23 02:34:56 +03:00
|
|
|
PathComponentPiece namePiece,
|
2018-03-20 03:01:15 +03:00
|
|
|
InodeNumber newParent,
|
2016-12-23 02:34:56 +03:00
|
|
|
PathComponentPiece newNamePiece) {
|
2017-07-21 16:48:03 +03:00
|
|
|
FB_LOGF(
|
2017-07-28 06:09:11 +03:00
|
|
|
mount_->getStraceLogger(),
|
2017-07-21 16:48:03 +03:00
|
|
|
DBG7,
|
|
|
|
"rename({}, {}, {}, {})",
|
|
|
|
parent,
|
|
|
|
namePiece,
|
|
|
|
newParent,
|
|
|
|
newNamePiece);
|
2016-12-23 02:34:56 +03:00
|
|
|
// Start looking up both parents
|
|
|
|
auto parentFuture = inodeMap_->lookupTreeInode(parent);
|
|
|
|
auto newParentFuture = inodeMap_->lookupTreeInode(newParent);
|
|
|
|
// Do the rename once we have looked up both parents.
|
2018-08-04 09:24:50 +03:00
|
|
|
return std::move(parentFuture)
|
2018-10-23 23:39:59 +03:00
|
|
|
.thenValue([npFuture = std::move(newParentFuture),
|
|
|
|
name = PathComponent{namePiece},
|
|
|
|
newName = PathComponent{newNamePiece}](
|
|
|
|
const TreeInodePtr& parent) mutable {
|
|
|
|
return std::move(npFuture).thenValue(
|
2018-08-04 09:24:50 +03:00
|
|
|
[parent, name, newName](const TreeInodePtr& newParent) {
|
|
|
|
return parent->rename(name, newParent, newName);
|
|
|
|
});
|
|
|
|
});
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2018-01-03 03:25:03 +03:00
|
|
|
folly::Future<fuse_entry_out> EdenDispatcher::link(
|
2018-03-20 03:01:15 +03:00
|
|
|
InodeNumber ino,
|
|
|
|
InodeNumber newParent,
|
2016-12-23 05:11:59 +03:00
|
|
|
PathComponentPiece newName) {
|
2017-07-21 16:48:03 +03:00
|
|
|
FB_LOGF(
|
2017-07-28 06:09:11 +03:00
|
|
|
mount_->getStraceLogger(),
|
|
|
|
DBG7,
|
|
|
|
"link({}, {}, {})",
|
|
|
|
ino,
|
|
|
|
newParent,
|
|
|
|
newName);
|
2017-07-21 16:48:03 +03:00
|
|
|
|
2018-05-31 09:07:08 +03:00
|
|
|
validatePathComponentLength(newName);
|
|
|
|
|
2016-12-02 04:49:43 +03:00
|
|
|
// We intentionally do not support hard links.
|
|
|
|
// These generally cannot be tracked in source control (git or mercurial)
|
|
|
|
// and are not portable to non-Unix platforms.
|
|
|
|
folly::throwSystemErrorExplicit(
|
|
|
|
EPERM, "hard links are not supported in eden mount points");
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2018-03-20 03:01:15 +03:00
|
|
|
Future<string> EdenDispatcher::getxattr(InodeNumber ino, StringPiece name) {
|
2017-07-28 06:09:11 +03:00
|
|
|
FB_LOGF(mount_->getStraceLogger(), DBG7, "getxattr({}, {})", ino, name);
|
2018-09-15 02:57:46 +03:00
|
|
|
return inodeMap_->lookupInode(ino).thenValue(
|
2017-11-04 01:58:04 +03:00
|
|
|
[attrName = name.str()](const InodePtr& inode) {
|
|
|
|
return inode->getxattr(attrName);
|
|
|
|
});
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2018-03-20 03:01:15 +03:00
|
|
|
Future<vector<string>> EdenDispatcher::listxattr(InodeNumber ino) {
|
2017-07-28 06:09:11 +03:00
|
|
|
FB_LOGF(mount_->getStraceLogger(), DBG7, "listxattr({})", ino);
|
2018-07-25 09:29:25 +03:00
|
|
|
return inodeMap_->lookupInode(ino).thenValue(
|
2016-12-23 02:34:56 +03:00
|
|
|
[](const InodePtr& inode) { return inode->listxattr(); });
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
2017-11-04 01:58:04 +03:00
|
|
|
} // namespace eden
|
|
|
|
} // namespace facebook
|