sapling/eden/fs/inodes/InodeBase.cpp
Adam Simpkins 0156f01d51 Update InodeBase to contain a pointer to its EdenMount
Summary:
Add an EdenMount* member variable to InodeBase.  Previously each TreeInode kept
a pointer to its EdenMount, and this moves that into the InodeBase class.

This is needed to support upcoming diffs that will change InodeBase memory
management.  InodeBase objects will be responsible for notifying the InodeMap
when they become unreferenced.

Reviewed By: bolinfest

Differential Revision: D4348079

fbshipit-source-id: 6bf7ea908c6096aa2bca5b21290c09cbd58d5af7
2016-12-22 15:36:29 -08:00

197 lines
5.8 KiB
C++

/*
* Copyright (c) 2016, Facebook, Inc.
* 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.
*
*/
#include "InodeBase.h"
#include <folly/Likely.h>
#include "TreeInode.h"
using namespace folly;
namespace facebook {
namespace eden {
InodeBase::~InodeBase() {
VLOG(5) << "inode " << this << " destroyed: " << getLogPath();
}
InodeBase::InodeBase(EdenMount* mount)
: ino_(FUSE_ROOT_ID),
mount_{mount},
location_{LocationInfo{
nullptr,
PathComponentPiece{"", detail::SkipPathSanityCheck()}}} {}
InodeBase::InodeBase(
fuse_ino_t ino,
TreeInodePtr parent,
PathComponentPiece name)
: ino_(ino),
mount_(parent->mount_),
location_(LocationInfo(std::move(parent), name)) {
// Inode numbers generally shouldn't be 0.
// Older versions of glibc have bugs handling files with an inode number of 0
DCHECK_NE(ino_, 0);
VLOG(5) << "inode " << this << " created: " << getLogPath();
}
// See Dispatcher::getattr
folly::Future<fusell::Dispatcher::Attr> InodeBase::getattr() {
FUSELL_NOT_IMPL();
}
// See Dispatcher::setattr
folly::Future<fusell::Dispatcher::Attr> InodeBase::setattr(
const struct stat& /* attr */,
int /* to_set */) {
FUSELL_NOT_IMPL();
}
folly::Future<folly::Unit> InodeBase::setxattr(folly::StringPiece name,
folly::StringPiece value,
int flags) {
FUSELL_NOT_IMPL();
}
folly::Future<std::string> InodeBase::getxattr(folly::StringPiece name) {
FUSELL_NOT_IMPL();
}
folly::Future<std::vector<std::string>> InodeBase::listxattr() {
FUSELL_NOT_IMPL();
}
folly::Future<folly::Unit> InodeBase::removexattr(folly::StringPiece name) {
FUSELL_NOT_IMPL();
}
folly::Future<folly::Unit> InodeBase::access(int mask) {
FUSELL_NOT_IMPL();
}
/**
* Helper function for getPath() and getLogPath()
*
* Populates the names vector with the list of PathComponents from the root
* down to this inode.
*
* This method should not be called on the root inode. The caller is
* responsible for checking that before calling getPathHelper().
*
* Returns true if the the file exists at the given path, or false if the file
* has been unlinked.
*
* If stopOnUnlinked is true, it breaks immediately when it finds that the file
* has been unlinked. The contents of the names vector are then undefined if
* the function returns false.
*
* If stopOnUnlinked is false it continues building the names vector even if
* the file is unlinked, which will then contain the path that the file used to
* exist at. (This path should be used only for logging purposes at that
* point.)
*/
bool InodeBase::getPathHelper(
std::vector<PathComponent>& names,
bool stopOnUnlinked) const {
TreeInodePtr parent;
bool unlinked = false;
{
auto loc = location_.rlock();
if (loc->unlinked) {
if (stopOnUnlinked) {
return false;
}
unlinked = true;
}
parent = loc->parent;
// Our caller should ensure that we are not the root
DCHECK(parent);
names.push_back(loc->name);
}
while (true) {
// Stop at the root inode.
// We check for this based on inode number so we can stop without having to
// acquire the root inode's location lock. (Otherwise all path lookups
// would have to acquire the root's lock, making it more likely to be
// contended.)
if (parent->ino_ == FUSE_ROOT_ID) {
// Reverse the names vector, since we built it from bottom to top.
std::reverse(names.begin(), names.end());
return !unlinked;
}
auto loc = parent->location_.rlock();
// In general our parent should not be unlinked if we are not unlinked,
// which we checked above. However, we have since released our location
// lock, so it's possible (but unlikely) that someone unlinked us and our
// parent directories since we checked above.
if (UNLIKELY(loc->unlinked)) {
if (stopOnUnlinked) {
return false;
}
unlinked = true;
}
names.push_back(loc->name);
parent = loc->parent;
DCHECK(parent);
}
}
folly::Optional<RelativePath> InodeBase::getPath() const {
if (ino_ == FUSE_ROOT_ID) {
return RelativePath();
}
std::vector<PathComponent> names;
if (!getPathHelper(names, true)) {
return folly::none;
}
return RelativePath(names);
}
std::string InodeBase::getLogPath() const {
if (ino_ == FUSE_ROOT_ID) {
// We use "<root>" here instead of the empty string to make log messages
// more understandable. The empty string would likely be confusing, as it
// would appear if the file name were missing.
return "<root>";
}
std::vector<PathComponent> names;
bool unlinked = !getPathHelper(names, false);
auto path = RelativePath(names);
if (unlinked) {
return folly::to<std::string>("<deleted:", path.stringPiece(), ">");
}
// TODO: We should probably adjust the PathFuncs code to use std::string
// instead of fbstring. For FB builds, std::string is the fbstring
// implementation. For external builds, with gcc 5+, std::string is very
// similar to fbstring anyway.
//
// return std::move(path).value();
return path.stringPiece().str();
}
void InodeBase::markUnlinked() {
VLOG(5) << "inode " << this << " unlinked: " << getLogPath();
auto loc = location_.wlock();
DCHECK(!loc->unlinked);
loc->unlinked = true;
}
void InodeBase::updateLocation(
TreeInodePtr newParent,
PathComponentPiece newName) {
VLOG(5) << "inode " << this << " renamed: " << getLogPath() << " --> "
<< newParent->getLogPath() << " / \"" << newName << "\"";
auto loc = location_.wlock();
DCHECK(!loc->unlinked);
loc->parent = newParent;
loc->name = newName.copy();
}
}
}