From 80d56ac94ecaba61396fae8c6f22b4c0d58eb8fc Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Sun, 19 May 2019 15:18:36 -0400 Subject: [PATCH] add support for POSIX ACLs --- README.md | 25 ++++++++++++++++--------- libfuse/Makefile | 2 +- libfuse/include/fuse_common.h | 2 ++ libfuse/lib/fuse_lowlevel.c | 4 ++++ man/mergerfs.1 | 33 +++++++++++++++++++++++---------- src/config.cpp | 13 +++++++------ src/config.hpp | 1 + src/fuse_getxattr.cpp | 2 ++ src/fuse_init.cpp | 23 ++++++++++++++++++----- src/fuse_listxattr.cpp | 1 + src/option_parser.cpp | 3 +++ 11 files changed, 78 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 2beb7ee4..bb3810de 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ % mergerfs(1) mergerfs user manual % Antonio SJ Musumeci -% 2019-05-12 +% 2019-05-18 # NAME @@ -31,6 +31,7 @@ mergerfs -o<options> <branches> <mountpoint> * Handles pool of read-only and read/write drives * Can turn read-only files into symlinks to underlying file * Hard link copy-on-write / CoW +* supports POSIX ACLs # How it works @@ -80,6 +81,7 @@ mergerfs does **not** support the copy-on-write (CoW) behavior found in **aufs** * **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) +* **posix_acl=true|false:** enable POSIX ACL support (if supported by kernel and underlying filesystem). (default: false) * **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. * **func.<func>=<policy>**: sets the specific FUSE function's policy. See below for the list of value types. Example: **func.getattr=newest** @@ -964,15 +966,20 @@ For non-Linux systems mergerfs uses a read-write lock and changes credentials on # PERFORMANCE TWEAKING -* try adding (or removing) `direct_io` -* try adding (or removing) `auto_cache` -* try adding (or removing) `kernel_cache` -* try adding (or removing) `splice_move`, `splice_read`, and `splice_write` -* try increasing cache timeouts `cache.attr`, `cache.entry`, `cache.negative_entry` -* try changing the number of worker threads -* try disabling `security_capability` or `xattr` +NOTE: be sure to read about these features before changing them + +* add (or remove) `direct_io` +* add (or remove) `auto_cache` +* add (or remove) `kernel_cache` +* add (or remove) `splice_move`, `splice_read`, and `splice_write` +* increase cache timeouts `cache.attr`, `cache.entry`, `cache.negative_entry` +* enable `cache.open` and/or `cache.statfs` +* change the number opf worker threads +* disable `security_capability` and/or `xattr` +* disable `posix_acl` * test theoretical performance using `nullrw` or mounting a ram disk -* use `symlinkify` if your data is largely static and you need native speed reads +* use `symlinkify` if your data is largely static +* use tiered cache drives * use lvm and lvm cache to place a SSD in front of your HDDs (howto coming) diff --git a/libfuse/Makefile b/libfuse/Makefile index 5363cb6a..df1923e6 100644 --- a/libfuse/Makefile +++ b/libfuse/Makefile @@ -1,4 +1,4 @@ -VERSION = "2.9.7-mergerfs_2.26.0" +VERSION = "2.9.7-mergerfs_2.27.0" OPT = -O2 ifeq ($(DEBUG),1) diff --git a/libfuse/include/fuse_common.h b/libfuse/include/fuse_common.h index a4d980d5..c8c0a9ad 100644 --- a/libfuse/include/fuse_common.h +++ b/libfuse/include/fuse_common.h @@ -112,6 +112,8 @@ struct fuse_file_info { #define FUSE_CAP_SPLICE_READ (1 << 9) #define FUSE_CAP_FLOCK_LOCKS (1 << 10) #define FUSE_CAP_IOCTL_DIR (1 << 11) +#define FUSE_CAP_POSIX_ACL (1 << 19) + /** * Ioctl flags diff --git a/libfuse/lib/fuse_lowlevel.c b/libfuse/lib/fuse_lowlevel.c index 4be9b1c9..694c9878 100644 --- a/libfuse/lib/fuse_lowlevel.c +++ b/libfuse/lib/fuse_lowlevel.c @@ -1795,6 +1795,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) f->conn.capable |= FUSE_CAP_DONT_MASK; if (arg->flags & FUSE_FLOCK_LOCKS) f->conn.capable |= FUSE_CAP_FLOCK_LOCKS; + if (arg->flags & FUSE_POSIX_ACL) + f->conn.capable |= FUSE_CAP_POSIX_ACL; } else { f->conn.async_read = 0; f->conn.max_readahead = 0; @@ -1861,6 +1863,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) outarg.flags |= FUSE_DONT_MASK; if (f->conn.want & FUSE_CAP_FLOCK_LOCKS) outarg.flags |= FUSE_FLOCK_LOCKS; + if (f->conn.want & FUSE_CAP_POSIX_ACL) + outarg.flags |= FUSE_POSIX_ACL; outarg.max_readahead = f->conn.max_readahead; outarg.max_write = f->conn.max_write; if (f->conn.proto_minor >= 13) { diff --git a/man/mergerfs.1 b/man/mergerfs.1 index 6114916e..02d7c4b8 100644 --- a/man/mergerfs.1 +++ b/man/mergerfs.1 @@ -1,7 +1,7 @@ .\"t .\" Automatically generated by Pandoc 1.19.2.4 .\" -.TH "mergerfs" "1" "2019\-05\-12" "mergerfs user manual" "" +.TH "mergerfs" "1" "2019\-05\-18" "mergerfs user manual" "" .hy .SH NAME .PP @@ -41,6 +41,8 @@ Handles pool of read\-only and read/write drives Can turn read\-only files into symlinks to underlying file .IP \[bu] 2 Hard link copy\-on\-write / CoW +.IP \[bu] 2 +supports POSIX ACLs .SH How it works .PP mergerfs logically merges multiple paths together. @@ -175,6 +177,10 @@ calculations to ignore available space for branches mounted or tagged as create\[aq]. (default: none) .IP \[bu] 2 +\f[B]posix_acl=true|false:\f[] enable POSIX ACL support (if supported by +kernel and underlying filesystem). +(default: false) +.IP \[bu] 2 \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 number of logical cores. @@ -1925,28 +1931,35 @@ be used so threads trying to change credentials don\[aq]t starve. This isn\[aq]t the best solution but should work reasonably well assuming there are few users. .SH PERFORMANCE TWEAKING +.PP +NOTE: be sure to read about these features before changing them .IP \[bu] 2 -try adding (or removing) \f[C]direct_io\f[] +add (or remove) \f[C]direct_io\f[] .IP \[bu] 2 -try adding (or removing) \f[C]auto_cache\f[] +add (or remove) \f[C]auto_cache\f[] .IP \[bu] 2 -try adding (or removing) \f[C]kernel_cache\f[] +add (or remove) \f[C]kernel_cache\f[] .IP \[bu] 2 -try adding (or removing) \f[C]splice_move\f[], \f[C]splice_read\f[], and +add (or remove) \f[C]splice_move\f[], \f[C]splice_read\f[], and \f[C]splice_write\f[] .IP \[bu] 2 -try increasing cache timeouts \f[C]cache.attr\f[], \f[C]cache.entry\f[], +increase cache timeouts \f[C]cache.attr\f[], \f[C]cache.entry\f[], \f[C]cache.negative_entry\f[] .IP \[bu] 2 -try changing the number of worker threads +enable \f[C]cache.open\f[] and/or \f[C]cache.statfs\f[] .IP \[bu] 2 -try disabling \f[C]security_capability\f[] or \f[C]xattr\f[] +change the number opf worker threads +.IP \[bu] 2 +disable \f[C]security_capability\f[] and/or \f[C]xattr\f[] +.IP \[bu] 2 +disable \f[C]posix_acl\f[] .IP \[bu] 2 test theoretical performance using \f[C]nullrw\f[] or mounting a ram disk .IP \[bu] 2 -use \f[C]symlinkify\f[] if your data is largely static and you need -native speed reads +use \f[C]symlinkify\f[] if your data is largely static +.IP \[bu] 2 +use tiered cache drives .IP \[bu] 2 use lvm and lvm cache to place a SSD in front of your HDDs (howto coming) diff --git a/src/config.cpp b/src/config.cpp index 898c8a95..05e4c769 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -14,17 +14,17 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include - -#include -#include - #include "config.hpp" #include "errno.hpp" #include "fs.hpp" #include "rwlock.hpp" +#include +#include + +#include +#include + #define MINFREESPACE_DEFAULT (4294967295ULL) #define POLICYINIT(X) X(policies[FuseFunc::Enum::X]) @@ -48,6 +48,7 @@ Config::Config() xattr(0), statfs(StatFS::BASE), statfs_ignore(StatFSIgnore::NONE), + posix_acl(false), POLICYINIT(access), POLICYINIT(chmod), POLICYINIT(chown), diff --git a/src/config.hpp b/src/config.hpp index ccacc9ce..26a30499 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -78,6 +78,7 @@ public: int xattr; StatFS::Enum statfs; StatFSIgnore::Enum statfs_ignore; + bool posix_acl; public: const Policy *policies[FuseFunc::Enum::END]; diff --git a/src/fuse_getxattr.cpp b/src/fuse_getxattr.cpp index 19028a05..47cafba3 100644 --- a/src/fuse_getxattr.cpp +++ b/src/fuse_getxattr.cpp @@ -346,6 +346,8 @@ namespace l l::getxattr_controlfile_pid(attrvalue); else if(attr[2] == "direct_io") l::getxattr_controlfile_bool(config.direct_io,attrvalue); + else if(attr[2] == "posix_acl") + l::getxattr_controlfile_bool(config.posix_acl,attrvalue); break; case 4: diff --git a/src/fuse_init.cpp b/src/fuse_init.cpp index ea3935e5..398aae16 100644 --- a/src/fuse_init.cpp +++ b/src/fuse_init.cpp @@ -19,6 +19,17 @@ #include +namespace l +{ + void + want_if_capable(fuse_conn_info *conn_, + const int flag_) + { + if(conn_->capable & flag_) + conn_->want |= flag_; + } +} + namespace FUSE { void * @@ -26,11 +37,13 @@ namespace FUSE { ugid::init(); - conn_->want |= FUSE_CAP_ASYNC_READ; - conn_->want |= FUSE_CAP_ATOMIC_O_TRUNC; - conn_->want |= FUSE_CAP_BIG_WRITES; - conn_->want |= FUSE_CAP_DONT_MASK; - conn_->want |= FUSE_CAP_IOCTL_DIR; + l::want_if_capable(conn_,FUSE_CAP_ASYNC_READ); + l::want_if_capable(conn_,FUSE_CAP_ATOMIC_O_TRUNC); + l::want_if_capable(conn_,FUSE_CAP_BIG_WRITES); + l::want_if_capable(conn_,FUSE_CAP_DONT_MASK); + l::want_if_capable(conn_,FUSE_CAP_IOCTL_DIR); + if(Config::get().posix_acl) + l::want_if_capable(conn_,FUSE_CAP_POSIX_ACL); return &Config::get_writable(); } diff --git a/src/fuse_listxattr.cpp b/src/fuse_listxattr.cpp index 23c09194..5aa3eed2 100644 --- a/src/fuse_listxattr.cpp +++ b/src/fuse_listxattr.cpp @@ -59,6 +59,7 @@ namespace l ("user.mergerfs.nullrw") ("user.mergerfs.pid") ("user.mergerfs.policies") + ("user.mergerfs.posix_acl") ("user.mergerfs.security_capability") ("user.mergerfs.srcmounts") ("user.mergerfs.statfs") diff --git a/src/option_parser.cpp b/src/option_parser.cpp index 26fe64ae..3a173930 100644 --- a/src/option_parser.cpp +++ b/src/option_parser.cpp @@ -305,6 +305,8 @@ parse_and_process_kv_arg(Config &config, rv = parse_and_process_statfsignore(value,config.statfs_ignore); else if(key == "fsname") rv = parse_and_process(value,config.fsname); + else if(key == "posix_acl") + rv = parse_and_process(value,config.posix_acl); } if(rv == -1) @@ -433,6 +435,7 @@ usage(void) " as 'read only' or 'no create'. 'nc' will ignore\n" " available space for branches tagged as\n" " 'no create'. default = none\n" + " -o posix_acl= enable POSIX ACL support\n" << std::endl; }