mirror of
https://github.com/trapexit/mergerfs.git
synced 2025-03-15 02:35:12 +08:00
add ability to change statfs behavior
This commit is contained in:
parent
3d33428a4e
commit
680f8194f9
@ -74,6 +74,8 @@ mergerfs does **not** support the copy-on-write (CoW) behavior found in **aufs**
|
|||||||
* **security_capability=true|false**: If false return ENOATTR when xattr security.capability is queried. (default: true)
|
* **security_capability=true|false**: If false return ENOATTR when xattr security.capability is queried. (default: true)
|
||||||
* **xattr=passthrough|noattr|notsup**: Runtime control of xattrs. Default is to passthrough xattr requests. 'noattr' will short circuit as if nothing exists. 'notsup' will respond with ENOTSUP as if xattrs are not supported or disabled. (default: passthrough)
|
* **xattr=passthrough|noattr|notsup**: Runtime control of xattrs. Default is to passthrough xattr requests. 'noattr' will short circuit as if nothing exists. 'notsup' will respond with ENOTSUP as if xattrs are not supported or disabled. (default: passthrough)
|
||||||
* **link_cow=true|false**: When enabled if a regular file is opened which has a link count > 1 it will copy the file to a temporary file and rename over the original. Breaking the link and providing a basic copy-on-write function similar to cow-shell. (default: false)
|
* **link_cow=true|false**: When enabled if a regular file is opened which has a link count > 1 it will copy the file to a temporary file and rename over the original. Breaking the link and providing a basic copy-on-write function similar to cow-shell. (default: false)
|
||||||
|
* **statfs=base|full**: Controls how statfs works. 'base' means it will always use all branches in statfs calculations. 'full' is in effect path preserving and only includes drives where the path exists. (default: base)
|
||||||
|
* **statfs_ignore=none|ro|nc**: 'ro' will cause statfs calculations to ignore available space for branches mounted or tagged as 'read only' or 'no create'. 'nc' will ignore available space for branches tagged as 'no create'. (default: none)
|
||||||
* **threads=num**: number of threads to use in multithreaded mode. When set to zero (the default) it will attempt to discover and use the number of logical cores. If the lookup fails it will fall back to using 4. If the thread count is set negative it will look up the number of cores then divide by the absolute value. ie. threads=-2 on an 8 core machine will result in 8 / 2 = 4 threads. There will always be at least 1 thread. NOTE: higher number of threads increases parallelism but usually decreases throughput. (default: number of cores) *NOTE2:* the option is unavailable when built with system libfuse.
|
* **threads=num**: number of threads to use in multithreaded mode. When set to zero (the default) it will attempt to discover and use the number of logical cores. If the lookup fails it will fall back to using 4. If the thread count is set negative it will look up the number of cores then divide by the absolute value. ie. threads=-2 on an 8 core machine will result in 8 / 2 = 4 threads. There will always be at least 1 thread. NOTE: higher number of threads increases parallelism but usually decreases throughput. (default: number of cores) *NOTE2:* the option is unavailable when built with system libfuse.
|
||||||
* **fsname=name**: sets the name of the filesystem as seen in **mount**, **df**, etc. Defaults to a list of the source paths concatenated together with the longest common prefix removed.
|
* **fsname=name**: sets the name of the filesystem as seen in **mount**, **df**, etc. Defaults to a list of the source paths concatenated together with the longest common prefix removed.
|
||||||
* **func.<func>=<policy>**: sets the specific FUSE function's policy. See below for the list of value types. Example: **func.getattr=newest**
|
* **func.<func>=<policy>**: sets the specific FUSE function's policy. See below for the list of value types. Example: **func.getattr=newest**
|
||||||
|
@ -170,6 +170,20 @@ Breaking the link and providing a basic copy\-on\-write function similar
|
|||||||
to cow\-shell.
|
to cow\-shell.
|
||||||
(default: false)
|
(default: false)
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
|
\f[B]statfs=base|full\f[]: Controls how statfs works.
|
||||||
|
\[aq]base\[aq] means it will always use all branches in statfs
|
||||||
|
calculations.
|
||||||
|
\[aq]full\[aq] is in effect path preserving and only includes drives
|
||||||
|
where the path exists.
|
||||||
|
(default: base)
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]statfs_ignore=none|ro|nc\f[]: \[aq]ro\[aq] will cause statfs
|
||||||
|
calculations to ignore available space for branches mounted or tagged as
|
||||||
|
\[aq]read only\[aq] or \[aq]no create\[aq].
|
||||||
|
\[aq]nc\[aq] will ignore available space for branches tagged as \[aq]no
|
||||||
|
create\[aq].
|
||||||
|
(default: none)
|
||||||
|
.IP \[bu] 2
|
||||||
\f[B]threads=num\f[]: number of threads to use in multithreaded mode.
|
\f[B]threads=num\f[]: number of threads to use in multithreaded mode.
|
||||||
When set to zero (the default) it will attempt to discover and use the
|
When set to zero (the default) it will attempt to discover and use the
|
||||||
number of logical cores.
|
number of logical cores.
|
||||||
@ -219,7 +233,7 @@ globbing (http://linux.die.net/man/7/glob).
|
|||||||
the shell itself will apply the glob itself.\f[]
|
the shell itself will apply the glob itself.\f[]
|
||||||
.PP
|
.PP
|
||||||
Each branch can have a suffix of \f[C]=RW\f[] (read / write),
|
Each branch can have a suffix of \f[C]=RW\f[] (read / write),
|
||||||
\f[C]=RO\f[] (read only), or \f[C]=NW\f[] (no writes).
|
\f[C]=RO\f[] (read only), or \f[C]=NC\f[] (no create).
|
||||||
These suffixes work with globs as well and will apply to each path
|
These suffixes work with globs as well and will apply to each path
|
||||||
found.
|
found.
|
||||||
\f[C]RW\f[] is the default behavior and those paths will be eligible for
|
\f[C]RW\f[] is the default behavior and those paths will be eligible for
|
||||||
@ -227,7 +241,7 @@ all policy categories.
|
|||||||
\f[C]RO\f[] will exclude those paths from \f[C]create\f[] and
|
\f[C]RO\f[] will exclude those paths from \f[C]create\f[] and
|
||||||
\f[C]action\f[] policies (just as a filesystem being mounted \f[C]ro\f[]
|
\f[C]action\f[] policies (just as a filesystem being mounted \f[C]ro\f[]
|
||||||
would).
|
would).
|
||||||
\f[C]NW\f[] will exclude those paths from \f[C]create\f[] policies (you
|
\f[C]NC\f[] will exclude those paths from \f[C]create\f[] policies (you
|
||||||
can\[aq]t create but you can change / delete).
|
can\[aq]t create but you can change / delete).
|
||||||
.IP
|
.IP
|
||||||
.nf
|
.nf
|
||||||
@ -433,7 +447,8 @@ drives as necessary.
|
|||||||
.SS Policy descriptions
|
.SS Policy descriptions
|
||||||
.PP
|
.PP
|
||||||
All \f[B]create\f[] policies will filter out branches which are mounted
|
All \f[B]create\f[] policies will filter out branches which are mounted
|
||||||
\f[B]read only\f[] or tagged as \f[B]read only\f[] or \f[B]no write\f[].
|
\f[B]read only\f[] or tagged as \f[B]read only\f[] or \f[B]no
|
||||||
|
create\f[].
|
||||||
All \f[B]action\f[] policies will filter out branches which are mounted
|
All \f[B]action\f[] policies will filter out branches which are mounted
|
||||||
or tagged as \f[B]read only\f[].
|
or tagged as \f[B]read only\f[].
|
||||||
.PP
|
.PP
|
||||||
|
@ -34,6 +34,12 @@ Branch::ro(void) const
|
|||||||
return (mode == Branch::RO);
|
return (mode == Branch::RO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Branch::nc(void) const
|
||||||
|
{
|
||||||
|
return (mode == Branch::NC);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Branch::ro_or_nc(void) const
|
Branch::ro_or_nc(void) const
|
||||||
{
|
{
|
||||||
|
@ -35,6 +35,7 @@ struct Branch
|
|||||||
std::string path;
|
std::string path;
|
||||||
|
|
||||||
bool ro(void) const;
|
bool ro(void) const;
|
||||||
|
bool nc(void) const;
|
||||||
bool ro_or_nc(void) const;
|
bool ro_or_nc(void) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,6 +48,8 @@ namespace mergerfs
|
|||||||
security_capability(true),
|
security_capability(true),
|
||||||
link_cow(false),
|
link_cow(false),
|
||||||
xattr(0),
|
xattr(0),
|
||||||
|
statfs(StatFS::BASE),
|
||||||
|
statfs_ignore(StatFSIgnore::NONE),
|
||||||
POLICYINIT(access),
|
POLICYINIT(access),
|
||||||
POLICYINIT(chmod),
|
POLICYINIT(chmod),
|
||||||
POLICYINIT(chown),
|
POLICYINIT(chown),
|
||||||
|
@ -32,6 +32,26 @@ namespace mergerfs
|
|||||||
{
|
{
|
||||||
class Config
|
class Config
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
struct StatFS
|
||||||
|
{
|
||||||
|
enum Enum
|
||||||
|
{
|
||||||
|
BASE,
|
||||||
|
FULL
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StatFSIgnore
|
||||||
|
{
|
||||||
|
enum Enum
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
RO,
|
||||||
|
NC
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Config();
|
Config();
|
||||||
|
|
||||||
@ -56,6 +76,8 @@ namespace mergerfs
|
|||||||
bool security_capability;
|
bool security_capability;
|
||||||
bool link_cow;
|
bool link_cow;
|
||||||
int xattr;
|
int xattr;
|
||||||
|
StatFS::Enum statfs;
|
||||||
|
StatFSIgnore::Enum statfs_ignore;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const Policy *policies[FuseFunc::Enum::END];
|
const Policy *policies[FuseFunc::Enum::END];
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "errno.hpp"
|
#include "errno.hpp"
|
||||||
|
#include "fs_base_close.hpp"
|
||||||
|
#include "fs_base_open.hpp"
|
||||||
|
|
||||||
#include <sys/statvfs.h>
|
#include <sys/statvfs.h>
|
||||||
|
|
||||||
@ -43,4 +45,33 @@ namespace fs
|
|||||||
{
|
{
|
||||||
return fs::statvfs(path.c_str(),st);
|
return fs::statvfs(path.c_str(),st);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
inline
|
||||||
|
int
|
||||||
|
fstatvfs(const int fd_,
|
||||||
|
struct statvfs &st_)
|
||||||
|
{
|
||||||
|
return ::fstatvfs(fd_,&st_);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
inline
|
||||||
|
int
|
||||||
|
lstatvfs(const std::string &path_,
|
||||||
|
struct statvfs &st_)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
fd = fs::open(path_,O_RDONLY|O_NOFOLLOW|O_PATH);
|
||||||
|
if(fd == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
rv = fs::fstatvfs(fd,st_);
|
||||||
|
|
||||||
|
fs::close(fd);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,6 +170,47 @@ _getxattr_controlfile_errno(const int errno_,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
_getxattr_controlfile_statfs(const Config::StatFS::Enum enum_,
|
||||||
|
string &attrvalue_)
|
||||||
|
{
|
||||||
|
switch(enum_)
|
||||||
|
{
|
||||||
|
case Config::StatFS::BASE:
|
||||||
|
attrvalue_ = "base";
|
||||||
|
break;
|
||||||
|
case Config::StatFS::FULL:
|
||||||
|
attrvalue_ = "full";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
attrvalue_ = "ERROR";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
_getxattr_controlfile_statfsignore(const Config::StatFSIgnore::Enum enum_,
|
||||||
|
string &attrvalue_)
|
||||||
|
{
|
||||||
|
switch(enum_)
|
||||||
|
{
|
||||||
|
case Config::StatFSIgnore::NONE:
|
||||||
|
attrvalue_ = "none";
|
||||||
|
break;
|
||||||
|
case Config::StatFSIgnore::RO:
|
||||||
|
attrvalue_ = "ro";
|
||||||
|
break;
|
||||||
|
case Config::StatFSIgnore::NC:
|
||||||
|
attrvalue_ = "nc";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
attrvalue_ = "ERROR";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
_getxattr_controlfile_policies(const Config &config,
|
_getxattr_controlfile_policies(const Config &config,
|
||||||
@ -246,6 +287,10 @@ _getxattr_controlfile(const Config &config,
|
|||||||
_getxattr_controlfile_errno(config.xattr,attrvalue);
|
_getxattr_controlfile_errno(config.xattr,attrvalue);
|
||||||
else if(attr[2] == "link_cow")
|
else if(attr[2] == "link_cow")
|
||||||
_getxattr_controlfile_bool(config.link_cow,attrvalue);
|
_getxattr_controlfile_bool(config.link_cow,attrvalue);
|
||||||
|
else if(attr[2] == "statfs")
|
||||||
|
_getxattr_controlfile_statfs(config.statfs,attrvalue);
|
||||||
|
else if(attr[2] == "statfs_ignore")
|
||||||
|
_getxattr_controlfile_statfsignore(config.statfs_ignore,attrvalue);
|
||||||
else if(attr[2] == "policies")
|
else if(attr[2] == "policies")
|
||||||
_getxattr_controlfile_policies(config,attrvalue);
|
_getxattr_controlfile_policies(config,attrvalue);
|
||||||
else if(attr[2] == "version")
|
else if(attr[2] == "version")
|
||||||
|
@ -55,6 +55,8 @@ _listxattr_controlfile(char *list,
|
|||||||
("user.mergerfs.link_cow")
|
("user.mergerfs.link_cow")
|
||||||
("user.mergerfs.security_capability")
|
("user.mergerfs.security_capability")
|
||||||
("user.mergerfs.xattr")
|
("user.mergerfs.xattr")
|
||||||
|
("user.mergerfs.statfs")
|
||||||
|
("user.mergerfs.statfs_ignore")
|
||||||
("user.mergerfs.policies")
|
("user.mergerfs.policies")
|
||||||
("user.mergerfs.version")
|
("user.mergerfs.version")
|
||||||
("user.mergerfs.pid");
|
("user.mergerfs.pid");
|
||||||
|
@ -170,6 +170,38 @@ parse_and_process_errno(const std::string &value_,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
parse_and_process_statfs(const std::string &value_,
|
||||||
|
Config::StatFS::Enum &enum_)
|
||||||
|
{
|
||||||
|
if(value_ == "base")
|
||||||
|
enum_ = Config::StatFS::BASE;
|
||||||
|
else if(value_ == "full")
|
||||||
|
enum_ = Config::StatFS::FULL;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
parse_and_process_statfsignore(const std::string &value_,
|
||||||
|
Config::StatFSIgnore::Enum &enum_)
|
||||||
|
{
|
||||||
|
if(value_ == "none")
|
||||||
|
enum_ = Config::StatFSIgnore::NONE;
|
||||||
|
else if(value_ == "ro")
|
||||||
|
enum_ = Config::StatFSIgnore::RO;
|
||||||
|
else if(value_ == "nc")
|
||||||
|
enum_ = Config::StatFSIgnore::NC;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
parse_and_process_arg(Config &config,
|
parse_and_process_arg(Config &config,
|
||||||
@ -190,9 +222,10 @@ parse_and_process_kv_arg(Config &config,
|
|||||||
const std::string &key,
|
const std::string &key,
|
||||||
const std::string &value)
|
const std::string &value)
|
||||||
{
|
{
|
||||||
int rv = -1;
|
int rv;
|
||||||
std::vector<std::string> keypart;
|
std::vector<std::string> keypart;
|
||||||
|
|
||||||
|
rv = -1;
|
||||||
str::split(keypart,key,'.');
|
str::split(keypart,key,'.');
|
||||||
if(keypart.size() == 2)
|
if(keypart.size() == 2)
|
||||||
{
|
{
|
||||||
@ -223,6 +256,10 @@ parse_and_process_kv_arg(Config &config,
|
|||||||
rv = parse_and_process(value,config.link_cow);
|
rv = parse_and_process(value,config.link_cow);
|
||||||
else if(key == "xattr")
|
else if(key == "xattr")
|
||||||
rv = parse_and_process_errno(value,config.xattr);
|
rv = parse_and_process_errno(value,config.xattr);
|
||||||
|
else if(key == "statfs")
|
||||||
|
rv = parse_and_process_statfs(value,config.statfs);
|
||||||
|
else if(key == "statfs_ignore")
|
||||||
|
rv = parse_and_process_statfsignore(value,config.statfs_ignore);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rv == -1)
|
if(rv == -1)
|
||||||
@ -334,6 +371,16 @@ usage(void)
|
|||||||
" filesystems. notattr will short circuit as if\n"
|
" filesystems. notattr will short circuit as if\n"
|
||||||
" nothing exists. notsup will respond as if not\n"
|
" nothing exists. notsup will respond as if not\n"
|
||||||
" supported or disabled. default = passthrough\n"
|
" supported or disabled. default = passthrough\n"
|
||||||
|
" -o statfs=base|full When set to 'base' statfs will use all branches\n"
|
||||||
|
" when performing statfs calculations. 'full' will\n"
|
||||||
|
" only include branches on which that path is\n"
|
||||||
|
" available. default = base\n"
|
||||||
|
" -o statfs_ignore=none|ro|nc\n"
|
||||||
|
" 'ro' will cause statfs calculations to ignore\n"
|
||||||
|
" available space for branches mounted or tagged\n"
|
||||||
|
" as 'read only' or 'no create'. 'nc' will ignore\n"
|
||||||
|
" available space for branches tagged as\n"
|
||||||
|
" 'no create'. default = none\n"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,6 +156,67 @@ _setxattr_bool(const string &attrval,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
_setxattr_xattr(const string &attrval_,
|
||||||
|
const int flags_,
|
||||||
|
int xattr_)
|
||||||
|
{
|
||||||
|
if((flags_ & XATTR_CREATE) == XATTR_CREATE)
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
if(attrval_ == "passthrough")
|
||||||
|
xattr_ = 0;
|
||||||
|
else if(attrval_ == "noattr")
|
||||||
|
xattr_ = ENOATTR;
|
||||||
|
else if(attrval_ == "notsup")
|
||||||
|
xattr_ = ENOTSUP;
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
_setxattr_statfs(const string &attrval_,
|
||||||
|
const int flags_,
|
||||||
|
Config::StatFS::Enum &enum_)
|
||||||
|
{
|
||||||
|
if((flags_ & XATTR_CREATE) == XATTR_CREATE)
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
if(attrval_ == "base")
|
||||||
|
enum_ = Config::StatFS::BASE;
|
||||||
|
else if(attrval_ == "full")
|
||||||
|
enum_ = Config::StatFS::FULL;
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
_setxattr_statfsignore(const string &attrval_,
|
||||||
|
const int flags_,
|
||||||
|
Config::StatFSIgnore::Enum &enum_)
|
||||||
|
{
|
||||||
|
if((flags_ & XATTR_CREATE) == XATTR_CREATE)
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
if(attrval_ == "none")
|
||||||
|
enum_ = Config::StatFSIgnore::NONE;
|
||||||
|
else if(attrval_ == "ro")
|
||||||
|
enum_ = Config::StatFSIgnore::RO;
|
||||||
|
else if(attrval_ == "nc")
|
||||||
|
enum_ = Config::StatFSIgnore::NC;
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
_setxattr_controlfile_func_policy(Config &config,
|
_setxattr_controlfile_func_policy(Config &config,
|
||||||
@ -246,10 +307,22 @@ _setxattr_controlfile(Config &config,
|
|||||||
return _setxattr_bool(attrval,
|
return _setxattr_bool(attrval,
|
||||||
flags,
|
flags,
|
||||||
config.security_capability);
|
config.security_capability);
|
||||||
|
else if(attr[2] == "xattr")
|
||||||
|
return _setxattr_xattr(attrval,
|
||||||
|
flags,
|
||||||
|
config.xattr);
|
||||||
else if(attr[2] == "link_cow")
|
else if(attr[2] == "link_cow")
|
||||||
return _setxattr_bool(attrval,
|
return _setxattr_bool(attrval,
|
||||||
flags,
|
flags,
|
||||||
config.link_cow);
|
config.link_cow);
|
||||||
|
else if(attr[2] == "statfs")
|
||||||
|
return _setxattr_statfs(attrval,
|
||||||
|
flags,
|
||||||
|
config.statfs);
|
||||||
|
else if(attr[2] == "statfs_ignore")
|
||||||
|
return _setxattr_statfsignore(attrval,
|
||||||
|
flags,
|
||||||
|
config.statfs_ignore);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
|
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
@ -17,7 +17,7 @@
|
|||||||
#include <fuse.h>
|
#include <fuse.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <climits>
|
#include <limits>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -26,12 +26,17 @@
|
|||||||
#include "errno.hpp"
|
#include "errno.hpp"
|
||||||
#include "fs_base_stat.hpp"
|
#include "fs_base_stat.hpp"
|
||||||
#include "fs_base_statvfs.hpp"
|
#include "fs_base_statvfs.hpp"
|
||||||
|
#include "fs_path.hpp"
|
||||||
#include "rwlock.hpp"
|
#include "rwlock.hpp"
|
||||||
|
#include "statvfs_util.hpp"
|
||||||
#include "ugid.hpp"
|
#include "ugid.hpp"
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::map;
|
using std::map;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
using mergerfs::Config;
|
||||||
|
typedef Config::StatFS StatFS;
|
||||||
|
typedef Config::StatFSIgnore StatFSIgnore;
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
@ -41,7 +46,7 @@ _normalize_statvfs(struct statvfs *fsstat,
|
|||||||
const unsigned long min_namemax)
|
const unsigned long min_namemax)
|
||||||
{
|
{
|
||||||
fsstat->f_blocks = (fsblkcnt_t)((fsstat->f_blocks * fsstat->f_frsize) / min_frsize);
|
fsstat->f_blocks = (fsblkcnt_t)((fsstat->f_blocks * fsstat->f_frsize) / min_frsize);
|
||||||
fsstat->f_bfree = (fsblkcnt_t)((fsstat->f_bfree * fsstat->f_frsize) / min_frsize);
|
fsstat->f_bfree = (fsblkcnt_t)((fsstat->f_bfree * fsstat->f_frsize) / min_frsize);
|
||||||
fsstat->f_bavail = (fsblkcnt_t)((fsstat->f_bavail * fsstat->f_frsize) / min_frsize);
|
fsstat->f_bavail = (fsblkcnt_t)((fsstat->f_bavail * fsstat->f_frsize) / min_frsize);
|
||||||
fsstat->f_bsize = min_bsize;
|
fsstat->f_bsize = min_bsize;
|
||||||
fsstat->f_frsize = min_frsize;
|
fsstat->f_frsize = min_frsize;
|
||||||
@ -63,48 +68,64 @@ _merge_statvfs(struct statvfs * const out,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
bool
|
||||||
_statfs_core(const string &path_,
|
_should_ignore(const StatFSIgnore::Enum ignore_,
|
||||||
unsigned long &min_bsize,
|
const Branch *branch_,
|
||||||
unsigned long &min_frsize,
|
const bool readonly_)
|
||||||
unsigned long &min_namemax,
|
|
||||||
map<dev_t,struct statvfs> &fsstats)
|
|
||||||
{
|
{
|
||||||
int rv;
|
return ((((ignore_ == StatFSIgnore::RO) || readonly_) &&
|
||||||
struct stat st;
|
(branch_->ro_or_nc())) ||
|
||||||
struct statvfs fsstat;
|
((ignore_ == StatFSIgnore::NC) && (branch_->nc())));
|
||||||
|
|
||||||
rv = fs::statvfs(path_,fsstat);
|
|
||||||
if(rv == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
rv = fs::stat(path_,st);
|
|
||||||
if(rv == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(fsstat.f_bsize && (min_bsize > fsstat.f_bsize))
|
|
||||||
min_bsize = fsstat.f_bsize;
|
|
||||||
if(fsstat.f_frsize && (min_frsize > fsstat.f_frsize))
|
|
||||||
min_frsize = fsstat.f_frsize;
|
|
||||||
if(fsstat.f_namemax && (min_namemax > fsstat.f_namemax))
|
|
||||||
min_namemax = fsstat.f_namemax;
|
|
||||||
|
|
||||||
fsstats.insert(std::make_pair(st.st_dev,fsstat));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
_statfs(const Branches &branches_,
|
_statfs(const Branches &branches_,
|
||||||
struct statvfs &fsstat)
|
const char *fusepath,
|
||||||
|
const StatFS::Enum mode,
|
||||||
|
const StatFSIgnore::Enum ignore,
|
||||||
|
struct statvfs &fsstat)
|
||||||
{
|
{
|
||||||
|
int rv;
|
||||||
|
string fullpath;
|
||||||
|
struct stat st;
|
||||||
|
struct statvfs stvfs;
|
||||||
|
unsigned long min_bsize;
|
||||||
|
unsigned long min_frsize;
|
||||||
|
unsigned long min_namemax;
|
||||||
map<dev_t,struct statvfs> fsstats;
|
map<dev_t,struct statvfs> fsstats;
|
||||||
unsigned long min_bsize = ULONG_MAX;
|
|
||||||
unsigned long min_frsize = ULONG_MAX;
|
|
||||||
unsigned long min_namemax = ULONG_MAX;
|
|
||||||
|
|
||||||
|
min_bsize = std::numeric_limits<unsigned long>::max();
|
||||||
|
min_frsize = std::numeric_limits<unsigned long>::max();
|
||||||
|
min_namemax = std::numeric_limits<unsigned long>::max();
|
||||||
for(size_t i = 0, ei = branches_.size(); i < ei; i++)
|
for(size_t i = 0, ei = branches_.size(); i < ei; i++)
|
||||||
{
|
{
|
||||||
_statfs_core(branches_[i].path,min_bsize,min_frsize,min_namemax,fsstats);
|
fullpath = ((mode == StatFS::FULL) ?
|
||||||
|
fs::path::make(&branches_[i].path,fusepath) :
|
||||||
|
branches_[i].path);
|
||||||
|
|
||||||
|
rv = fs::lstat(fullpath,st);
|
||||||
|
if(rv == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rv = fs::lstatvfs(fullpath,stvfs);
|
||||||
|
if(rv == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(stvfs.f_bsize && (min_bsize > stvfs.f_bsize))
|
||||||
|
min_bsize = stvfs.f_bsize;
|
||||||
|
if(stvfs.f_frsize && (min_frsize > stvfs.f_frsize))
|
||||||
|
min_frsize = stvfs.f_frsize;
|
||||||
|
if(stvfs.f_namemax && (min_namemax > stvfs.f_namemax))
|
||||||
|
min_namemax = stvfs.f_namemax;
|
||||||
|
|
||||||
|
if(_should_ignore(ignore,&branches_[i],StatVFS::readonly(stvfs)))
|
||||||
|
{
|
||||||
|
stvfs.f_bavail = 0;
|
||||||
|
stvfs.f_favail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fsstats.insert(std::make_pair(st.st_dev,stvfs));
|
||||||
}
|
}
|
||||||
|
|
||||||
map<dev_t,struct statvfs>::iterator iter = fsstats.begin();
|
map<dev_t,struct statvfs>::iterator iter = fsstats.begin();
|
||||||
@ -138,6 +159,9 @@ namespace mergerfs
|
|||||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||||
|
|
||||||
return _statfs(config.branches,
|
return _statfs(config.branches,
|
||||||
|
fusepath,
|
||||||
|
config.statfs,
|
||||||
|
config.statfs_ignore,
|
||||||
*stat);
|
*stat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user