sapling/eden/fs/fuse/Dispatcher.h

397 lines
11 KiB
C
Raw Normal View History

/*
* Copyright (c) 2016-present, 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.
*
*/
#pragma once
#include <errno.h>
#include <folly/Exception.h>
#include <folly/Portability.h>
#include <folly/Range.h>
#include <folly/ThreadLocal.h>
#include <folly/futures/Future.h>
#include "eden/fs/fuse/EdenStats.h"
#include "eden/fs/fuse/FileHandleMap.h"
#include "eden/fs/fuse/fuse_headers.h"
#include "eden/fs/utils/PathFuncs.h"
namespace facebook {
namespace eden {
namespace fusell {
#define FUSELL_NOT_IMPL() \
do { \
LOG_FIRST_N(ERROR, 1) << __PRETTY_FUNCTION__ << " not implemented"; \
folly::throwSystemErrorExplicit(ENOSYS, __PRETTY_FUNCTION__); \
} while (0)
class Dispatcher;
class RequestData;
class FileHandle;
class DirHandle;
class MountPoint;
re-organize the fuse Channel and Session code Summary: The higher level goal is to make it easier to deal with the graceful restart scenario. This diff removes the SessionDeleter class and effectively renames the Channel class to FuseChannel. The FuseChannel represents the channel to the kernel; it can be constructed from a fuse device descriptor that has been obtained either from the privhelper at mount time, or from the graceful restart procedure. Importantly for graceful restart, it is possible to move the fuse device descriptor out of the FuseChannel so that it can be transferred to a new eden process. The graceful restart procedure requires a bit more control over the lifecycle of the fuse event loop so this diff also takes over managing the thread pool for the worker threads. The threads are owned by the MountPoint class which continues to be responsible for starting and stopping the fuse session and notifying EdenServer when it has finished. A nice side effect of this change is that we can remove a couple of inelegant aspects of the integration; the stack size env var stuff and the redundant extra thread to wait for the loop to finish. I opted to expose the dispatcher ops struct via an `extern` to simplify the code in the MountPoint class and avoid adding special interfaces for passing the ops around; they're constant anyway so this doesn't feel especially egregious. Reviewed By: bolinfest Differential Revision: D5751521 fbshipit-source-id: 5ba4fff48f3efb31a809adfc7787555711f649c9
2017-09-09 05:15:17 +03:00
/** Low level fuse operations are exposed here so that we can
* tie them into the fuse channel in the MountPoint class. */
extern const fuse_lowlevel_ops dispatcher_ops;
class Dispatcher {
fuse_conn_info connInfo_;
ThreadLocalEdenStats* stats_{nullptr};
FileHandleMap fileHandles_;
std::atomic<size_t> numOutstandingRequests_{0};
public:
virtual ~Dispatcher();
explicit Dispatcher(ThreadLocalEdenStats* stats);
static void disp_init(void* userdata, struct fuse_conn_info* conn);
ThreadLocalEdenStats* getStats() const;
/**
* Called by RequestData to advise of requests that are in-flight
* and pending completion.
*/
inline void incNumOutstandingRequests() {
numOutstandingRequests_++;
}
inline void decNumOutstandingRequests() {
numOutstandingRequests_--;
}
/**
* Returns true if there are no outstanding fuse requests.
* This is intended to be used only after the associated fuse
* channel has stopped servicing new requests during graceful
* shutdown; once that has happened, and hasOutstandingRequests()
* returns false we know that it is safe to proceed with the
* graceful shutdown. */
inline bool hasOutstandingRequests() const {
return numOutstandingRequests_ == 0;
}
const fuse_conn_info& getConnInfo() const;
FileHandleMap& getFileHandles();
// delegates to FileHandleMap::getGenericFileHandle
std::shared_ptr<FileHandleBase> getGenericFileHandle(uint64_t fh);
// delegates to FileHandleMap::getFileHandle
std::shared_ptr<FileHandle> getFileHandle(uint64_t fh);
// delegates to FileHandleMap::getDirHandle
std::shared_ptr<DirHandle> getDirHandle(uint64_t dh);
/**
* Called during filesystem mounting. It informs the filesystem
* of kernel capabilities and provides an opportunity to poke some
* flags and limits in the conn_info to report capabilities back
* to the kernel
*/
virtual void initConnection(fuse_conn_info& conn);
/**
* Called when fuse is tearing down the session
*/
virtual void destroy();
/**
* Lookup a directory entry by name and get its attributes
*/
virtual folly::Future<fuse_entry_param> lookup(
fuse_ino_t parent,
PathComponentPiece name);
/**
* Forget about an inode
*
* The nlookup parameter indicates the number of lookups
* previously performed on this inode.
*
* If the filesystem implements inode lifetimes, it is recommended
* that inodes acquire a single reference on each lookup, and lose
* nlookup references on each forget.
*
* The filesystem may ignore forget calls, if the inodes don't
* need to have a limited lifetime.
*
* On unmount it is not guaranteed, that all referenced inodes
* will receive a forget message.
*
* @param ino the inode number
* @param nlookup the number of lookups to forget
*/
virtual folly::Future<folly::Unit> forget(
fuse_ino_t ino,
unsigned long nlookup);
/**
* The stat information and the cache TTL for the kernel
*
* The timeout value is measured in seconds and indicates how long
* the kernel side of the FUSE will cache the values in the
* struct stat before calling getattr() again to refresh it.
*/
struct Attr {
struct stat st;
double timeout;
explicit Attr(
const struct stat& st,
double timeout = std::numeric_limits<double>::max());
};
/**
* Get file attributes
*
* @param ino the inode number
*/
virtual folly::Future<Attr> getattr(fuse_ino_t ino);
/**
* Set file attributes
*
* In the 'attr' argument only members indicated by the 'to_set'
* bitmask contain valid values. Other members contain undefined
* values.
*
* @param ino the inode number
* @param attr the attributes
* @param to_set bit mask of attributes which should be set
*
* Changed in version 2.5:
* file information filled in for ftruncate
*/
virtual folly::Future<Attr>
setattr(fuse_ino_t ino, const struct stat& attr, int to_set);
/**
* Read symbolic link
*
* @param ino the inode number
*/
virtual folly::Future<std::string> readlink(fuse_ino_t ino);
/**
* Create file node
*
* Create a regular file, character device, block device, fifo or
* socket node.
*
* @param parent inode number of the parent directory
* @param name to create
* @param mode file type and mode with which to create the new file
* @param rdev the device number (only valid if created file is a device)
*/
virtual folly::Future<fuse_entry_param>
mknod(fuse_ino_t parent, PathComponentPiece name, mode_t mode, dev_t rdev);
/**
* Create a directory
*
* @param parent inode number of the parent directory
* @param name to create
* @param mode with which to create the new file
*/
virtual folly::Future<fuse_entry_param>
mkdir(fuse_ino_t parent, PathComponentPiece name, mode_t mode);
/**
* Remove a file
*
* @param parent inode number of the parent directory
* @param name to remove
*/
virtual folly::Future<folly::Unit> unlink(
fuse_ino_t parent,
PathComponentPiece name);
/**
* Remove a directory
*
* @param parent inode number of the parent directory
* @param name to remove
*/
virtual folly::Future<folly::Unit> rmdir(
fuse_ino_t parent,
PathComponentPiece name);
/**
* Create a symbolic link
*
* @param parent inode number of the parent directory
* @param name to create
* @param link the contents of the symbolic link
*/
virtual folly::Future<fuse_entry_param>
symlink(fuse_ino_t parent, PathComponentPiece name, folly::StringPiece link);
/**
* Rename a file
*
* @param parent inode number of the old parent directory
* @param name old name
* @param newparent inode number of the new parent directory
* @param newname new name
*/
virtual folly::Future<folly::Unit> rename(
fuse_ino_t parent,
PathComponentPiece name,
fuse_ino_t newparent,
PathComponentPiece newname);
/**
* Create a hard link
*
* @param ino the old inode number
* @param newparent inode number of the new parent directory
* @param newname new name to create
*/
virtual folly::Future<fuse_entry_param>
link(fuse_ino_t ino, fuse_ino_t newparent, PathComponentPiece newname);
/**
* Open a file
*
* Open flags (with the exception of O_CREAT, O_EXCL, O_NOCTTY and
* O_TRUNC) are available in fi->flags.
*
* Filesystem may store an arbitrary file handle (pointer, index,
* etc) in fi->fh, and use this in other all other file operations
* (read, write, flush, release, fsync).
*
* There are also some flags (direct_io, keep_cache) which the
* filesystem may set in fi, to change the way the file is opened.
* See fuse_file_info structure in <fuse_common.h> for more details.
*
* @param ino the inode number
* @param fi file information
*/
virtual folly::Future<std::shared_ptr<FileHandle>> open(
fuse_ino_t ino,
const struct fuse_file_info& fi);
/**
* Open a directory
*
* Filesystem may store an arbitrary file handle (pointer, index,
* etc) in fi->fh, and use this in other all other directory
* stream operations (readdir, releasedir, fsyncdir).
*
* Filesystem may also implement stateless directory I/O and not
* store anything in fi->fh, though that makes it impossible to
* implement standard conforming directory stream operations in
* case the contents of the directory can change between opendir
* and releasedir.
*
* @param ino the inode number
* @param fi file information
*/
virtual folly::Future<std::shared_ptr<DirHandle>> opendir(
fuse_ino_t ino,
const struct fuse_file_info& fi);
/**
* Get file system statistics
*
* @param ino the inode number, zero means "undefined"
*/
virtual folly::Future<struct statvfs> statfs(fuse_ino_t ino);
/**
* Set an extended attribute
*/
virtual folly::Future<folly::Unit> setxattr(
fuse_ino_t ino,
folly::StringPiece name,
folly::StringPiece value,
int flags);
/**
* Get an extended attribute
*/
virtual folly::Future<std::string> getxattr(
fuse_ino_t ino,
folly::StringPiece name);
static const int kENOATTR;
/**
* List extended attribute names
*/
virtual folly::Future<std::vector<std::string>> listxattr(fuse_ino_t ino);
/**
* Remove an extended attribute
*
* @param ino the inode number
* @param name of the extended attribute
*/
virtual folly::Future<folly::Unit> removexattr(
fuse_ino_t ino,
folly::StringPiece name);
/**
* Check file access permissions
*
* This will be called for the access() system call. If the
* 'default_permissions' mount option is given, this method is not
* called.
*
* This method is not called under Linux kernel versions 2.4.x
*
* Introduced in version 2.5
*
* @param ino the inode number
* @param mask requested access mode
*/
virtual folly::Future<folly::Unit> access(fuse_ino_t ino, int mask);
struct Create {
fuse_entry_param entry;
std::shared_ptr<FileHandle> fh;
};
/**
* Create and open a file
*
* If the file does not exist, first create it with the specified
* mode, and then open it.
*
* Open flags (with the exception of O_NOCTTY) are available in
* fi->flags.
*
* If this method is not implemented or under Linux kernel
* versions earlier than 2.6.15, the mknod() and open() methods
* will be called instead.
*
* Introduced in version 2.5
*
* @param parent inode number of the parent directory
* @param name to create
* @param mode file type and mode with which to create the new file
*/
virtual folly::Future<Create>
create(fuse_ino_t parent, PathComponentPiece name, mode_t mode, int flags);
/**
* Map block index within file to block index within device
*
* Note: This makes sense only for block device backed filesystems
* mounted with the 'blkdev' option
*
* Introduced in version 2.6
*
* @param ino the inode number
* @param blocksize unit of block index
* @param idx block index within file
*/
virtual folly::Future<uint64_t>
bmap(fuse_ino_t ino, size_t blocksize, uint64_t idx);
};
} // namespace fusell
} // namespace eden
} // namespace facebook