mirror of https://github.com/trapexit/mergerfs.git
Browse Source
Rework of runtime interface (#1498)
Rework of runtime interface (#1498)
Also have special error handling for when branches are invalid and ENOENT would be returned for getattr and readdir so users understand what is going on and the runtime interface can still be used to fix the problem.pull/1499/head
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
37 changed files with 3378 additions and 824 deletions
-
7Makefile
-
2mkdocs/docs/faq/usage_and_functionality.md
-
8mkdocs/docs/faq/why_isnt_it_working.md
-
180mkdocs/docs/runtime_interface.md
-
114mkdocs/docs/runtime_interfaces.md
-
2mkdocs/docs/setup/upgrade.md
-
2mkdocs/mkdocs.yml
-
86src/config.cpp
-
10src/config.hpp
-
32src/fs_attr_linux.icpp
-
2src/fs_clonepath.cpp
-
2src/fs_copyfile.cpp
-
2src/fs_ficlone_linux.icpp
-
20src/fs_ioctl.hpp
-
12src/fs_llistxattr.hpp
-
44src/fuse_getattr.cpp
-
2src/fuse_getattr.hpp
-
92src/fuse_getxattr.cpp
-
6src/fuse_getxattr.hpp
-
381src/fuse_ioctl.cpp
-
192src/fuse_listxattr.cpp
-
1src/fuse_listxattr.hpp
-
2src/fuse_open.cpp
-
45src/fuse_readdir.cpp
-
2src/fuse_removexattr.cpp
-
328src/fuse_setxattr.cpp
-
2src/fuse_setxattr.hpp
-
42src/fuse_statx_supported.icpp
-
26src/gidcache.cpp
-
12src/gidcache.hpp
-
14src/mergerfs.cpp
-
47src/mergerfs_api.cpp
-
86src/mergerfs_collect_info.cpp
-
23src/mergerfs_ioctl.hpp
-
2311src/nonstd/string.hpp
-
49src/str.cpp
-
14src/str.hpp
@ -0,0 +1,180 @@ |
|||
# Runtime Interface |
|||
|
|||
`mergerfs` has runtime interfaces allowing users to query certain |
|||
filesystem information, get and set config, and trigger certain |
|||
activities while it is running. |
|||
|
|||
The interface is provided via the POSIX extended attributes filesystem |
|||
API which is a namespaced `key=value` pair store associated with a |
|||
file. Since `mergerfs` primarily uses `key=value` pairs for config it |
|||
fits well and is a known and reasonably well supported API. |
|||
|
|||
There are two targets for `xattr` calls. One is a pseudo file used for |
|||
getting and setting config and issuing certain commands. The other are |
|||
files found on the filesystem for querying certain `mergerfs` specific |
|||
information about them. |
|||
|
|||
|
|||
## .mergerfs pseudo file |
|||
|
|||
``` |
|||
<mountpoint>/.mergerfs |
|||
``` |
|||
|
|||
`mergerfs` provides this pseudo file for the runtime modification of |
|||
certain options and issuing commands. The file will not show up in |
|||
`readdir` but can be `stat`'ed and viewed/manipulated via |
|||
[listxattr](http://linux.die.net/man/2/listxattr), |
|||
[getxattr](https://linux.die.net/man/2/getxattr), and |
|||
[setxattr](https://linux.die.net/man/2/setxattr) calls. |
|||
|
|||
Any changes made at runtime are **NOT** persisted. If you wish for |
|||
values to persist they must be included as options wherever you |
|||
configure the mounting of mergerfs (/etc/fstab, systemd, etc.). |
|||
|
|||
|
|||
### Command Line Tooling |
|||
|
|||
Extended attributes is prevelant enough that there are common tools |
|||
available for interacting with them. |
|||
|
|||
In Debian / Ubuntu distributions you can get the tools |
|||
[getfattr](https://linux.die.net/man/1/getfattr) and |
|||
[setfattr](https://linux.die.net/man/1/setfattr) from |
|||
[attr](https://linux.die.net/man/5/attr) package. |
|||
|
|||
``` |
|||
$ sudo apt-get install attr |
|||
``` |
|||
|
|||
|
|||
### Config |
|||
|
|||
#### Keys |
|||
|
|||
Use `getfattr -d /mountpoint/.mergerfs` to see all supported |
|||
configuration keys. It is effectively the same as the |
|||
[options](config/options.md) prefixed with `user.mergerfs.`. Some are |
|||
informational or only can be set at startup and therefore read-only. |
|||
|
|||
Example: option `cache.files` would be `user.mergerfs.cache.files`. |
|||
|
|||
|
|||
#### Values |
|||
|
|||
Same as the [command line options](config/options.md). |
|||
|
|||
|
|||
#### Getting |
|||
|
|||
`getfattr -n user.mergerfs.branches /mountpoint/.mergerfs` |
|||
|
|||
`ENOATTR` will be returned if the key doesn't exist as normal with |
|||
[getxattr](https://linux.die.net/man/2/getxattr). |
|||
|
|||
|
|||
#### Setting |
|||
|
|||
`setfattr -n user.mergerfs.branches -v VALUE /mountpoint/.mergerfs` |
|||
|
|||
[setxattr](https://linux.die.net/man/2/setxattr) will return `EROFS` |
|||
(Read-only filesystem) on read-only keys. `ENOATTR` will be returned |
|||
if the key does not exist. If the value attempting to be set is not |
|||
valid `EINVAL` will be returned. |
|||
|
|||
|
|||
#### user.mergerfs.branches |
|||
|
|||
`branches` has the ability to understand some simple instructions to |
|||
make manipulation of the list easier. The `[list]` is simply what is |
|||
described in the [branches](config/branches.md) docs. |
|||
|
|||
| Value | Description | |
|||
| -------- | -------------------------- | |
|||
| [list] | set | |
|||
| +<[list] | prepend to existing list | |
|||
| +>[list] | append to existing list | |
|||
| -[list] | remove all values provided | |
|||
| -< | remove first in list | |
|||
| -> | remove last in list | |
|||
|
|||
**NOTE:** if the value of `branches` is set to something invalid / |
|||
non-existant `mergerfs` will return a bogus entry when the mount point |
|||
directory is `stat`'ed and create a fake file entry when listing the |
|||
directory telling the user "error: no valid mergerfs branch found, |
|||
check config". This is done to ensure the user understands the |
|||
situation and continue to be able to access the xattr interface. |
|||
|
|||
|
|||
#### Example |
|||
|
|||
``` |
|||
[trapexit:/mnt/mergerfs] $ getfattr -d .mergerfs |
|||
user.mergerfs.branches="/mnt/a=RW:/mnt/b=RW" |
|||
user.mergerfs.minfreespace="4294967295" |
|||
user.mergerfs.moveonenospc="false" |
|||
... |
|||
|
|||
[trapexit:/mnt/mergerfs] $ getfattr -n user.mergerfs.category.create .mergerfs |
|||
user.mergerfs.category.search="mfs" |
|||
|
|||
[trapexit:/mnt/mergerfs] $ setfattr -n user.mergerfs.category.create -v pfrd .mergerfs |
|||
[trapexit:/mnt/mergerfs] $ getfattr -n user.mergerfs.category.create .mergerfs |
|||
user.mergerfs.category.search="prfd" |
|||
|
|||
[trapexit:/mnt/mergerfs] $ setfattr -n user.mergerfs.branches -v "'+</mnt/c=RO .mergerfs |
|||
[trapexit:/mnt/mergerfs] $ getfattr -n user.mergerfs.branches .mergerfs |
|||
user.mergerfs.branches="/mnt/c=RO:/mnt/a=RW:/mnt/b=RW" |
|||
``` |
|||
|
|||
### Commands |
|||
|
|||
There are a number of commands / behaviors which can be triggerd by |
|||
writing ([setfattr](https://linux.die.net/man/1/setfattr), |
|||
[setxattr](https://linux.die.net/man/2/setxattr)) particular xattr |
|||
keys of `/mountpoint/.mergerfs`. These keys do not show up in key |
|||
listings. |
|||
|
|||
Commands can take an argument however currently no command uses or |
|||
allows a value. |
|||
|
|||
| Key | Value | Description | |
|||
| --- | ----- | ----------- | |
|||
| user.mergerfs.cmd.gc | (empty) |Trigger a thorough garbage collection of certain pools of resources. The xattr value is not used. | |
|||
| user.mergerfs.cmd.gc1 | (empty) | Trigger a simple garbage collection of certain pools of resources. This is also done on a timer. | |
|||
| user.mergerfs.cmd.invalidate-all-nodes | (empty) | Attempts to invalidate FUSE file nodes. Primarily used for debugging. | |
|||
| user.mergerfs.cmd.invalidate-gid-cache | (empty) | Invalidates all entries in gid cache. Primarily used for debugging but can also be useful in cases where gid supplemental groups change. | |
|||
| user.mergerfs.cmd.clear-gid-cache | (empty) | Clears all entries in the gid cache. Primarily used for debugging but can also be useful in cases where gid supplemental groups change. | |
|||
|
|||
``` |
|||
[trapexit:/mnt/mergerfs] $ setfattr -n user.mergerfs.cmd.gc /mnt/mergerfs/.mergerfs |
|||
[trapexit:/mnt/mergerfs] $ journalctl -t mergerfs | tail -n1 |
|||
Jul 20 15:36:18 hostname mergerfs[1931348]: running basic garbage collection |
|||
``` |
|||
|
|||
|
|||
### file / directory xattrs |
|||
|
|||
There is certain information `mergerfs` knows or calculates about a |
|||
file that can be useful in building tooling or debugging. |
|||
|
|||
The keys below can be queried (`getfattr -n key`, |
|||
[getxattr](http://linux.die.net/man/2/getxattr)) to get the described |
|||
information. These keys will not show up in any listing (`getfattr |
|||
-d`, [listxattr](https://linux.die.net/man/2/listxattr)). Attempting |
|||
to set them will result in an error. |
|||
|
|||
| Key | Return Value | |
|||
| --- | ------------ | |
|||
| user.mergerfs.basepath | The base mount point for the file given the current `getattr` policy. | |
|||
| user.mergerfs.relpath | The relative path of the file from the perspective of the mount point. | |
|||
| user.mergerfs.fullpath | The full path of the original file given the `getattr` policy. | |
|||
| user.mergerfs.allpaths | A NULL ('\0') separated list of full paths to all files found. | |
|||
|
|||
|
|||
``` |
|||
[trapexit:/mnt/mergerfs] $ getfattr -n user.mergerfs.fullpath test |
|||
user.mergerfs.fullpath="/mnt/a/test" |
|||
[trapexit:/mnt/mergerfs] $ getfattr -n user.mergerfs.allpaths . |
|||
user.mergerfs.allpaths="/mnt/a\000/mnt/b\000/mnt/c" |
|||
``` |
|||
@ -1,114 +0,0 @@ |
|||
# Runtime Interfaces |
|||
|
|||
## Runtime Config |
|||
|
|||
### .mergerfs pseudo file |
|||
|
|||
``` |
|||
<mountpoint>/.mergerfs |
|||
``` |
|||
|
|||
There is a pseudo file available at the mount point which allows for |
|||
the runtime modification of certain **mergerfs** options. The file |
|||
will not show up in **readdir** but can be **stat**'ed and manipulated |
|||
via [{list,get,set}xattrs](http://linux.die.net/man/2/listxattr) |
|||
calls. |
|||
|
|||
Any changes made at runtime are **not** persisted. If you wish for |
|||
values to persist they must be included as options wherever you |
|||
configure the mounting of mergerfs (/etc/fstab). |
|||
|
|||
|
|||
#### Keys |
|||
|
|||
Use `getfattr -d /mountpoint/.mergerfs` or `xattr -l |
|||
/mountpoint/.mergerfs` to see all supported keys. Some are |
|||
informational and therefore read-only. `setxattr` will return EINVAL |
|||
(invalid argument) on read-only keys. |
|||
|
|||
|
|||
#### Values |
|||
|
|||
Same as the command line. |
|||
|
|||
|
|||
##### user.mergerfs.branches |
|||
|
|||
Used to query or modify the list of branches. When modifying there are |
|||
several shortcuts to easy manipulation of the list. |
|||
|
|||
| Value | Description | |
|||
| -------- | -------------------------- | |
|||
| [list] | set | |
|||
| +<[list] | prepend | |
|||
| +>[list] | append | |
|||
| -[list] | remove all values provided | |
|||
| -< | remove first in list | |
|||
| -> | remove last in list | |
|||
|
|||
`xattr -w user.mergerfs.branches +</mnt/drive3 /mnt/pool/.mergerfs` |
|||
|
|||
The `=NC`, `=RO`, `=RW` syntax works just as on the command line. |
|||
|
|||
##### Example |
|||
|
|||
``` |
|||
[trapexit:/mnt/mergerfs] $ getfattr -d .mergerfs |
|||
user.mergerfs.branches="/mnt/a=RW:/mnt/b=RW" |
|||
user.mergerfs.minfreespace="4294967295" |
|||
user.mergerfs.moveonenospc="false" |
|||
... |
|||
|
|||
[trapexit:/mnt/mergerfs] $ getfattr -n user.mergerfs.category.search .mergerfs |
|||
user.mergerfs.category.search="ff" |
|||
|
|||
[trapexit:/mnt/mergerfs] $ setfattr -n user.mergerfs.category.search -v newest .mergerfs |
|||
[trapexit:/mnt/mergerfs] $ getfattr -n user.mergerfs.category.search .mergerfs |
|||
user.mergerfs.category.search="newest" |
|||
``` |
|||
|
|||
### file / directory xattrs |
|||
|
|||
While they won't show up when using `getfattr` **mergerfs** offers a |
|||
number of special xattrs to query information about the files |
|||
served. To access the values you will need to issue a |
|||
[getxattr](http://linux.die.net/man/2/getxattr) for one of the |
|||
following: |
|||
|
|||
- **user.mergerfs.basepath**: the base mount point for the file given the current getattr policy |
|||
- **user.mergerfs.relpath**: the relative path of the file from the perspective of the mount point |
|||
- **user.mergerfs.fullpath**: the full path of the original file given the getattr policy |
|||
- **user.mergerfs.allpaths**: a NUL ('\0') separated list of full paths to all files found |
|||
|
|||
## Signals |
|||
|
|||
- USR1: This will cause mergerfs to send invalidation notifications to |
|||
the kernel for all files. This will cause all unused files to be |
|||
released from memory. |
|||
- USR2: Trigger a general cleanup of currently unused memory. A more |
|||
thorough version of what happens every ~15 minutes. |
|||
|
|||
## ioctl |
|||
|
|||
Found in `fuse_ioctl.cpp`: |
|||
|
|||
```C++ |
|||
typedef char IOCTL_BUF[4096]; |
|||
#define IOCTL_APP_TYPE 0xDF |
|||
#define IOCTL_FILE_INFO _IOWR(IOCTL_APP_TYPE,0,IOCTL_BUF) |
|||
#define IOCTL_GC _IO(IOCTL_APP_TYPE,1) |
|||
#define IOCTL_GC1 _IO(IOCTL_APP_TYPE,2) |
|||
#define IOCTL_INVALIDATE_ALL_NODES _IO(IOCTL_APP_TYPE,3) |
|||
``` |
|||
|
|||
- IOCTL_FILE_INFO: Same as the "file / directory xattrs" mentioned |
|||
above. Use a buffer size of 4096 bytes. Pass in a string of |
|||
"basepath", "relpath", "fullpath", or "allpaths". Receive details in |
|||
same buffer. |
|||
- IOCTL_GC: Triggers a thorough garbage collection of excess |
|||
memory. Same as SIGUSR2. |
|||
- IOCTL_GC1: Triggers a simple garbage collection of excess |
|||
memory. Same as what happens every 15 minutes normally. |
|||
- IOCTL_INVALIDATE_ALL_NODES: Same as SIGUSR1. Send invalidation |
|||
notifications to the kernel for all files causing unused files to be |
|||
released from memory. |
|||
@ -1,68 +1,71 @@ |
|||
#include "mergerfs_api.hpp"
|
|||
|
|||
#include "fs_close.hpp"
|
|||
#include "fs_ioctl.hpp"
|
|||
#include "fs_open.hpp"
|
|||
#include "mergerfs_ioctl.hpp"
|
|||
#include "fs_lgetxattr.hpp"
|
|||
|
|||
#include "str.hpp"
|
|||
|
|||
#include "scope_guard.hpp"
|
|||
|
|||
#include <string.h>
|
|||
#include <array>
|
|||
#include <cstring>
|
|||
|
|||
|
|||
typedef std::array<char,64*1024> mfs_api_buf_t; |
|||
|
|||
static |
|||
int |
|||
mergerfs::api::allpaths(const std::string &input_path_, |
|||
std::vector<std::string> &output_paths_) |
|||
_lgetxattr(const std::string &input_path_, |
|||
const std::string &key_, |
|||
std::string &value_) |
|||
{ |
|||
int rv; |
|||
IOCTL_BUF buf; |
|||
std::string key; |
|||
mfs_api_buf_t buf; |
|||
|
|||
rv = fs::lgetxattr(input_path_,"user.mergerfs.allpaths",buf,sizeof(buf)); |
|||
key = "user.mergerfs." + key_; |
|||
rv = fs::lgetxattr(input_path_,key,buf.data(),buf.size()); |
|||
if(rv < 0) |
|||
return rv; |
|||
|
|||
str::split_on_null(buf,rv,&output_paths_); |
|||
value_.clear(); |
|||
value_.reserve(rv); |
|||
value_.append(buf.data(),(size_t)rv); |
|||
|
|||
return 0; |
|||
return rv; |
|||
} |
|||
|
|||
int |
|||
_lgetxattr(const std::string &input_path_, |
|||
const std::string &key_, |
|||
std::string &value_) |
|||
mergerfs::api::allpaths(const std::string &input_path_, |
|||
std::vector<std::string> &output_paths_) |
|||
{ |
|||
int rv; |
|||
IOCTL_BUF buf; |
|||
std::string val; |
|||
|
|||
rv = fs::lgetxattr(input_path_,key_,buf,sizeof(buf)); |
|||
rv = ::_lgetxattr(input_path_,"allpaths",val); |
|||
if(rv < 0) |
|||
return rv; |
|||
|
|||
value_ = buf; |
|||
str::split_on_null(val.data(),val.size(),&output_paths_); |
|||
|
|||
return rv; |
|||
return 0; |
|||
} |
|||
|
|||
int |
|||
mergerfs::api::basepath(const std::string &input_path_, |
|||
std::string &basepath_) |
|||
{ |
|||
return ::_lgetxattr(input_path_,"user.mergerfs.basepath",basepath_); |
|||
return ::_lgetxattr(input_path_,"basepath",basepath_); |
|||
} |
|||
|
|||
int |
|||
mergerfs::api::relpath(const std::string &input_path_, |
|||
std::string &relpath_) |
|||
{ |
|||
return ::_lgetxattr(input_path_,"user.mergerfs.relpath",relpath_); |
|||
return ::_lgetxattr(input_path_,"relpath",relpath_); |
|||
} |
|||
|
|||
int |
|||
mergerfs::api::fullpath(const std::string &input_path_, |
|||
std::string &fullpath_) |
|||
{ |
|||
return ::_lgetxattr(input_path_,"user.mergerfs.fullpath",fullpath_); |
|||
return ::_lgetxattr(input_path_,"fullpath",fullpath_); |
|||
} |
|||
2311
src/nonstd/string.hpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue